opencv學習筆記28-輪廓周圍繪製矩形框和圓形框

只用來記錄學習筆記

在這裏插入圖片描述

Douglas-Peucker算法:

  1. 在曲線首尾兩點間虛連一條直線,求出其餘各點到該直線的距離,如右圖(1)。
  2. 選其最大者與閾值相比較,若大於閾值,則離該直線距離最大的點保留,否則將直線兩端點間各點全部捨去,如右圖(2),第4點保留。
  3. 依據所保留的點,將已知曲線分成兩部分處理,重複第1、2步操作,迭代操作,即仍選距離最大者與閾值比較,依次取捨,直到無點可捨去,最後得到滿足給定精度限差的曲線點座標,如圖(3)、(4)依次保留第6點、第7點,捨去其他點,即完成線的化簡。

approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)

代碼:(函數的解釋全部寫在註釋中了)

定義:

Mat src, gray_src, temp, dst;
const char* input_title = "input";
const char* output_title = "output";
const char* trackbar_title = "output";
int threshold_value = 170;
int threshold_max = 255;
RNG rng(12345);
void Contours_Callback(int, void*);

主函數:

	int main(int argc, char** argv) {
	src = imread("C:/Users/Administrator/Pictures/p234.jpg");
	if (src.empty()) {
		cout << "no image" << endl;
		return -1;
	}
	namedWindow(input_title, CV_WINDOW_AUTOSIZE);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(input_title, src);

	cvtColor(src, gray_src, CV_BGR2GRAY); //轉灰度圖像
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1)); //模糊

	createTrackbar(trackbar_title, output_title, &threshold_value, threshold_max, Contours_Callback);//滑塊改變閾值
	Contours_Callback(0, 0);

	waitKey(0);
	return 0;
}

方法:

void Contours_Callback(int, void*) {
	Mat binary_output;
	vector<vector<Point>> contours;  //輪廓集合,每個輪廓用點的集合表示
	vector<Vec4i> hierachy;

	threshold(gray_src, binary_output, threshold_value, threshold_max, THRESH_BINARY);//閾值操作
	findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));//輪廓發現

	vector<vector<Point>> contours_ploy(contours.size()); //折線結合,每個折線用點集表示
	vector<Rect> ploy_rects(contours.size()); //正矩形集合
	vector<Point2f> ccs(contours.size()); //圓心
	vector<float> radius(contours.size()); //半徑
	vector<RotatedRect> minRects(contours.size());  //RotatedRect:包含中心點座標,以及矩形的長度和寬度還有矩形的偏轉角度
	vector<RotatedRect> myellipse(contours.size()); //RotatedRect:包含中心點座標,以及矩形的長度和寬度還有矩形的偏轉角度
	
	for (size_t i = 0; i < contours.size(); i++) { //循環所有輪廓
		approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);  //多邊擬合函數 ,目的是減少
		//Mat(contours[i]):輸入曲線,數據類型可以爲vector<Point>
		//contours_ploy[i]:輸出折線,數據類型可以爲vector<Point>
		//3:判斷點到相對應的line segment 的距離的閾值。(距離大於此閾值則保留,小於此閾值則捨棄,epsilon越小,折線的形狀越“接近”曲線。)
		//true:曲線是否閉合的標誌位
		ploy_rects[i]=boundingRect(contours_ploy[i]);//計算輪廓的垂直邊界最小矩形,矩形是與圖像上下邊界平行的
		minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]); //尋找最小包圍圓形
		//contours_ploy[i]:輸入折線
		//ccs[i]:圓心
		//radius[i]:半徑

		if (contours_ploy[i].size() > 5) { //只有大於等於6條線的才能擬合成橢圓
			myellipse[i] = fitEllipse(contours_ploy[i]); //二維點集的橢圓擬合,用橢圓將二維點包含起來
			minRects[i] = minAreaRect(contours_ploy[i]);//最小區域邊界斜矩形
		}	
	}

	//繪製
	src.copyTo(dst);
	Point2f pts[4];
	for (size_t t = 0; t < contours.size(); t++) {//循環所有輪廓
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); 
		//rectangle(dst, ploy_rects[t], color, 1, 8); //繪製正矩形框
		//circle(dst, ccs[t], radius[t], color, 1, 8);//繪製最小包圍圓

		ellipse(dst, myellipse[t], color, 1, 8); //繪製橢圓
		minRects[t].points(pts);
		for (int r = 0; r < 4; r++) {//繪製斜矩形
			line(dst, pts[r], pts[(r + 1) % 4], color, 1, 8);
		}
	}
	imshow(output_title, dst);
}

效果圖:(繪製正矩形和最小包圍圓的代碼已經註釋掉了)
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章