1. 程式人生 > >OPENCV中提取連通區域輪廓

OPENCV中提取連通區域輪廓

在進行影象分割後,可能需要對感興趣的目標區域進行提取,比較常用的方法是計算輪廓

通過輪廓可以獲得目標的一些資訊:

(1)目標位置

(2)目標大小(即面積)

(3)目標形狀(輪廓矩)

當然,輪廓不一定代表希望目標區域,閾值分割時可能造成一部分資訊丟失,因此可以計算輪廓的質心座標,再進行漫水填充

程式中有尋找質心+填充,但效果不好,因此就不放填充後的圖了。

實驗結果:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdio.h>

using namespace cv;
using namespace std;

vector<vector<Point> > contours;   //輪廓陣列
vector<Point2d>  centers;    //輪廓質心座標 
vector<vector<Point> >::iterator itr;  //輪廓迭代器
vector<Point2d>::iterator  itrc;    //質心座標迭代器
vector<vector<Point> > con;    //當前輪廓


int main()
{
	double area;
	double minarea = 100;
    double maxarea = 0;
	Moments mom; // 輪廓矩
	Mat image,gray,edge,dst;
	namedWindow("origin");
	namedWindow("connected_region");

	image = imread("view.jpg");
    cvtColor(image, gray, COLOR_BGR2GRAY);
	blur(gray, edge, Size(3,3));   //模糊去噪
	threshold(edge,edge,200,255,THRESH_BINARY);   //二值化處理
	
	/*尋找輪廓*/
	 findContours( edge, contours,
        CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE );
	 itr = contours.begin();     //使用迭代器去除噪聲輪廓
	 while(itr!=contours.end())
	 {
		 area = contourArea(*itr);
		 if(area<minarea)
		 {
			 itr = contours.erase(itr);  //itr一旦erase,需要重新賦值
		 }
		 else
		 {
		    itr++;
		 }
			if (area>maxarea)
		 {
			 maxarea = area;
		 }
	 }
	  dst = Mat::zeros(image.rows,image.cols,CV_8UC3);
	 
	  /*繪製連通區域輪廓,計算質心座標*/
	  Point2d center;
	  itr = contours.begin();
	 while(itr!=contours.end())
	 {
		 area = contourArea(*itr);
		 con.push_back(*itr);
		 if(area==maxarea)
			 drawContours(dst,con,-1,Scalar(0,0,255),2);  //最大面積紅色繪製
		 else
			 drawContours(dst,con,-1,Scalar(255,0,0),2);   //其它面積藍色繪製
		 con.pop_back();

		 //計算質心
		 mom = moments(*itr);
		 center.x = (int)(mom.m10/mom.m00);
		 center.y = (int)(mom.m01/mom.m00);
		 centers.push_back(center);

		 itr++;
	 }
    imshow("origin",image);
    imshow("connected_region",dst);
    waitKey(0);

   /*漫水填充連通區域*/
    Point2d seed;
    int new_scalar = 0;
    int loDiff = 8, upDiff = 8;
    int connectivity = 4;    

	itrc = centers.begin();
	while(itrc!=centers.end())
   {  
	   seed = *itrc;
	   floodFill(image,seed,Scalar::all(new_scalar),NULL,
		Scalar::all(loDiff),Scalar::all(upDiff),connectivity);
	   itrc++;
	}

    waitKey(0);
    return 0 ;
}