距离变换运算用于计算二值化图像中的每一个非零点距自己最近的零点的距离,距离变换图像上越亮的点,代表了这一点距离零点的距离越远。
距离变换通常用于细化字符的轮廓和查找物体的质心(中心)。
OpenCV提供了distanceTransform函数用于计算二值化图像的距离变换。
这个函数的原型如下:
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:距离类型。可以的类型是CV_DIST_L1、CV_DIST_L2、CV_DIST_C,具体各类型的意义,请查阅相关算法文档。
maskSize:距离变换运算时的掩码大小。值可以是3、5或CV_DIST_MASK_PRECISE(5或CV_DIST_MASK_PRECISE只能用在第一个原型中)。当distanceType=CV_DIST_L1 或 CV_DIST_C时,maskSize只能为3。
dstType:输出图像(矩阵)的类型,可以是CV_8U 或 CV_32F。CV_8U只能用在第一个原型中,而且distanceType只能为CV_DIST_L1。
labels:输出二维阵列标签。(这是啥意思?抱歉,我也不知道,等以后知道了再来补充)
labelType:标签数组类型。可选值为DIST_LABEL_CCOMP和DIST_LABEL_PIXEL,具体各是什么含义,我现在也不清楚,等以后清楚了再来补充。
我们通常使用的是这个函数的第一个原型,所以对于参数“labels”和“labelType”,我们可以暂时不管。
使用distanceTransform函数进行距离变换的示例代码如下:
下面这段代码的作用是查询物体的质心位置。
代码如下:
图像处理开发资料、图像处理开发需求、图像处理接私活挣零花钱,可以搜索公众号"qxsf321",并关注!
代码中用到的图像下载链接:http://pan.baidu.com/s/1slnyePv 密码:3yh6
//opencv版本:OpenCV3.0
//VS版本:VS2013
//Author:qxsf321.net
#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; //取反,为什么要取反?请大家仔细思考距离变换的定义
//GaussianBlur(imageGray, imageGray, Size(5, 5), 2); //滤波
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;
}
运行结果截图如下: