用OpenCV的函数distanceTransform()作图像的距离变换,并找出图像中图形的几何中心

图像处理开发需求、图像处理接私活挣零花钱,请加微信/QQ 2487872782
图像处理开发资料、图像处理技术交流请加QQ群,群号 271891601

距离变换运算用于计算二值化图像中的每一个非零点距自己最近的零点的距离,距离变换图像上越亮的点,代表了这一点距离零点的距离越远。
通过以上定义我们可以想到距离变换通常用于细化字符的轮廓和查找物体的质心(中心)。

更详细的关于距离变换的原理和作用的介绍,可以参见我的另一篇博文,链接如下:

https://blog.csdn.net/wenhao_ir/article/details/51656160

OpenCV提供了函数distanceTransform()用于计算二值化图像的距离变换。

函数distanceTransform()有两个C++原型,分别如下:

C++: void distanceTransform(InputArray src, 
							OutputArray dst, 
							int distanceType, 
							int maskSize, 
							int dstType=CV_32F
						   )
C++: void distanceTransform(InputArray src, 
							OutputArray dst, 
							OutputArray labels, 
							int distanceType, 
							int maskSize, 
							int labelType=DIST_LABEL_CCOMP
						   )

第一个原型是我们常用的,所以我们这里介绍第一个原型中各参数的意义。

src:源矩阵
dst:目标矩阵
distanceType:距离类型,可选的类型如下:

DIST_USER 

User defined distance.

DIST_L1 

distance = |x1-x2| + |y1-y2|

DIST_L2 

the simple euclidean distance

DIST_C 

distance = max(|x1-x2|,|y1-y2|)

DIST_L12 

L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))

DIST_FAIR 

distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998

DIST_WELSCH 

distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846

DIST_HUBER 

distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345

maskSize:作距离变换运算时的掩码大小,可取值如下:

当距离类型为DIST_L1或DIST_C时,这个mask的大小被强制设定为3×3,因为更大的mask(比如5×5的mask)的运算结果和3×3一样。

dstType:输出图像(矩阵)的数据类型,可以是CV_8U 或 CV_32F。当选择CV_8U时,distanceType的类型只能为DIST_L1。

下面是使用OpenCV的函数distanceTransform()作图像距离变换的示例代码

代码中用到的图像下载链接:http://pan.baidu.com/s/1slnyePv 密码:3yh6

//opencv版本:OpenCV3.0
//VS版本:VS2013
//图像处理开发需求、图像处理接私活挣零花钱,请加微信/QQ 2487872782
//图像处理开发资料、图像处理技术交流请加QQ群,群号 271891601
 
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>    
#include <opencv2/imgproc/types_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
 
#include <iostream>
 
using namespace cv;
using namespace std;
 
int main()
{
        float maxValue = 0;  //存储距离变换结果矩阵中的最大值  
        Point Pt(0, 0);
        Mat image = imread("ceter.jpg");
        Mat image_1 = imread("ceter.jpg");
        if (image.empty())
        {
                cout << "Error: Could not load image" << endl;
                return 0;
        }
 
 
        Mat imageGray;
        cvtColor(image, imageGray, CV_BGR2GRAY);
        imageGray = ~imageGray;  //为什么要取反?我在下面有说明
        threshold(imageGray, imageGray, 20, 200, CV_THRESH_BINARY); //阈值化
 
        Mat imageThin(imageGray.size(), CV_32FC1); //定义保存距离变换结果的Mat矩阵  
        distanceTransform(imageGray, imageThin, CV_DIST_L2, 3);  //距离变换  
        Mat distShow;
        distShow = Mat::zeros(imageGray.size(), CV_8UC1); 
        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);
                        if (imageThin.at<float>(i, j)>maxValue)
                        {
                                maxValue = imageThin.at<float>(i, j);  //获取距离变换的最大值  
                                Pt = Point(j, i);  //记录最大值的坐标  
                        }
                }
        }
        normalize(distShow, distShow, 0, 255, CV_MINMAX); //为了显示清晰,做0~255归一化  
        circle(image, Pt, maxValue, Scalar(0, 0, 255), 3);//在原图中标示出最大距离半径
        circle(image, Pt, 3, Scalar(0, 255, 0), 3);//在原图中标示出几何中心
        imshow("Source Image", image_1);
        imshow("Dist_transform", distShow);
        imshow("Find centroid ", image);
 
        waitKey();
        return 0;
}

对于上面的代码有两点需要说明:

①为什么要对原图的灰度图像作取反处理?

答:看下面的两幅图,左边是原图的灰度图像,右边是灰度图像作取反处理后的图像。

再结合距离变换计算的是二值化图像中的每一个非零点距自己最近的零点的距离。应该就能想明白了为什么要作取处理了吧。如果不做取反处理,那么按下面的代码

threshold(imageGray, imageGray, 20, 200, CV_THRESH_BINARY); 

二值化之后,背景的灰度值是200,前景的灰度值是0,显然不是我们要计算的距离变换。我们要计算的灰度变换是背景的灰度值是0,而前景的灰度值是200。

② 为什么距离变换结果矩阵中最大值的点坐标是“ Point(j, i)”,而不是“Point(i, j)”?

答:这里的坐标是指直角坐标系的坐标,在直角坐标系中,第一个数对应的是x轴的坐标,第二个数对应的y轴的坐标。x轴对应的坐标值是矩阵中元素的列号,y轴对应的坐标值是矩阵中元素的行号。

代码运行结果如下图所示:

图像处理开发需求、图像处理接私活挣零花钱,请加微信/QQ 2487872782
图像处理开发资料、图像处理技术交流请加QQ群,群号 271891601

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值