用于计算图像中每一个非零点距离离自己最近的零点的距离
1.png
cv::Mat src = cv::imread("D:/bb/tu1/1.png",0); cv::Mat imageThin(src.size(), CV_32FC1); //定义保存距离变换结果的Mat矩阵 distanceTransform(src, imageThin, CV_DIST_L2, 3); //距离计算 /* 参数1:8-bit, 单通道输入图片 参数2:输出结果中包含计算的距离,这是一个32-bit float 单通道的Mat类型,大小与输入图片相同 参数3:distanceType计算距离的类型 distanceType maskSize a b c CV_DIST_C 3(3X3) a = 1, b = 1 CV_DIST_L1 3(3X3) a = 1, b = 2 CV_DIST_L2 3(3X3) a=0.955, b=1.3693 CV_DIST_L2 5(5X5) a=1, b=1.4, c=2.1969 参数4:maskSize – 距离变换掩码矩阵的大小 3(CV_DIST_L1、 CV_DIST_L2 、CV_DIST_C) 5(CV_DIST_L2 ) CV_DIST_MASK_PRECISE (这个只能在4参数的API中使用) 参数5:目标矩阵的数据类型
CV_8U
说明:其中 a b c 含义:在这个函数中计算每个非0像素到黑色像素(0值像素)的最短距离,因此需要通过最短的移动方式找到这个点计算他们之间的值。通常来说移动有水平方向、竖直方向、对角方向、跳跃式几个移动方法。虽然计算距离的方法都是一些很基础的公式,但是这个这个掩码矩阵必须是对阵的,因此掩码矩阵上所有水平和竖直方向的变化量,这里用 a 代表;对角方向的变化量用 b 代表;跳跃移动的变化量用 c 代表。CV_DIST_C、CV_DIST_L1、CV_DIST_L2(maskSize=5)的计算结果是精确的,CV_DIST_L2(maskSize=3)是一个快速计算方法 */
应用一:细化轮廓
2.png
float maxValue = 0; //保存距离变换矩阵中的最大值 cv::Mat src = cv::imread("D:/bb/tu1/2.png",0); cv::Mat imageGray=~src; //取反 cv::GaussianBlur(imageGray, imageGray, cv::Size(5, 5), 2); //滤波-去除杂点 cv::threshold(imageGray, imageGray, 10, 200, 0); cv::namedWindow("imageGray"); cv::imshow("imageGray",imageGray); cv::Mat imageThin(imageGray.size(), CV_32FC1); cv::distanceTransform(imageGray, imageThin, CV_DIST_L2, 3); //距离计算 cv::Mat distShow; distShow = cv::Mat::zeros(imageGray.size(), CV_8UC1); for (int i = 0; i < imageThin.rows; i++) { for (int j = 0; j < imageThin.cols; j++) { if (imageThin.at<float>(i, j) > maxValue) { maxValue = imageThin.at<float>(i, j); //获取距离变换的最大值 } } } for (int i = 0; i < imageThin.rows; i++) { for (int j = 0; j < imageThin.cols; j++) { if (imageThin.at<float>(i, j) > maxValue / 1.9) { distShow.at<uchar>(i, j) = 255; //符合距离大于最大值一定比例条件的点设为255 } } } cv::namedWindow("distShow"); cv::imshow("distShow", distShow);
应用二:查找物体质心
3.png
cv::Mat src = cv::imread("D:/bb/tu1/3.png"); cv::Mat imageGray; cv::cvtColor(src, imageGray, CV_RGB2GRAY); imageGray = ~imageGray; cv::threshold(imageGray, imageGray, 20, 255, 0); cv::Mat imageThin(imageGray.size(), CV_32FC1); cv::distanceTransform(imageGray, imageThin, CV_DIST_L2, 3); //距离变换 cv::Mat distShow; distShow = cv::Mat::zeros(imageGray.size(), CV_8UC1); float maxValue = 0; cv::Point Pt(0, 0); for (int i = 0; i < imageThin.rows; i++) { for (int j = 0; j < imageThin.cols; j++) { distShow.at<uchar>(i, j) = imageThin.at<float>(i, j); //把float转换成uchar之后,距离越远的地方越亮 if (imageThin.at<float>(i, j) > maxValue) { maxValue = imageThin.at<float>(i, j); //获取距离变换的最大值 Pt = cv::Point(j, i); //最大值的坐标 } } } cv::normalize(distShow, distShow, 0, 255, CV_MINMAX); //为了显示清晰,做了0~255归一化 cv::circle(src, Pt, maxValue, cv::Scalar(0, 0, 255), 3); cv::circle(src, Pt, 3, cv::Scalar(0, 255, 0), 3); cv::namedWindow("src1"); cv::imshow("src1", src); cv::waitKey();