3.3 距离变换

3.3.4 距离变换-扫描

  1 //////https://blog.csdn.net/gone_huilin/article/details/53223026
  2 #include <opencv2/imgproc/imgproc.hpp>
  3 #include <opencv2/core/core.hpp>
  4 #include <opencv2/highgui/highgui.hpp>
  5 #include <iostream>
  6 // 计算欧式距离
  7 float calcEuclideanDistance(int x1, int y1, int x2, int y2)
  8 {
  9     return sqrt(float((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)));
 10 }
 11 // 计算棋盘距离
 12 int calcChessboardDistance(int x1, int y1, int x2, int y2)
 13 {
 14     return cv::max(abs(x1 - x2), abs(y1 - y2));
 15 }
 16 // 计算街区距离
 17 int calcBlockDistance(int x1, int y1, int x2, int y2)
 18 {
 19     return abs(x1 - x2) + abs(y1 - y2);
 20 }
 21 // 距离变换函数实现
 22 void distanceTrans(cv::Mat &srcImage, cv::Mat &resultIamge)
 23 {
 24     CV_Assert(srcImage.data != NULL);
 25     cv::Mat srcGray, srcBinary;
 26     // 转换成灰度图像
 27     cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);
 28     // 转换成二值图像
 29     threshold(srcGray, srcBinary, 100, 255, cv::THRESH_BINARY);
 30     cv::imshow("srcBinary", srcBinary);
 31     int rows = srcBinary.rows;
 32     int cols = srcBinary.cols;
 33     uchar* pDataOne;
 34     uchar* pDataTwo;
 35     float disPara = 0;
 36     float fDisMin = 0;
 37     // 第一遍遍历图像用左模板更新像素值
 38     for (int i = 1; i < rows - 1; i++)
 39     {
 40         // 图像指针获取
 41         pDataOne = srcBinary.ptr<uchar>(i);
 42         for (int j = 1; j < cols; j++)
 43         {
 44             // 分别计算其左模板掩码相关距离
 45             //   pL  pL
 46             //   pL  p
 47             //   pL
 48             pDataTwo = srcBinary.ptr<uchar>(i - 1);
 49             disPara = calcEuclideanDistance(i, j, i - 1, j - 1);
 50             fDisMin = cv::min((float)pDataOne[j],
 51                 disPara + pDataTwo[j - 1]);
 52             disPara = calcEuclideanDistance(i, j, i - 1, j);
 53             fDisMin = cv::min(fDisMin,
 54                 disPara + pDataTwo[j]);
 55             pDataTwo = srcBinary.ptr<uchar>(i);
 56             disPara = calcEuclideanDistance(i, j, i, j - 1);
 57             fDisMin = cv::min(fDisMin,
 58                 disPara + pDataTwo[j - 1]);
 59             pDataTwo = srcBinary.ptr<uchar>(i + 1);
 60             disPara = calcEuclideanDistance(i, j, i + 1, j - 1);
 61             fDisMin = cv::min(fDisMin,
 62                 disPara + pDataTwo[j - 1]);
 63             pDataOne[j] = (uchar)cvRound(fDisMin);
 64         }
 65     }
 66     // 第二遍遍历图像用右模板更新像素值
 67     for (int i = rows - 2; i > 0; i--)
 68     {
 69         pDataOne = srcBinary.ptr<uchar>(i);
 70         for (int j = cols - 1; j >= 0; j--)
 71         {
 72             // 分别计算其右模板掩码相关距离
 73             //   pR  pR
 74             //   pR  p
 75             //   pR
 76             pDataTwo = srcBinary.ptr<uchar>(i + 1);
 77             disPara = calcEuclideanDistance(i, j, i + 1, j);
 78             fDisMin = cv::min((float)pDataOne[j],
 79                 disPara + pDataTwo[j]);
 80             disPara = calcEuclideanDistance(i, j, i + 1, j + 1);
 81             fDisMin = cv::min(fDisMin,
 82                 disPara + pDataTwo[j + 1]);
 83             pDataTwo = srcBinary.ptr<uchar>(i);
 84             disPara = calcEuclideanDistance(i, j, i, j + 1);
 85             fDisMin = cv::min(fDisMin,
 86                 disPara + pDataTwo[j + 1]);
 87             pDataTwo = srcBinary.ptr<uchar>(i - 1);
 88             disPara = calcEuclideanDistance(i, j, i - 1, j + 1);
 89             fDisMin = cv::min(fDisMin,
 90                 disPara + pDataTwo[j + 1]);
 91             pDataOne[j] = (uchar)cvRound(fDisMin);
 92         }
 93     }
 94     resultIamge = srcBinary.clone();
 95 }
 96 int main()
 97 {
 98     cv::Mat srcImage = cv::imread("D:\\沙漠.jpg");
 99     if (!srcImage.data)
100         return -1;
101     cv::Mat resultIamge;
102     distanceTrans(srcImage, resultIamge);
103     cv::imshow("resultIamge", resultIamge);
104     cv::waitKey(0);
105     return 0;
106 }

