1. 程式人生 > >opencv(24)---輪廓特徵屬性及應用之最小外接圓

opencv(24)---輪廓特徵屬性及應用之最小外接圓

最小外接圓

函式原型—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部分被複制)