opencv-distanceTransform 距离计算函数

用于计算图像中每一个非零点距离离自己最近的零点的距离 

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();

原文地址:https://www.cnblogs.com/liming19680104/p/15472690.html