OpenCV 距離變換的筆記
阿新 • • 發佈:2019-02-15
目前正在學習<影象處理,分析與機器視覺>裡面有提到距離變換計算,以此筆記記錄生活。
距離變換的定義 :計算影象中畫素點到最近零畫素點的距離,也就是零畫素點的最短距離。
Mat srcImage = imread("/Users/hanoi/Desktop/hand.jpg",0);
Mat dist_image(size,CV_32FC1);
distanceTransform(srcImage, dist_image, CV_DIST_L2, CV_DIST_MASK_3);
int main(int argc, const char * argv[])
{
Mat srcImage = imread("/Users/hanoi/Desktop/hand.jpg" ,0);
printf("step=%ld\n",srcImage.step[0]);
if (!srcImage.data)
{
cout << "讀入圖片錯誤!" << endl;
system("pause");
return -1;
}
Size size;
size.width = srcImage.cols;
size.height = srcImage.rows;
Mat dist_image(size,CV_32FC1);
Mat bi_src(size ,CV_8SC1);
distanceTransform(srcImage, dist_image, CV_DIST_L2, CV_DIST_MASK_3);
normalize(dist_image, dist_image, 0, 1, NORM_MINMAX);
imshow("src",dist_image);
//imwrite("/Users/hanoi/Desktop/gray1.jpg", dist_image );
Mat myImage(size,CV_8UC1);
for (int j=0; j<dist_image.rows; j++)
{
for (int i=0; i<dist_image.cols; i++)
{
double m = dist_image.at<float>(j,i );
int y = m * 255;
if(y > 255)
{
y = 255;
}
*(myImage.data + j*myImage.step[0] + i) = y;
}
}
imwrite("/Users/hanoi/Desktop/gray1.bmp", myImage);
waitKey();
return 0;
}
我們的type是CV_32FC1,所以每個畫素是4個位元組,為了能儲存影象,在進行歸一化處理之後,需要用距離*255,然後作為該畫素點的亮度值。
distanceTransform是opencv的提供的計算距離轉換的函式,個人覺得要主要是dest的輸出,存的是距離的矩陣,所以這裡我們建立的時候type是CV_32FC1。
其中距離的計算方法:
為了減少計算了量,我們採用的是一種倒角模版的演算法,只需要對影象進行兩次掃描玖可以實現距離變換,該方法被稱為chamfer倒角距離變換,該模版如下:
網路程式碼參考:
//距離變換的掃描實現
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace cv;
using namespace std;
//計算歐氏距離的函式
float calcEuclideanDiatance(int x1, int y1, int x2, int y2)
{
return sqrt(float((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)));
}
//計算棋盤距離的函式
int calcChessboardDistance(int x1, int y1, int x2, int y2)
{
return cv::max(abs(x1 - x2), (y1 - y2));
}
//計算麥哈頓距離(街區距離)
int calcBlockDistance(int x1, int y1, int x2, int y2)
{
return abs(x1 - x2) + abs(y1 - y2);
}
//距離變換函式的實現
void distanceTrans(Mat &srcImage, Mat &dstImage)
{
CV_Assert(srcImage.data != nullptr);
//CV_Assert()若括號中的表示式值為false,則返回一個錯誤資訊。
//定義灰度影象的二值影象
Mat grayImage, binaryImage;
//將原影象轉換為灰度影象
cvtColor(srcImage, grayImage, CV_BGR2GRAY);
//將灰度影象轉換為二值影象
threshold(grayImage, binaryImage, 100, 255, THRESH_BINARY);
imshow("二值化影象", binaryImage);
int rows = binaryImage.rows;
int cols = binaryImage.cols;
uchar *pDataOne;
uchar *pDataTwo;
float disPara = 0;
float fDisMIn = 0;
//第一遍遍歷影象,使用左模板更新畫素值
for (int i = 1; i < rows - 1; i++)
{
//影象的行指標的獲取
pDataOne = binaryImage.ptr<uchar>(i);
for (int j = 1; j < cols; j++)
{
//分別計算左模板掩碼的相關距離
//PL PL
//PL P
//PL
pDataTwo = binaryImage.ptr<uchar>(i - 1);
disPara = calcEuclideanDiatance(i, j, i - 1, j - 1);
fDisMIn = cv::min((float)pDataOne[j], disPara + pDataTwo[j - 1]);
disPara = calcEuclideanDiatance(i, j, i - 1, j);
fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j]);
pDataTwo = binaryImage.ptr<uchar>(i);
disPara = calcEuclideanDiatance(i, j, i, j - 1);
fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j-1]);
pDataTwo = binaryImage.ptr<uchar>(i+1);
disPara = calcEuclideanDiatance(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 = binaryImage.ptr<uchar>(i);
for (int j = cols - 1; j >= 0; j--)
{
//分別計算右模板掩碼的相關距離
//pR pR
//pR p
//pR
pDataTwo = binaryImage.ptr<uchar>(i + 1);
disPara = calcEuclideanDiatance(i, j, i + 1, j);
fDisMIn = cv::min((float)pDataOne[j], disPara + pDataTwo[j]);
disPara = calcEuclideanDiatance(i, j, i + 1, j + 1);
fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j+1]);
pDataTwo = binaryImage.ptr<uchar>(i);
disPara = calcEuclideanDiatance(i, j, i, j +1);
fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j + 1]);
pDataTwo = binaryImage.ptr<uchar>(i - 1);
disPara = calcEuclideanDiatance(i, j, i - 1, j + 1);
fDisMIn = cv::min(fDisMIn, disPara + pDataTwo[j + 1]);
pDataOne[j] = (uchar)cvRound(fDisMIn);
}
}
dstImage = binaryImage.clone();
}
//主函式
int main()
{
Mat srcImage = imread("2345.jpg");
if (!srcImage.data)
{
cout << "讀入圖片錯誤!" << endl;
system("pause");
return -1;
}
Mat dstImage;
distanceTrans(srcImage, dstImage);
imshow("距離變換影象", dstImage);
waitKey();
return 0;
}