opencv(24)---輪廓特徵屬性及應用之最小外接圓
阿新 • • 發佈:2019-02-06
最小外接圓
函式原型—minEnclosingCircle()
void minEnclosingCircle( InputArray points,
CV_OUT Point2f& center, CV_OUT float& radius );
- points: 輸入的二維點集, 可以填Mat型別或std::vector
- center: Point2f&型別的center, 圓的輸出圓心
- radius: float&型別, 表示圓的輸出半徑
應用例項
程式碼
Mat srcImg = imread("D:\\1\\10.png" );
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
Canny(srcImg, srcImg, 100, 200);
imshow("Canny", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout <<"num="<<contours.size()<<endl;
Point2f center; //定義圓中心座標
float radius; //定義圓半徑
for(int i=0; i<contours.size(); i++) //依次遍歷每個輪廓
{
minEnclosingCircle(Mat(contours[i]), center, radius);
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8);
circle(dstImg, center, radius, Scalar(0 , 255, 0), 2, 8); //繪製第i個輪廓的最小外接圓
}
imshow("dst", dstImg);
waitKey(0);
執行結果
橢圓擬合
函式原型—fitEllipse()
RotatedRect fitEllipse( InputArray points );
- points: 輸入的二維點集, 可以填Mat型別或std::vector
- 返回值: RotatedRect類旋轉矩形物件
應用例項
程式碼
Mat srcImg = imread("D:\\1\\10.png");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
Canny(srcImg, srcImg, 100, 200);
imshow("Canny", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
vector<RotatedRect> box(contours.size());
Point2f rect[4];
for(int i=0; i<contours.size(); i++)
{
box[i] = fitEllipse(Mat(contours[i]));
//ellipse(dstImg, box[i].center, Size(box[i].size.width/2, box[i].size.height/2), box[i].angle, 0, 360, Scalar(0, 255, 0), 2, 8);
ellipse(dstImg, box[i], Scalar(0, 255, 0), 2, 8);
}
imshow("dst", dstImg);
waitKey(0);
執行結果
逼近多邊形曲線
函式原型—approxPolyDP()
void approxPolyDP( InputArray curve,
OutputArray approxCurve,
double epsilon, bool closed );
- curve: 輸入的二維點集, 可以填Mat型別或std::vector
- approxCurve: 多邊形逼近的結果, 其型別和輸入二維點集型別一致
- epsilon: 逼近的精度, 為原始曲線和近似曲線間的最大值
- closed: 如果其為真, 則近似的曲線為封閉曲線, 否則近似的曲線不封閉
應用例項
1. 當影象有缺口時,輪廓逼近後逼近為完整的影象
2. 當查詢外接矩形時,先進行輪廓逼近,再查詢外接矩形
程式碼
Mat srcImg = imread("22.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
Mat dstImg2(srcImg.size(), CV_8UC3, Scalar::all(0));
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
//Canny(srcImg, srcImg, 100, 200);
threshold(srcImg, srcImg, 200, 255, CV_THRESH_BINARY_INV);
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
vector<vector<Point>> contours_poly(contours.size());
for(int i=0; i<contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_poly[i], 15, true);
drawContours(dstImg, contours, i, Scalar(0, 255, 0), 2, 8);
drawContours(dstImg2, contours_poly, i, Scalar(0, 255, 255), 2, 8); //繪製多邊形逼近
}
imshow("dst", dstImg);
imshow("approx", dstImg2);
waitKey(0);
執行結果
srcImg
thresholdImg
輪廓圖
多邊形趨近
計算輪廓面積
函式原型
double contourArea( InputArray contour, bool oriented = false );
- contour: 輸入的二維點集或輪廓, 可以填Mat型別或std::vector
- oriented: 預設值false, 表示返回面積為絕對值, 負責帶符號
返回值: double型別返回輪廓面積
程式碼
Mat srcImg = imread("33.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
Mat dstImg2(srcImg.size(), CV_8UC3, Scalar::all(0));
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
//Canny(srcImg, srcImg, 100, 200);
threshold(srcImg, srcImg, 200, 255, CV_THRESH_BINARY);
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
for(int i=0; i<contours.size(); i++)
{
double area = contourArea(contours[i]);
cout<<"area--"<<i<<"---"<<area<<endl;
if(area>10000) //面積大約1W
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8);
}
imshow("dst", dstImg);
waitKey(0);
計算輪廓長度(周長或者曲線長度)
函式原型—arcLength()
double arcLength( InputArray curve, bool closed );
- curve: 輸入的二維點集, 可以填Mat型別或std::vector
- colsed: 用於指示曲線是否封閉的識別符號, 預設值true, 表示曲線封閉
返回值: double型別返回輪廓長度
注:contourArea()&& arcLength()可用於輪廓刪選
程式碼
Mat srcImg = imread("33.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone();
Mat dstImg2(srcImg.size(), CV_8UC3, Scalar::all(0));
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
//Canny(srcImg, srcImg, 100, 200);
threshold(srcImg, srcImg, 200, 255, CV_THRESH_BINARY);
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
for(int i=0; i<contours.size(); i++)
{
double length = arcLength(contours[i], true);
cout<<"length--"<<i<<"---"<<length<<endl;
if(length>300) //輪廓曲線長度大於300
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8);
}
imshow("dst", dstImg);
waitKey(0);
利用mask提取不規則輪廓
應用例項
程式碼
Mat srcImg = imread("D:\\1\\220.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone(); //原圖備份
Mat tempImg = srcImg.clone(); //原圖備份
Mat tempImg2(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定義全黑的和原圖一樣大小的影象
Mat draw(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定義全黑的和原圖一樣大小的影象
Mat tempImg3(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定義全黑的和原圖一樣大小的影象
GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
cvtColor(srcImg, srcImg, CV_BGR2GRAY);
threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY); //二值化
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
cout<<"num="<<contours.size()<<endl;
while(1)
{
for(int i=0; i<contours.size(); i++)
{
tempImg2.copyTo(draw); //每次進入將draw清空為全黑
tempImg2 .copyTo(tempImg3); //每次進入將tempImg3清空為全黑
//drawContours(dstImg, contours, i, Scalar(0, 255, 0), 5, 8);
drawContours(draw, contours, i, Scalar(255, 255, 255), -1, 8);
Mat mask; //定義掩碼
cvtColor(draw, mask, CV_BGR2GRAY);
tempImg.copyTo(tempImg3, mask); //將tempImg 複製到tempImg3(只有mask部分被複制)
imshow("draw", draw);
imshow("result", tempImg3);
char key = waitKey();
if(key==27) //按下Esc鍵跳出for迴圈
break;
}
break;
}
執行結果
srcImg
threshold
draw
result
知識點講解
掩碼
參考以前的opencv學習之掩碼
dstImg,tempImg都是對原圖的備份;tempImg2,draw,tempImg3都是全黑的影象
Mat dstImg = srcImg.clone(); //原圖備份
Mat tempImg = srcImg.clone(); //原圖備份
Mat tempImg2(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定義全黑的和原圖一樣大小的影象
Mat draw(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定義全黑的和原圖一樣大小的影象
Mat tempImg3(srcImg.rows, srcImg.cols, CV_8UC3, Scalar::all(0)); //定義全黑的和原圖一樣大小的影象
每次繪製都將draw和tempImg3清空為全黑。將輪廓(內部填充為白色)繪製到draw影象,將draw影象轉為灰度的掩碼影象mask,然後進行掩碼的複製操作
tempImg2.copyTo(draw); //每次進入將draw清空為全黑
tempImg2 .copyTo(tempImg3); //每次進入將tempImg3清空為全黑
//drawContours(dstImg, contours, i, Scalar(0, 255, 0), 5, 8);
drawContours(draw, contours, i, Scalar(255, 255, 255), -1, 8);
Mat mask; //定義掩碼
cvtColor(draw, mask, CV_BGR2GRAY);
tempImg.copyTo(tempImg3, mask); //將tempImg 複製到tempImg3(只有mask部分被複制)