kinect学习笔记四(距离变换 distance tranform 和opencv像素访问方式)

本文主要是介绍kinect学习笔记四(距离变换 distance tranform 和opencv像素访问方式),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

当时自己理解的一点小误区,放到这里防止再犯错。

距离变换的基本意思就是计算一个图像中非零像素点到最近的零像素点的距离,也就是到所有零像素点的最短距离。建立距离变换图像可以方便提取骨骼

在opencv中有专门的函数cvDistTransform来计算距离变换图像。

DistTransform
计算输入图像的所有非零元素对其最近零元素的距离void cvDistTransform( const CvArr* src, CvArr* dst, int distance_type=CV_DIST_L2,int mask_size=3, const float* mask=NULL );
src
输入 8-比特、单通道 (二值) 图像.
dst
含计算出的距离的输出图像(32-比特、浮点数、单通道).
distance_type
距离类型; 可以是 CV_DIST_L1, CV_DIST_L2, CV_DIST_C 或 CV_DIST_USER.
mask_size
距离变换掩模的大小,可以是 3 或 5. 对 CV_DIST_L1 或 CV_DIST_C 的情况,参数值被强制设定为 3, 因为 3×3 mask 给出 5×5 mask 一样的结果,而且速度还更快。
mask
用户自定义距离距离情况下的 mask。 在 3×3 mask 下它由两个数(水平/垂直位量,对角线位移量)组成, 5×5 mask 下由三个数组成(水平/垂直位移量,对角位移和 国际象棋里的马步(马走日)) 
函数 cvDistTransform 二值图像每一个象素点到它最邻近零象素点的距离。对零象素,函数设置 0 距离,对其它象素,它寻找由基本位移(水平、垂直、对角线或knight's move,最后一项对 5×5 mask 有用)构成的最短路径。 全部的距离被认为是基本距离的和。由于距离函数是对称的,所有水平和垂直位移具有同样的代价 (表示为 a ), 所有的对角位移具有同样的代价 (表示为 b), 所有的 knight's 移动具有同样的代价 (表示为 c). 对类型 CV_DIST_C 和 CV_DIST_L1,距离的计算是精确的,而类型 CV_DIST_L2 (欧式距离) 距离的计算有某些相对误差 (5×5 mask 给出更精确的结果), OpenCV 使用 [Borgefors86] 推荐的值:CV_DIST_C (3×3):
a=1, b=1CV_DIST_L1 (3×3):
a=1, b=2CV_DIST_L2 (3×3):
a=0.955, b=1.3693CV_DIST_L2 (5×5):
a=1, b=1.4, c=2.1969

其中mask刚开始不是很理解,经过模拟数据得到了其含义。

距离计算
2b?2a b
?bab?
2aa0a2a
?bab?
b?a?b

a\b分别表示在水平垂直方向的距离,?/问号部分表示根据a和b的值的大小再确定其值。
如果定义了c值(用户自定义mask或者选择CV_DIST_L2等)在变为

a,b,c
2bc2ac2b
cbabc
2aa0a2a
cbabc
2bc2ac2b

所以定义c的时候必须是5*5的mask,然后在往外扩充的时候类似上面的问号类型,找到最小距离即可。

下面代码表示自己创建一个9*9的矩阵,然后利用该函数计算其值:

//距离变换代码,在微软的那个ppt中用来计算掌心的位置可能用到这个
//部分内容在http://www.opencv.org.cn/forum/viewtopic.php?f=1&t=4574&start=0有解释#include <iostream>
#include "highgui.h"
#include "cv.h"using namespace std;int main()
{IplImage *src = cvCreateImage(cvSize(9, 9), 8, 1);cvZero(src);uchar *ptr = (uchar*)(src->imageData);*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0; *ptr++ = 0;*ptr++ = 0;ptr +=3;*ptr++ = 0;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 0;*ptr++ = 0; *ptr++ = 0;*ptr++ = 0;ptr +=3;*ptr++ = 0;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255; *ptr++ = 0;*ptr++ = 0;ptr +=3;*ptr++ = 0;*ptr++ = 0;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 0;*ptr++ = 0;ptr +=3;*ptr++ = 0;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 0;ptr +=3;*ptr++ = 0;*ptr++ = 0;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 0;*ptr++ = 0;ptr +=3;*ptr++ = 0;*ptr++ = 0;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255;*ptr++ = 255; *ptr++ = 0;*ptr++ = 0;ptr +=3;*ptr++ = 0;*ptr++ = 0;*ptr++ = 255;*ptr++ = 0;*ptr++ = 255;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0; ptr +=3;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;*ptr++ = 0;IplImage *dist = cvCreateImage( cvGetSize(src), IPL_DEPTH_32F, 1 );cvDistTransform( src, dist, CV_DIST_L1, 3, NULL, NULL );/*cvConvertScale( dist, dist, 1000.0, 0 );cvShowImage("dist2", dist);cvPow( dist, dist, 0.5 );cvShowImage("dist3", dist);IplImage *dist32s = cvCreateImage(cvGetSize(src), IPL_DEPTH_32S, 1);cvConvertScale( dist, dist32s, 1.0, 0.5 );cvShowImage("dist32s", dist32s);cvAndS( dist32s, cvScalarAll(255), dist32s, 0 );cvShowImage("dist32s2", dist32s);IplImage *dist8u1 = cvCloneImage(src);cvConvertScale( dist32s, dist8u1, 1, 0 );cvShowImage("dist8u1", dist8u1);*/for (int y=0; y<src->height; y++){uchar *pt = (uchar*)(src->imageData+y*src->widthStep);for (int x=0; x<src->width; x++){cout << int(pt[x]) << '\t';}cout << endl;}cout << endl << endl;for (int y=0; y<dist->height; y++){float *p = (float *)(dist->imageData+y*dist->widthStep);//因为输出图像必须是浮点型数据,所以这里必须采用float。也是自己一开始做错的。虽然IplImage->imageData是char型的,但是针对不同类型(字节型浮点型)要有不同的处理方式for (int x=0; x<dist->width; x++){cout << float(p[x]) << '\t';}cout << endl;}cvShowImage("src",src);cvShowImage("dist", dist);cvWaitKey(0);return 0;}
运行结果



如果将距离运算改为CV_DIST_L2运行结果:




因为一开始栽倒数据访问上了,所以有必要将opencv中像素访问方式贴出来,方便以后查阅。csnd编辑界面太差了,一堆乱码,大家还是移步到:http://www.opencv.org.cn/index.php/OpenCV_编程简介(矩阵/图像/视频的基本读写操作)

这篇关于kinect学习笔记四(距离变换 distance tranform 和opencv像素访问方式)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/888132

相关文章

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

MySQL中的InnoDB单表访问过程

《MySQL中的InnoDB单表访问过程》:本文主要介绍MySQL中的InnoDB单表访问过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、访问类型【1】const【2】ref【3】ref_or_null【4】range【5】index【6】

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文

前端如何通过nginx访问本地端口

《前端如何通过nginx访问本地端口》:本文主要介绍前端如何通过nginx访问本地端口的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、nginx安装1、下载(1)下载地址(2)系统选择(3)版本选择2、安装部署(1)解压(2)配置文件修改(3)启动(4)

Python如何将OpenCV摄像头视频流通过浏览器播放

《Python如何将OpenCV摄像头视频流通过浏览器播放》:本文主要介绍Python如何将OpenCV摄像头视频流通过浏览器播放的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完... 目录方法1:使用Flask + MJPEG流实现代码使用方法优点缺点方法2:使用WebSocket传输视

gitlab安装及邮箱配置和常用使用方式

《gitlab安装及邮箱配置和常用使用方式》:本文主要介绍gitlab安装及邮箱配置和常用使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装GitLab2.配置GitLab邮件服务3.GitLab的账号注册邮箱验证及其分组4.gitlab分支和标签的

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间