C/C++ 影象處理(14)------影象の輪廓填充
阿新 • • 發佈:2019-01-24
所謂影象的輪廓填充,是建立在影象的輪廓已然查詢完成的情況下的,以下面影象為例:
我們首先需要查詢到影象中的圓形和正方形的幾個輪廓,之後才能對這些輪廓進行處理(查詢的過程我們用到OpenCV的findContours函式)。
在得到輪廓之後,難點就轉變為如何填充輪廓了,對於左上角的圓來說,直接填充即可,然而對於圓環和“田”字,則一般只希望填充兩個輪廓直接的區域,中間的孔洞則保留,因此在對輪廓進行填充之前需要做進一步的判斷工作(通過判斷findContours函式的第三個引數物件實現),具體的實現程式碼如下:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "time.h"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
long time = clock();
int r = 100;
Mat src = Mat::zeros(Size(8 * r, 4 * r), CV_8UC1);
//繪製輪廓,因為線段本身有粗細,則繪製一個圓會檢測出兩個輪廓,需要特別注意
//繪製三個圓,其中一個巢狀著另一個
circle(src, cvPoint(2 * r, 2 * r), 80, Scalar(255), 2);
circle(src, cvPoint(2 * r, 2 * r), 50, Scalar(255), 2);
circle(src, cvPoint(r, r), 30, Scalar(255), 2);
//繪製一個田字
rectangle(src, cvPoint(4 * r - r / 2, 2 * r - r / 2), cvPoint(4 * r + r / 2, 2 * r + r / 2), Scalar(255), 2);
rectangle(src, cvPoint(4 * r - r * 2 / 5, 2 * r - r * 2 / 5), cvPoint(4 * r - r * 1 / 20, 2 * r - r * 1 / 20), Scalar(255), 2);
rectangle(src, cvPoint(4 * r - r * 2 / 5, 2 * r + r * 1 / 20), cvPoint(4 * r - r * 1 / 20, 2 * r + r * 2 / 5), Scalar(255));
rectangle(src, cvPoint(4 * r + r * 2 / 5, 2 * r - r * 2 / 5), cvPoint(4 * r + r * 1 / 20, 2 * r - r * 1 / 20), Scalar(255), 2);
rectangle(src, cvPoint(4 * r + r * 2 / 5, 2 * r + r * 1 / 20), cvPoint(4 * r + r * 1 / 20, 2 * r + r * 2 / 5), Scalar(255), 2);
Mat raw_dist1(src.size(), CV_32FC1);
vector<vector<Point> > contours; vector<Vec4i> hierarchy;
Mat src_copy = src.clone();
findContours(src_copy, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);//查詢輪廓,並以樹狀圖結果儲存輪廓資訊
for (size_t i = 0; i < contours.size(); i++)
{
if (hierarchy[i][3] != -1)//表示其為某一個輪廓的內嵌輪廓
{
if (hierarchy[hierarchy[i][3]][3] == -1)//表示其為最外層輪廓,上面檢測到的是其線條的內部
{
drawContours(raw_dist1, contours, i, Scalar(255), -1);
}
else
{
drawContours(raw_dist1, contours, i, Scalar(0), -1);
}
}
else
{
drawContours(raw_dist1, contours, i, Scalar(0), -1);
}
}
printf("花費時間%dms\n", clock() - time);
char* source_window = "Source";
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, src);
namedWindow("Distance1", CV_WINDOW_AUTOSIZE);
imshow("Distance1", raw_dist1);
imwrite("輪廓查詢影象.jpg", src);
imwrite("輪廓查詢完成影象.jpg", raw_dist1);
waitKey(0);
return(0);
}
通過上面的程式碼,我們把影象中的輪廓進行了白色的填充,結果如下圖所示
到此,我們得到了一副輪廓填充完成的影象,其中的填充區域為白色,如果需要進一步處理,則可以通過連通域檢測演算法找到各個輪廓畫素點的集合。
需要注意的是,上面的程式碼只支援到兩層輪廓的巢狀(一般而言,對於CAD等軟體出來的圖形最多隻會有兩層),再多層的巢狀則需要修改程式碼中的判斷部分。