应用:

https://blog.csdn.net/dan1900/article/details/16989023

https://blog.csdn.net/augusdi/article/details/9022077

https://blog.csdn.net/u014751607/article/details/61919706

https://blog.csdn.net/qq_34784753/article/details/68951918?locationNum=8&fps=1

https://blog.csdn.net/guoruijiushiwo/article/details/72841482

3.3.5 距离变换-distanceTransform

Opencv中distanceTransform方法用于计算图像中每一个非零点距离离自己最近的零点的距离,distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,图像上越亮的点,代表了离零点的距离越远。

 1 ////////https://blog.csdn.net/gone_huilin/article/details/53223066
 2 #include <opencv2/imgproc/imgproc.hpp>
 3 #include <opencv2/core/core.hpp>
 4 #include <opencv2/highgui/highgui.hpp>
 5 #include <iostream>
 6 int main()
 7 {
 8     cv::Mat srcImage = cv::imread("D:\\六角星.jpg");
 9     if (!srcImage.data)
10         return -1;
11     // 转换为灰度图像
12     cv::Mat srcGray;
13     cvtColor(srcImage, srcGray, CV_BGR2GRAY);
14     // 转换为二值图像
15     cv::Mat srcBinary;
16     threshold(srcGray, srcBinary, 160, 255, cv::THRESH_BINARY);
17     // 距离变换
18     cv::Mat dstImage;
19     cv::distanceTransform(srcBinary, dstImage, CV_DIST_L2,
20         CV_DIST_MASK_PRECISE);
21     // 归一化矩阵
22     cv::normalize(dstImage, dstImage, 0, 1., cv::NORM_MINMAX);
23     cv::imshow("srcBinary", srcBinary);
24     cv::imshow("dstImage", dstImage);
25     cv::waitKey(0);
26     return 0;
27 }

 1 #include "core/core.hpp"
 2 #include "imgproc/imgproc.hpp"
 3 #include "highgui/highgui.hpp"
 4
 5 using namespace cv;
 6
 7 int main(int argc, char *argv[])
 8 {
 9     float maxValue = 0;  //定义距离变换矩阵中的最大值
10     //Mat image = imread(argv[1]);
11     Mat image = imread("D:\\字母ABCD.jpg");
12     Mat imageGray;
13     cvtColor(image, imageGray, CV_RGB2GRAY);
14     imageGray = ~imageGray;  //取反
15     GaussianBlur(imageGray, imageGray, Size(5, 5), 2); //滤波
16     threshold(imageGray, imageGray, 20, 200, CV_THRESH_BINARY); //阈值
17     imshow("s", imageGray);
18     Mat imageThin(imageGray.size(), CV_32FC1); //定义保存距离变换结果的Mat矩阵
19     distanceTransform(imageGray, imageThin, CV_DIST_L2, 3);  //距离变换
20     Mat distShow;
21     distShow = Mat::zeros(imageGray.size(), CV_8UC1); //定义细化后的字符轮廓
22     for (int i = 0; i<imageThin.rows; i++)
23     {
24         for (int j = 0; j<imageThin.cols; j++)
25         {
26             if (imageThin.at<float>(i, j)>maxValue)
27             {
28                 maxValue = imageThin.at<float>(i, j);  //获取距离变换的极大值
29             }
30         }
31     }
32     for (int i = 0; i<imageThin.rows; i++)
33     {
34         for (int j = 0; j<imageThin.cols; j++)
35         {
36             if (imageThin.at<float>(i, j)>maxValue / 1.9)
37             {
38                 distShow.at<uchar>(i, j) = 255;   //符合距离大于最大值一定比例条件的点设为255
39             }
40         }
41     }
42     imshow("Source Image", image);
43     imshow("Thin Image", distShow);
44     waitKey();
45     return 0;
46 }

 1 ////////distanceTransform应用:查找物体质心
 2 ////////https://blog.csdn.net/dcrmg/article/details/52517991
 3 #include "core/core.hpp"
 4 #include "imgproc/imgproc.hpp"
 5 #include "highgui/highgui.hpp"
 6
 7 using namespace cv;
 8
 9 int main(int argc, char *argv[])
10 {
11     float maxValue = 0;  //定义距离变换矩阵中的最大值
12     Point Pt(0, 0);
13     Mat image = imread("D:\\六角星.jpg");
14     Mat imageGray;
15     cvtColor(image, imageGray, CV_RGB2GRAY);
16     imageGray = ~imageGray;  //取反
17     GaussianBlur(imageGray, imageGray, Size(5, 5), 2); //滤波
18     threshold(imageGray, imageGray, 20, 200, CV_THRESH_BINARY); //阈值化
19     Mat imageThin(imageGray.size(), CV_32FC1); //定义保存距离变换结果的Mat矩阵
20     distanceTransform(imageGray, imageThin, CV_DIST_L2, 3);  //距离变换
21     Mat distShow;
22     distShow = Mat::zeros(imageGray.size(), CV_8UC1); //定义细化后的字符轮廓
23     for (int i = 0; i<imageThin.rows; i++)
24     {
25         for (int j = 0; j<imageThin.cols; j++)
26         {
27             distShow.at<uchar>(i, j) = imageThin.at<float>(i, j);
28             if (imageThin.at<float>(i, j)>maxValue)
29             {
30                 maxValue = imageThin.at<float>(i, j);  //获取距离变换的极大值
31                 Pt = Point(j, i);  //坐标
32             }
33         }
34     }
35     normalize(distShow, distShow, 0, 255, CV_MINMAX); //为了显示清晰,做了0~255归一化
36     circle(image, Pt, maxValue, Scalar(0, 0, 255), 3);
37     circle(image, Pt, 3, Scalar(0, 255, 0), 3);
38     imshow("Source Image", image);
39     imshow("Thin Image", distShow);
40     waitKey();
41     return 0;
42 }

 1 ////////https://blog.csdn.net/wuhaibing_cver/article/details/8602461
 2 #include <opencv2/imgproc/imgproc.hpp>
 3 #include <opencv2/core/core.hpp>
 4 #include <opencv2/highgui/highgui.hpp>
 5 #include <cv.h>
 6 #include <highgui.h>
 7
 8 int main()
 9 {
10     char* filename = "D:\\二值化手.jpg";
11     IplImage* src_image = cvLoadImage(filename, 1);
12     if (!src_image)
13         return -1;
14     cvNamedWindow("src");
15
16     CvSize size = cvGetSize(src_image);
17     IplImage* gray_image = cvCreateImage(size, 8, 1);
18     cvCvtColor(src_image, gray_image, CV_BGR2GRAY);
19
20     IplImage* dist_image = cvCreateImage(size, 32, 1);
21     IplImage* bi_src = cvCreateImage(size, 8, 1);
22     IplImage* dist8u_image = cvCreateImage(size, 8, 1);
23     IplImage* bi_dist = cvCreateImage(size, 8, 1);
24     //原图像二值化
25     cvThreshold(gray_image, bi_src, 100, 255, CV_THRESH_BINARY);
26     //距离变换
27     cvDistTransform(bi_src, dist_image, CV_DIST_L2, 3, 0, 0);
28     //找最大值
29     double max;
30     cvMinMaxLoc(dist_image, 0, &max, 0, 0);
31     cvCvtScale(dist_image, dist8u_image, 255. / max);
32     //对距离图像二值化,去除手指部分
33     cvThreshold(dist8u_image, bi_dist, 80, 255, CV_THRESH_BINARY);
34     //求重心
35     float s = 0.0, x = 0.0, y = 0.0;
36     uchar* data = (uchar*)bi_dist->imageData;
37     int step = bi_dist->widthStep;
38     for (int h = 0; h<bi_dist->height; h++)
39         for (int w = 0; w<bi_dist->width; w++)
40             if (255 == data[step*h + w])
41             {
42                 x += w;
43                 y += h;
44                 s++;
45             }
46     if (s>0)
47     {
48         x = x / s;
49         y = y / s;
50     }
51     CvPoint pos = cvPoint((int)x, (int)y);
52
53     cvCircle(src_image, pos, 3, CV_RGB(255, 0, 0), 1, CV_AA);
54     cvShowImage("src", src_image);
55     cvWaitKey(-1);
56
57     cvDestroyWindow("src");
58     cvReleaseImage(&src_image);
59     cvReleaseImage(&gray_image);
60     cvReleaseImage(&bi_src);
61     cvReleaseImage(&dist8u_image);
62     cvReleaseImage(&bi_dist);
63
64     return 0;
65 }

参考:

https://blog.csdn.net/dcrmg/article/details/52517991

https://blog.csdn.net/wuhaibing_cver/article/details/8602461

原理参考:https://blog.csdn.net/liubing8609/article/details/78483667

其他参考:

https://blog.csdn.net/abcjennifer/article/details/7617883

https://blog.csdn.net/haoji007/article/details/52063389

http://www.linuxkiss.com/287.html

原文地址:https://www.cnblogs.com/thebreakofdawn/p/9484458.html

时间: 2024-10-11 09:33:22

3.3 距离变换的相关文章

