距离变换的理解
a\b分别表示在水平垂直方向的距离,?/问号部分表示根据a和b的值的大小再确定其值。 如果定义了c值(用户自定义mask或者选择CV_DIST_L2等)在变为
所以定义c的时候必须是5*5的mask,然后在往外扩充的时候类似上面的问号类型,找到最小距离即可。
发布日期:2022-01-31 02:37:28
浏览次数:21
分类:技术文章
本文共 7645 字,大约阅读时间需要 25 分钟。
当时自己理解的一点小误区,放到这里防止再犯错。
距离变换的基本意思就是计算一个图像中非零像素点到最近的零像素点的距离,也就是到所有零像素点的最短距离。建立距离变换图像可以方便提取骨骼
在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=1
- CV_DIST_L1 (3×3):
- a=1, b=2
- CV_DIST_L2 (3×3):
- a=0.955, b=1.3693
- CV_DIST_L2 (5×5):
- a=1, b=1.4, c=2.1969
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 | |
? | b | a | b | ? |
2a | a | 0 | a | 2a |
? | b | a | b | ? |
b | ? | a | ? | b |
2b | c | 2a | c | 2b |
c | b | a | b | c |
2a | a | 0 | a | 2a |
c | b | a | b | c |
2b | c | 2a | c | 2b |
下面代码表示自己创建一个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;
- }
//距离变换代码,在微软的那个ppt中用来计算掌心的位置可能用到这个//部分内容在http://www.opencv.org.cn/forum/viewtopic.php?f=1&t=4574&start=0有解释#include运行结果#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 height; y++) { uchar *pt = (uchar*)(src->imageData+y*src->widthStep); for (int x=0; x width; x++) { cout << int(pt[x]) << '\t'; } cout << endl; } cout << endl << endl; for (int y=0; y height; y++) { float *p = (float *)(dist->imageData+y*dist->widthStep);//因为输出图像必须是浮点型数据,所以这里必须采用float。也是自己一开始做错的。虽然IplImage->imageData是char型的,但是针对不同类型(字节型浮点型)要有不同的处理方式 for (int x=0; x 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_编程简介(矩阵/图像/视频的基本读写操作)
转载地址:https://blog.csdn.net/LJH0600301217/article/details/8679566 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年03月30日 06时54分39秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
ElasticSearch 面试 4 连炮,你顶得住么?
2019-04-26
聊一聊:你碰到过哪些操蛋的文档?
2019-04-26
赠书:《深入理解 Spring Cloud 与实战》
2019-04-26
如何写好注释,让同事赞不绝口?
2019-04-26
好用!目前用下来最溜的MacOS微信多开工具!
2019-04-26
皮一皮:最头铁的汪峰...
2019-04-26
IntelliJ IDEA 2020.3.2 正式发布
2019-04-26
苹果开源代码中惊现“wechat”,老外注释的吐槽亮了!
2019-04-26
这回,不用为Linux命令发愁了吧
2019-04-26
皮一皮:直男最后的倔强...
2019-04-26
中国男人の数据大赏
2019-04-26
皮一皮:精致的人生,哪怕拔火罐也要搭配衣服出门...
2019-04-26
用了5年的Git,你竟然还不晓得它的实现原理!
2019-04-26
微信8.0之后,又悄悄上线新功能:别人“抢不到”的红包!赶紧看看灰度到你了没?...
2019-04-26
我以为的周末 vs 实际上的周末
2019-04-26
到底要刷多少道算法题面试才稳?
2019-04-26
据说这套组合拳,可以把面试官给问懵逼了,你要不要试试?
2019-04-26
皮一皮:还以为女神的眼睛特别好看...
2019-04-26
Spring中涉及的设计模式总结
2019-04-26
最近又Get个新技能,不是全栈也能用技术倒腾点东西赚零花钱了!
2019-04-26