1.29【OpenCV圖像處理】輪廓邊界框

RDP演算法求輪廓周圍近似多邊形approxPolyDP()、得到矩形boundingRect()、圓形minEnclosingCircle()、 橢圓fitEllipse()、 旋轉矩形minAreaRect()

1.29.1 在輪廓周圍繪製矩形框和圓形框

概念:計算完全包圍已有輪廓的最小圓和矩形框。輪廓有很多點,基於輪廓直接繪製矩形和圓形有些困難,創建包圍輪廓的矩形和圓形邊界框就是由多點的多邊形變成輪廓點數比較少的多邊形,並且形狀基本不變。

RDP演算法:(Douglas–Peucker algorithm道格拉斯-普克演算法,亦稱為拉默-道格拉斯-普克演算法、迭代適應點演算法、分裂與合併演算法)是將曲線近似表示為一系列點,並減少點的數量的一種演算法。

目的:減少多邊形輪廓點數,以指定的精度逼近多邊形曲線。

經典的Douglas-Peucker演算法步驟如下(如下圖):(OpenCV已封裝好)

1)在曲線首尾兩點A,B之間連接一條直線AB,該直線為曲線的弦;

2)得到曲線上離該直線段距離最大的點C,計算其與AB的距離d;

3)比較該距離與預先給定的閾值threshold的大小,如果小於threshold,則該直線段AB就被作為曲線的近似,該段曲線處理完畢。

4)如果距離大於閾值,則用C將曲線分為兩段AC和BC,並再分別對兩段取信進行1~3的處理。

5)當所有曲線都處理完畢時,依次連接各個分割點形成的折線,即可以作為曲線的近似。

1.29.2 相關API

(1)RDP演算法求輪廓周圍近似多邊形

approxPolyDP(

InputArray curve, //輸入輪廓點

OutputArray approxCurve, //輸出近似結果

double epsilon, //近似精度參數,原始曲線與其近似之間的最大距離d。小於這個距離取其為近似線,大於則再次分割。

bool closed //true則近似曲線封閉(它的第一個頂點和最後一個頂點是連通的),否則false它就不封閉。

)

vector<vector<Point>> contours_ploy(contours.size()); //定義近似結果,要初始化(contours.size())napproxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true); //RDP演算法找輪廓周圍多邊形:輸入輪廓點,輸出近似多邊形,最小距離,true近似曲線封閉n

(2)得到輪廓周圍最小矩形

boundingRect(InputArray points); //得到輪廓周圍最小矩形的左上角點坐標和右下角點坐標,繪製一個矩形

vector<Rect> ploy_rects(contours.size()); //定義矩形nploy_rects[i] = boundingRect(contours_ploy[i]); //得到最小矩形(左上角點和右下角點坐標)n

(3)得到輪廓周圍旋轉矩形

minAreaRect(InputArray points); //得到一個旋轉的矩形,返迴旋轉矩形

vector<RotatedRect> myellipse(contours.size()); //定義橢圓nminRects[i] = minAreaRect(contours_ploy[i]);//得到一個旋轉矩形n

(4)得到輪廓周圍圓形

minEnclosingCircle(

InputArray points, //得到最小圓形

Point2f& center, // 圓心位置

float& radius // 圓的半徑

)

minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]); //得到最小圓形:近似多邊形,圓心位置,半徑nvector<Point2f> ccs(contours.size()); //定義圓心位置nvector<float> radius(contours.size()); //定義圓半徑n

(5)得到輪廓周圍橢圓

fitEllipse(InputArray points); //得到最小橢圓,橢圓有方向。

vector<RotatedRect> myellipse(contours.size()); //定義橢圓nmyellipse[i] = fitEllipse(contours_ploy[i]); //得到最小橢圓n

實現步驟:

1)轉灰度並模糊取雜訊 - cvtColor()、blur()

cvtColor(src, gray_src, CV_BGR2GRAY); //轉灰度nblur(gray_src, gray_src, Size(3, 3), Point(-1, -1)); // 濾波n

2)首先將圖像變為二值圖像 - threshold()

/*二值化*/nMat binary_output;nthreshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);n

3)尋找圖像輪廓 - findContours()

/*尋找輪廓*/nvector<vector<Point>> contours;nvector<Vec4i> hierachy;nfindContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));n

4)RDP演算法求輪廓周圍近似多邊形,得到最小矩形和圓形 - approxPolyDP()、boundingRect()、minEnclosingCircle()、 fitEllipse()、 minAreaRect()

/*RDP演算法求輪廓周圍近似多邊形,得到最小矩形和圓形*/nvector<vector<Point>> contours_ploy(contours.size()); //定義近似結果,要初始化(contours.size())nvector<Rect> ploy_rects(contours.size()); //定義矩形nvector<Point2f> ccs(contours.size()); //定義圓心位置nvector<float> radius(contours.size()); //定義圓半徑nvector<RotatedRect> minRects(contours.size()); //定義旋轉矩形nvector<RotatedRect> myellipse(contours.size()); //定義橢圓nfor (size_t i = 0; i < contours.size(); i++) {nnapproxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true); //RDP演算法找輪廓周圍多邊形:輸入輪廓點,輸出近似多邊形,最小距離,true近似曲線封閉nn ploy_rects[i] = boundingRect(contours_ploy[i]); //得到最小矩形(左上角點和右下角點坐標)nminEnclosingCircle(contours_ploy[i], ccs[i], radius[i]); //得到最小圓形:近似多邊形,圓心位置,半徑nif (contours_ploy[i].size() > 5) { //要求多邊形點數大於5個才行n myellipse[i] = fitEllipse(contours_ploy[i]); //得到最小橢圓n minRects[i] = minAreaRect(contours_ploy[i]);//得到一個旋轉矩形n }n}n

