OpenCV距离变换实现
2018-02-12 15:23:34         来源：wang_128的博客

1.将图像进行二值化，子图像值为0，背景为255；

4.F(p) 则为距离变换后的图像。

```//计算欧式距离
float calcEuclideanDistance(int x1, int y1, int x2, int y2)
{
return sqrt(float((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)));
}

//计算棋盘距离
int calcChessboardDistance(int x1, int y1, int x2, int y2)
{
return cv::max(abs(x1 - x2), abs(y1 - y2));
}

//计算街区距离
int calcBlockDistance(int x1, int y1, int x2, int y2)
{
return abs(x1 - x2) + abs(y1 - y2);
}

//距离变换函数实现
void distanceTrans(cv::Mat &image, cv::Mat &result)
{
//CV_Assert（）若括号中的表达式值为false，则返回一个错误信息
CV_Assert(!image.empty());
cv::Mat imageGray, imageBinary;
//转换成灰度图像
cv::cvtColor(image, imageGray, CV_RGB2GRAY);
//转换成二值图
cv::threshold(imageGray, imageBinary, 100, 255, cv::THRESH_BINARY);
cv::imshow("imageBinary", imageBinary);
int rows = imageBinary.rows, cols = imageBinary.cols;
uchar* pDataOne, *pDataTwo;
float disPara = 0, fDisMin = 0;
//第一遍遍历图像，用左模板更新像素值
for (int i = 1; i < rows - 1; i++)
{
//图像指针获取
pDataOne = imageBinary.ptr(i);
for (int j = 1; j < cols; j++)
{
//分别计算其左掩码的相关距离
// pL pL
// pL p
// pL
pDataTwo = imageBinary.ptr(i - 1);
disPara = calcEuclideanDistance(i, j, i - 1, j - 1);
fDisMin = cv::min((float)pDataOne[j], disPara + pDataTwo[j - 1]);
disPara = calcEuclideanDistance(i, j, i - 1, j);
fDisMin = cv::min(fDisMin, disPara + pDataTwo[j]);
pDataTwo = imageBinary.ptr(i);
disPara = calcEuclideanDistance(i, j, i, j - 1);
fDisMin = cv::min(fDisMin, disPara + pDataTwo[j - 1]);
pDataTwo = imageBinary.ptr(i + 1);
disPara = calcEuclideanDistance(i, j, i + 1, j - 1);
fDisMin = cv::min(fDisMin, disPara + pDataTwo[j - 1]);
pDataOne[j] = (uchar)cvRound(fDisMin);
}
}
//第二遍遍历图像，用右模板更新图像值
for (int i = rows - 2; i > 0; i--)
{
//图像指针获取
pDataOne = imageBinary.ptr(i);
for (int j = cols - 2; j >= 0; j--)
{
//分别计算其右掩码的相关距离
//    pR
// p  pR
// pR pR
pDataTwo = imageBinary.ptr(i + 1);
disPara = calcEuclideanDistance(i, j, i + 1, j);
fDisMin = cv::min((float)pDataOne[j], disPara + pDataTwo[j]);
disPara = calcEuclideanDistance(i, j, i + 1, j + 1);
fDisMin = cv::min(fDisMin, disPara + pDataTwo[j + 1]);
pDataTwo = imageBinary.ptr(i);
disPara = calcEuclideanDistance(i, j, i, j + 1);
fDisMin = cv::min(fDisMin, disPara + pDataTwo[j + 1]);
pDataTwo = imageBinary.ptr(i - 1);
disPara = calcEuclideanDistance(i, j, i - 1, j + 1);
fDisMin = cv::min(fDisMin, disPara + pDataTwo[j + 1]);
pDataOne[j] = (uchar)cvRound(fDisMin);
}
}
result = imageBinary.clone();
}```

OpenCV距离变换函数：

`void distanceTransform(InputArray src, OutputArray dst, int distanceType, int maskSize, int dstType=CV_32F )`
src：输入矩阵
dst：输出矩阵
distanceType：距离类型。可以的类型是CV_DIST_L1、CV_DIST_L2、CV_DIST_C（CV_DIST_L1街区距离，CV_DIST_L2欧几里得距离，CV_DIST_C棋盘距离）。
dstType：输出图像的类型，可以是CV_8U 或 CV_32F。

```int main()
{
if (image.empty()) return -1;
cv::imshow("image", image);
//转换为灰度图
cv::Mat imageGray, imageBinary, result1;
cv::cvtColor(image, imageGray, CV_RGB2GRAY);
//转换为二值图
cv::threshold(imageGray, imageBinary, 160, 255, cv::THRESH_BINARY);
//距离变换
//归一化矩阵
cv::normalize(result1, result1, 0, 1, cv::NORM_MINMAX);
cv::imshow("imageBinary1", imageBinary);
cv::imshow("result1", result1);
cv::waitKey(0);
return 0;
}```