图像处理之倒角距离变换

图像处理之倒角距离变换 图像处理中的倒角距离变换(Chamfer Distance Transform)在对象匹配识别中经常用到, 算法基本上是基于3x3的窗口来生成每个像素的距离值,分为两步完成距离变换,第一 步从左上角开始,从左向右.从上到下移动窗口扫描每个像素,检测在中心像素x的周 围0.1.2.3四个像素,保存最小距离与位置作为结果,图示如下: 第二步从底向上.从右向左,对每个像素,检测相邻像素4.5.6.7保存最小距离与 位置作为结果,如图示所: 完成这两步以后,得到的结果输出即为倒角

距离变换DT

距离变换:计算区域中的每个点与最接近的区域外的点之间距离,把二值图象变换为灰度图象. 对于目标中一个点,距离变换的定义为改点与目标边界最近的距离. 目标点离边界约近则值越小,转换的点越暗:越远,值越大,转换的点约亮.  a是原图,b是以图像边缘看做B,c是以两个白点看做B 计算方法: 1.串行实现: 模板:  将a分成b.c两个模板.做一次从左上角到右下角的前向扫描,做一次右下角到左上角的反向扫描. 扫描方案类似于卷积: 在扫到某个像素时,将模板系数值和图像的对应值加起来,将所得和中最小值赋给对

opencv::基于距离变换与分水岭的图像分割

什么是图像分割 图像分割(Image Segmentation)是图像处理最重要的处理手段之一 图像分割的目标是将图像中像素根据一定的规则分为若干(N)个cluster集合,每个集合包含一类像素. 根据算法分为监督学习方法和无监督学习方法,图像分割的算法多数都是无监督学习方法 - KMeans 距离变换常见算法有两种 - 不断膨胀/腐蚀得到 - 基于倒角距离 分水岭变换常见的算法 - 基于浸泡理论实现 cv::distanceTransform( InputArray src, OutputAr

[OpenCV] Image Processing - Non-linear Filtering

如果不是高斯噪声,怎么办? 中值滤波 散离噪声通常位于邻域内正确值的两端. (a) original image with Gaussian noise; (b) Gaussian filtered; (c) median filtered; (d) bilaterally filtered; (e) original image with shot noise; (f) Gaussian filtered; (g) median filtered; (h) bilaterally filter

【转】matlab函数_连通区域

转载自einyboy的博文Matlab的regionprops详解 1. matlab函数bwareaopen──删除小面积对象格式:BW2 = bwareaopen(BW,P,conn)作用:删除二值图像BW中面积小于P的对象,默认情况下使用8邻域.算法:(1)Determine the connected components.  L = bwlabeln(BW, conn);(2)Compute the area of each component.  S = regionprops(L,

python数字图像处理(19):骨架提取与分水岭算法

骨架提取与分水岭算法也属于形态学处理范畴,都放在morphology子模块内. 1.骨架提取 骨架提取,也叫二值图像细化.这种算法能将一个连通区域细化成一个像素的宽度,用于特征提取和目标拓扑表示. morphology子模块提供了两个函数用于骨架提取,分别是Skeletonize()函数和medial_axis()函数.我们先来看Skeletonize()函数. 格式为:skimage.morphology.skeletonize(image) 输入和输出都是一幅二值图像. 例1: from s

【转】Matlab的regionprops详解

matlab函数_连通区域 1. matlab函数bwareaopen──删除小面积对象格式:BW2 = bwareaopen(BW,P,conn)作用:删除二值图像BW中面积小于P的对象,默认情况下使用8邻域.算法:(1)Determine the connected components.  L = bwlabeln(BW, conn);(2)Compute the area of each component.  S = regionprops(L, 'Area');(3)Remove s

【OpenCV学堂】图像处理开发者基本知识图谱

原创图像处理与机器学习文章,关注微信公众号[OpenCV学堂] 作为一个入门的图像处理开发者与工程师,要掌握的知识点也不少,不要看每个知识点只有几个字,可以说每个都代表一个算法,都有数学知识,都需要你认真领悟学习!不认真的学习一年两年你不可能做到下面的全部领悟与贯通,成为一个合格的图像处理与机器学习开发者,一个人工智能时代的程序员! 图像像素操作 - 几何运算-加减乘除 - 逻辑运算-与或非取反 - 像素读写 - 通道混合与调整 - 对比度与亮度调整 图像变换 - 插值(zoom in或out)

DPM(Deformable Parts Model)--原理(一)(转载)

DPM(Deformable Parts Model) Reference: Object detection with discriminatively trained partbased models. IEEE Trans. PAMI, 32(9):1627–1645, 2010. "Support Vector Machines for Multiple-Instance Learning,"Proc. Advances in Neural Information Proces