5)繪製矩形與橢圓 - rectangle()、circle()、ellipse()、line()

/*繪製矩形和圓形*/nsrc.copyTo(drawImg); //將矩形和圓形畫在原圖上n// drawImg = Mat::zeros(src.size(), src.type()); //將矩形和圓形畫在黑背景圖上nPoint2f pts[4];nfor (size_t t = 0; t < contours.size(); t++) {nScalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));nif (contours_ploy[t].size() > 5) { //要求多邊形點數大於5個才行nrectangle(drawImg, ploy_rects[t], color, 2, 8); //畫矩形ncircle(drawImg, ccs[t], radius[t], color, 2, 8); //畫圓nellipse(drawImg, myellipse[t], color, 1, 8); //畫橢圓 nminRects[t].points(pts); //畫旋轉矩形nfor (int r = 0; r < 4; r++) {n line(drawImg, pts[r], pts[(r + 1) % 4], color, 1, 8);//連線4個點(0-1,1-2,3-4,4-0)n }n }n}n


完整程序:

/*1.29 輪廓邊界框*/n#include <opencv2/opencv.hpp>n#include <iostream>n#include <math.h>nnusing namespace std;nusing namespace cv;nMat src, gray_src, drawImg;nint threshold_v = 170;nint threshold_max = 255;nconst char* output_win = "rectangle-demo";nRNG rng(12345);nvoid Contours_Callback(int, void*);nnint main(int argc, char** argv) {n src = imread("E:/OpenCV/testimage/globe2.jpg");nif (!src.data) {n printf("could not load image...n");nreturn -1;n }nn cvtColor(src, gray_src, CV_BGR2GRAY); //轉灰度n blur(gray_src, gray_src, Size(3, 3), Point(-1, -1)); // 濾波nnconst char* source_win = "input image";n namedWindow(source_win, CV_WINDOW_AUTOSIZE);n namedWindow(output_win, CV_WINDOW_AUTOSIZE);n imshow(source_win, src);nn createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback);n Contours_Callback(0, 0);nn waitKey(0);nreturn 0;n}nnvoid Contours_Callback(int, void*) {n/*二值化*/nMat binary_output;n threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);n imshow("binary image", binary_output);nn/*尋找輪廓*/nvector<vector<Point>> contours;nvector<Vec4i> hierachy;n findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));nn/*RDP演算法求輪廓周圍近似多邊形,得到最小矩形和圓形*/nvector<vector<Point>> contours_ploy(contours.size()); //定義近似結果,要初始化(contours.size())nvector<Rect> ploy_rects(contours.size()); //定義矩形nvector<Point2f> ccs(contours.size()); //定義圓心位置nvector<float> radius(contours.size()); //定義圓半徑nvector<RotatedRect> minRects(contours.size()); //定義旋轉矩形nvector<RotatedRect> myellipse(contours.size()); //定義橢圓nfor (size_t i = 0; i < contours.size(); i++) {nn approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true); //RDP演算法找輪廓周圍多邊形:輸入輪廓點,輸出近似多邊形,最小距離,true近似曲線封閉nn ploy_rects[i] = boundingRect(contours_ploy[i]); //得到最小矩形(左上角點和右下角點坐標)n minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]); //得到最小圓形:近似多邊形,圓心位置,半徑nif (contours_ploy[i].size() > 5) { //要求多邊形點數大於5個才行n myellipse[i] = fitEllipse(contours_ploy[i]); //得到最小橢圓n minRects[i] = minAreaRect(contours_ploy[i]);//得到一個旋轉矩形n }n }nn/*繪製矩形和圓形*/n src.copyTo(drawImg); //將矩形和圓形畫在原圖上n// drawImg = Mat::zeros(src.size(), src.type()); //將矩形和圓形畫在黑背景圖上nPoint2f pts[4];nfor (size_t t = 0; t < contours.size(); t++) {nScalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));nif (contours_ploy[t].size() > 5) { //要求多邊形點數大於5個才行n rectangle(drawImg, ploy_rects[t], color, 2, 8); //畫矩形n circle(drawImg, ccs[t], radius[t], color, 2, 8); //畫圓n ellipse(drawImg, myellipse[t], color, 1, 8); //畫橢圓 n minRects[t].points(pts); //畫旋轉矩形nfor (int r = 0; r < 4; r++) {n line(drawImg, pts[r], pts[(r + 1) % 4], color, 1, 8); //連線4個點(0-1,1-2,3-4,4-0)n }n }n }nn imshow(output_win, drawImg);nreturn;n}n

運行結果:

推薦閱讀:

[171118] PyQt5 滑動條控制 Canny 邊緣閾值並繪製 OpenCV 圖像
數字圖像處理專業如何快速入門?謝謝。
斯坦福大學2017年春季_基於卷積神經網路的視覺識別課程視頻教程及ppt分享

TAG:OpenCV | 图像处理 |