answerOpenCV輪廓類問題解析

weixin_33958585發表於2018-07-20
contour在opencv中是一個基礎的資料結構,靈活運用的話,作用很大。以contour為關鍵字,在answerOpenCV中能夠發現很多有趣的東西。
508489-20180720231403511-741869872.png

1、無法解決的問題
508489-20180720231403989-630815896.jpg
The problem is that. I just want to take the external contours of the main leaf in the image. Or If it is possible, The image can be cleaned. The second important point is that the process should be standard for all images.
解析:這個提問者希望從上面的葉子圖片,得到葉子的輪廓。但實際上這是不可能完成的任務,這個圖片質量達不到要求,關於這一點,是影像處理的常識。
也就是根本無法輪廓分析,因為沒有穩定的輪廓。

2、如何從影像中獲得完整輪廓

How to find dimensions of an object in the image


這道題厲害了,一看這個需求就是專業的:
I want to find the length of an object in the image (image length not the real physical length). My first idea is was to use boundingRect to find the dimensions, but some of the masks I have split in between them so the boundingRect method fails. Can someone suggest me a robust method to find the length of the object in the given mask

Mask with split
他需要從這個圖中活動輪廓的長度(這個應該是一個腳印),但是因為圖上輪廓可能有多個,所以不知道怎麼辦。
解析:這道題的關鍵,就在於實際上,每張圖的輪廓只有一個。這是重要的先驗條件。那怎麼辦?把識別出來的輪廓連起來呀。
連的方法有多種,我給出兩種比較保險:
1、形態學變化
508489-20180720231404514-200137535.png
    dilate(bw,bw,Mat(11,11,CV_8UC1));
    erode(bw,bw,Mat(11,11,CV_8UC1));
508489-20180720231404751-542016959.png
2、實在距離太遠,靠不上了,直接把中線連起來吧
508489-20180720231404971-287499825.jpg

由於這道題目前還沒有比較好的解決方法,所以我實現了一個,應該是可以用的,這是結果:
508489-20180720231405252-241035686.jpg
網站程式碼也已經提交到網站上了
//程式主要部分
int mainint argcchar** argv )
{
    //讀入影像,轉換為灰度
    Mat img = imread("e:/sandbox/1234.png");
    Mat bw;
    bool dRet;
    cvtColor(imgbwCOLOR_BGR2GRAY);
    //閾值處理
    threshold(bwbw, 150, 255, CV_THRESH_BINARY);
    bitwise_not(bw,bw);
    //形態學變化
    dilate(bw,bw,Mat(11,11,CV_8UC1));
    erode(bw,bw,Mat(11,11,CV_8UC1));
    //尋找輪廓
    vector<vector<Point> > contours;
    vector<Vec4ihierarchy;
    findContours(bwcontourshierarchyCV_RETR_LISTCV_CHAIN_APPROX_NONE);
    /// 計算矩
    vector<Momentsmu(contours.size() );
    forint i = 0; i < contours.size(); i++ )
        mu[i] = momentscontours[i], false ); 
    ///  計算中心矩:
    vector<Point2fmccontours.size() );
    forint i = 0; i < contours.size(); i++ )
        mc[i] = Point2fmu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); 
    //connect all contours into ONE
    for (int i = 0; i < contours.size(); ++i)
    {
        Scalar color = Scalarrng12345.uniform(0, 255), rng12345.uniform(0,255), rng12345.uniform(0,255) );
        drawContoursimgcontoursicolor, 2, 8, hierarchy, 0, Point() );
        circleimgmc[i], 4, color, -1, 8, 0 );
        //connect
        if (i+1 <contours.size())
            line(bw,mc[i],mc[i+1],Scalar(255,255,255));
    }
    contours.clear();
    hierarchy.clear();
    //尋找結果
    findContours(bwcontourshierarchyCV_RETR_LISTCV_CHAIN_APPROX_NONE);
    for (int i = 0;i<contours.size();i++)
    {
        RotatedRect minRect = minAreaRectMat(contours[i]) );
        Point2f rect_points[4];
        minRect.pointsrect_points ); 
        forint j = 0; j < 4; j++ )
            lineimgrect_points[j], rect_points[(j+1)%4],Scalar(255,255,0),2);
        float fshort = std::min(minRect.size.width,minRect.size.height); //short
        float flong = std::max(minRect.size.width,minRect.size.height);  //long
    }
    imshow("img",img);
    waitKey();
    return 0;
}

3、新函式

Orientation of two contours


image description

這個topic希望能夠獲得兩個輪廓之間的角度。並且後期通過旋轉將兩者重合。
I try to calculate the orientation of 2 contours. At the end i want to rotate one contour, so it is in cover with the other one. With my code I get a result, but it isn't that accurate. Also I get the same orientations although the contours is rotated around 90 degrees.

