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