1. 程式人生 > >cvFindContours/findContours提取輪廓

cvFindContours/findContours提取輪廓

opencv在提取輪廓時,C/C++有兩種方式,有些許不同,結合查詢的資料和補充,做個小筆記;

功能,提取滿足一定面積閾值和寬高比例的輪廓;

主函式

static int getContoursByC(char* Imgname, double minarea = 100, double whRatio = 1);
static int getContoursByCplus(char* Imgname, double minarea=0, double whRatio=1);
int main()
{
	char* filename = new char[50];
	strcpy(filename, "../image/rl_4.jpg");
	getContoursByCplus(filename);
	delete[] filename;
	return 0;
}

API實現

cvFindContours形式

/*採用cvFindContours提取輪廓,並過濾掉小面積輪廓,最後將輪廓儲存*/
static int getContoursByC(char* Imgname, double minarea, double whRatio)
{
	IplImage* src = cvLoadImage(Imgname, CV_LOAD_IMAGE_GRAYSCALE);
	if (!src)
	{
		printf("read data error!\n");
		return -1;
	}
	IplImage* dst = cvCreateImage(cvGetSize(src), 8, 3);
	
	//the parm. for cvFindContours
	CvMemStorage* storage = cvCreateMemStorage(0);
	CvSeq* contour = 0;
	double maxarea = 0;

	//for display
	cvNamedWindow("Source", CV_WINDOW_NORMAL);
	cvShowImage("Source", src);

	//二值化
	cvThreshold(src, src, 120, 255, CV_THRESH_BINARY);
	
	//提取輪廓
	cvFindContours(src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
	cvZero(dst);//清空陣列

	/*CvSeq* _contour為了儲存輪廓的首指標位置,因為隨後contour將用來迭代*/
	CvSeq* _contour = contour;
	

	int maxAreaIdx = -1, iteratorIdx = 0;//n為面積最大輪廓索引,m為迭代索引
	for (int iteratorIdx = 0; contour != 0; contour = contour->h_next, iteratorIdx++/*更新迭代索引*/)
	{

		double tmparea = fabs(cvContourArea(contour));
		if (tmparea > maxarea)
		{
			maxarea = tmparea;
			maxAreaIdx = iteratorIdx;
			continue;
		}
		if (tmparea < minarea)
		{
			//刪除面積小於設定值的輪廓
			cvSeqRemove(contour, 0); 
			continue;
		}
		CvRect aRect = cvBoundingRect(contour, 0);
		if ((aRect.width / aRect.height)<whRatio)
		{
			//刪除寬高比例小於設定值的輪廓
			cvSeqRemove(contour, 0); 
			continue;
		}
		//CvScalar color = CV_RGB( rand()&255, rand()&255, rand()&255 );//建立一個色彩值
		//CvScalar color = CV_RGB(0, 255, 255);

		//max_level 繪製輪廓的最大等級。如果等級為0,繪製單獨的輪廓。如果為1,繪製輪廓及在其後的相同的級別下輪廓。
		//如果值為2,所有的輪廓。如果等級為2,繪製所有同級輪廓及所有低一級輪廓,諸此種種。
		//如果值為負數,函式不繪製同級輪廓,但會升序繪製直到級別為abs(max_level)-1的子輪廓。 
		//cvDrawContours(dst, contour, color, color, -1, 1, 8);//繪製外部和內部的輪廓
	}
	contour = _contour; /*int k=0;*/
	//統計剩餘輪廓,並畫出最大面積的輪廓
	int count = 0;
	for (; contour != 0; contour = contour->h_next)
	{
		count++;
		double tmparea = fabs(cvContourArea(contour));
		if (tmparea == maxarea /*k==n*/)
		{
			CvScalar color = CV_RGB(255, 0, 0);
			cvDrawContours(dst, contour, color, color, -1, 1, 8);
		}
		/*k++;*/
	}
	printf("The total number of contours is:%d", count);
	cvNamedWindow("Components", CV_WINDOW_NORMAL);
	cvShowImage("Components", dst);
	cvSaveImage("dst.jpg", dst);
	//roateProcess(dst);
	cvWaitKey(0);
	//銷燬視窗和影象儲存
	cvDestroyWindow("Source");
	cvReleaseImage(&src);
	cvDestroyWindow("Components");
	cvReleaseImage(&dst);
	return 0;
}

findContours形式
static int getContoursByCplus(char* Imgname, double minarea, double whRatio)
{
	cv::Mat src, dst, canny_output;
	/// Load source image and convert it to gray
	src = imread(Imgname, 0);

	if (!src.data)
	{
		std::cout << "read data error!" << std::endl;
		return -1;
	}
	blur(src, src, Size(3, 3));

	
	//the pram. for findContours,
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	/// Detect edges using canny
	Canny(src, canny_output, 80, 255, 3);
	/// Find contours
	findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
	//CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE

	double maxarea = 0;
	int maxAreaIdx = 0;

	for (int i = 0; i<contours.size(); i++)
	{

		double tmparea = fabs(contourArea(contours[i]));
		if (tmparea>maxarea)
		{
			maxarea = tmparea;
			maxAreaIdx = i;
			continue;
		}
		
		if (tmparea < minarea)
		{
			//刪除面積小於設定值的輪廓
			contours.erase(contours.begin() + i); 
			std::wcout << "delete a small area" << std::endl;
			continue;
		}
		//計算輪廓的直徑寬高
		Rect aRect =boundingRect(contours[i]);
		if ((aRect.width / aRect.height)<whRatio)
		{
			//刪除寬高比例小於設定值的輪廓
			contours.erase(contours.begin() + i); 
			std::wcout << "delete a unnomalRatio area" << std::endl;
			continue;
		}
	}
	/// Draw contours,彩色輪廓
	dst= Mat::zeros(canny_output.size(), CV_8UC3);
	for (int i = 0; i< contours.size(); i++)
	{
		//隨機顏色
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(dst, contours, i, color, 2, 8, hierarchy, 0, Point());
	}
	// Create Window
	char* source_window = "countors";
	namedWindow(source_window, CV_WINDOW_NORMAL);
	imshow(source_window, dst);
	cv:; waitKey(0);
	
	return 0;
}

之後


over!