解析:如果是我,一定會直接使用pca分別求出兩個輪廓的角度,然後算差。但是原文中使用了,並且提出了獨特的解決方法。

Shape Distance and Common Interfaces

https://docs.opencv.org/3.0-beta/modules/shape/doc/shape_distances.html#shapecontextdistanceextractor

Shape Distance algorithms in OpenCV are derivated from a common interface that allows you toswitch between them in a practical way for solving the same problem with different methods.Thus, all objects that implement shape distance measures inherit theShapeDistanceExtractor interface.
當然,有了這個函式,做輪廓匹配也是非常方便:
image description
http://answers.opencv.org/question/28489/how-to-compare-two-contours-translated-from-one-another/
 
4、發現opencv的不足

I need a maxEnclosingCircle function


opencv目前是沒有最大內接圓函式的(當然它還沒有很多函式),但是這個只有研究要一定程度的人才會發現。這裡他提問了,我幫助解決下:

508489-20180720231406498-899701832.jpg


#include "stdafx.h"
#include <iostream>
 
using namespace std;
using namespace cv;
 
VP FindBigestContour(Mat src){    
    int imax = 0//代表最大輪廓的序號
    int imaxcontour = -1//代表最大輪廓的大小
    std::vector<std::vector<cv::Point>>contours;    
    findContours(src,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
    for (int i=0;i<contours.size();i++){
        int itmp =  contourArea(contours[i]);//這裡採用的是輪廓大小
        if (imaxcontour < itmp ){
            imax = i;
            imaxcontour = itmp;
        }
    }
    return contours[imax];
}
int main(int argc, char* argv[])
{
    Mat src = imread("e:/template/cloud.png");
    Mat temp;
    cvtColor(src,temp,COLOR_BGR2GRAY);
    threshold(temp,temp,100,255,THRESH_OTSU);
    imshow("src",temp);
    //尋找最大輪廓
    VP VPResult = FindBigestContour(temp);
    //尋找最大內切圓
    int dist = 0;
    int maxdist = 0;
    Point center;
    for(int i=0;i<src.cols;i++)
    {
        for(int j=0;j<src.rows;j++)
        {
            dist = pointPolygonTest(VPResult,cv::Point(i,j),true);
            if(dist>maxdist)
            {
                maxdist=dist;
                center=cv::Point(i,j);
            }
        }
    }
    //繪製結果
    circle(src,center,maxdist,Scalar(0,0,255));
    imshow("dst",src);
    waitKey();
}
    



另過程中,發現了pyimagesearch上的一些不錯文章,感謝這個blog的作者的長期、高質量的付出,向他學習。
1、Removing contours from an image using Python and OpenCV


3、Finding extreme points in contours with OpenCV
https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/

結語:
實際上,最近我正在做關於輪廓的事情,這也是今天我做這個研究的直接原因。

我的問題是:如何識別出輪廓準確的長和寬
比如這張,其中2的這個外輪廓明顯是識別錯誤的,這樣它的長寬也是錯誤的(注意裡面我標紅的1和2)
image description

程式碼:
int mainint argcchar** argv )
{
    //read the image
    Mat img = imread("e:/sandbox/leaf.jpg");
    Mat bw;
    bool dRet;
    //resize
    pyrDown(img,img);
    pyrDown(img,img);
    cvtColor(imgbwCOLOR_BGR2GRAY);
    //morphology operation    
    threshold(bwbw, 150, 255, CV_THRESH_BINARY);
    //bitwise_not(bw,bw);
    //find and draw contours
    vector<vector<Point> > contours;
    vector<Vec4ihierarchy;
    findContours(bwcontourshierarchyCV_RETR_LISTCV_CHAIN_APPROX_NONE);
    for (int i = 0;i<contours.size();i++)
    {
        RotatedRect minRect = minAreaRectMat(contours[i]) );
        Point2f rect_points[4];
        minRect.pointsrect_points ); 
        forint j = 0; j < 4; j++ )
            lineimgrect_points[j], rect_points[(j+1)%4],Scalar(255,255,0),2);
    }
    imshow("img",img);
    waitKey();
    return 0;
}

我們要得到這樣的結果
image description

當然,這個程式碼我已經差不多寫出來了,如何獲得輪廓的真實的長寬?這個問題很實際,opencv沒有實現,目前看來answeropencv也人問?
就是這張圖片?想看看大家的想法。也可以直接在answeropencv上進行討論。
508489-20180720231407486-1026547186.jpg

answerOpencv的討論地址為:



感謝閱讀至此,希望有所幫助。








相關文章