使用OpenCV C++绘制最大轮廓的凸包

Sru*_*ury 1 c++ opencv

int main()
{

vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
int largest_area=0;
int largest_contour_index=0;


OriginalImage = imread("C:\\Data Drive\\opencv Projects\\testwithC++\\Plant001-9\\SideView90\\Day_021.png",CV_LOAD_IMAGE_GRAYSCALE);
BackgroundImage = imread("C:\\Data Drive\\opencv Projects\\testwithC++\\Plant001-9\\SideView90\\Day_001.png",CV_LOAD_IMAGE_GRAYSCALE);

absdiff(OriginalImage,BackgroundImage,GrayImage);
threshold(GrayImage,Binary,80,255,CV_THRESH_BINARY);


namedWindow( "OriginalImage", WINDOW_NORMAL);             
imshow("OriginalImage", OriginalImage);                   


namedWindow( "BackgroundImage", WINDOW_NORMAL);             
imshow("BackgroundImage", BackgroundImage);                 

namedWindow( "GrayImage", WINDOW_NORMAL);               
imshow("GrayImage", GrayImage);                         


namedWindow( "Binary", WINDOW_NORMAL);              
imshow("Binary", Binary);                 

ImageROI = Binary(Rect(300,0,Binary.size().width-600,Binary.size().height));

namedWindow( "ImageROI", WINDOW_NORMAL);                
imshow("ImageROI", ImageROI);                           

dilate(ImageROI,BinaryMorph,Mat(),Point(-1,-1),2);

namedWindow( "BinaryMorph", WINDOW_NORMAL);             
imshow("BinaryMorph", BinaryMorph);                 

findContours(BinaryMorph, contours, hierarchy, RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

for( int i = 0; i< contours.size(); i++ )
 {
    double a=contourArea(contours[i],false);
    if(a>largest_area)
    {
    largest_area=a;
    largest_contour_index=i; 
    }
 }
Contour = Mat(ImageROI.size().width,ImageROI.size().height,CV_8UC1,Scalar::all(0));


drawContours(Contour, contours,largest_contour_index,Scalar(255),CV_FILLED, 8,hierarchy);

vector<Point>hull;

convexHull(contours[largest_contour_index],hull,CV_CLOCKWISE,true);
drawContours(Contour, Mat(hull),largest_contour_index,Scalar(255),3, 8);

namedWindow( "Contour", WINDOW_NORMAL);             
imshow("Contour", Contour);                       

OriginalImage.release();
BackgroundImage.release();
GrayImage.release();
Binary.release();
BinaryMorph.release();
ImageROI.release();
Contour.release();

waitKey(0);                                              
return 0;}
Run Code Online (Sandbox Code Playgroud)

我已经编写了上面的代码,使用microsoft visual studio 2010 express使用OpenCV 2.4.9绘制最大轮廓的凸包.代码符合并执行没有任何错误,成功绘制最大轮廓,但不能显示轮廓.

请注意,到目前为止我使用过C api,现在尝试转换为C++.所以,我是新手,使用openCV和C++.您对使该程序适用于绘制凸包的建议将非常感激.

Mik*_*iki 5

这里的主要问题是你要求drawContours不正确地绘制凸包.

drawContours接受输入点a InputArrayOfArrays,即2维结构,而hull仅是1维.

您可以轻松地动态修复这个创建二维向量,只有一个元素(the hull),作为索引传递0,即您刚刚创建的2D结构的第一个元素:

vector<Point>hull;
convexHull(contours[largest_contour_index], hull, CV_CLOCKWISE, true);
drawContours(Contour, vector<vector<Point>> {hull}, 0, Scalar(128), 3, 8);
Run Code Online (Sandbox Code Playgroud)

或者,如果C++ 11不可用:

vector<Point>hull;
convexHull(contours[largest_contour_index], hull, CV_CLOCKWISE, true);
vector<vector<Point>> tmp;
tmp.push_back(hull);
drawContours(Contour, tmp, 0, Scalar(128), 3, 8);
Run Code Online (Sandbox Code Playgroud)

此外,由于你来自C背景,一些提示:

  • 在需要之前声明变量,而不是在函数的开头.
  • 您不需要手动释放Mats,因为当它们超出范围时,它们会被析构函数自动释放.

也:

  • 如果您不需要能够调整窗口大小,则无需调用,namedWindow因为imshow只需为您创建.(在下面的代码中,我删除了所有调用namedWindow,但我不能再调整它们了)
  • 由于您已经知道矩阵的类型(CV_8UC1),因此您可以使用特化Mat_<Tp>,即Mat1b(又名Mat_<uchar>).这将产生更少的冗长代码,并且还允许您访问类似的元素mat(i,j),而不是mat.at<uchar>(i,j)(这里不需要,但只是一般建议).
  • dilate用空内核是没用的.请定义合适的内核.
  • 你不需要hierarchy这里,所以不要使用它.
  • 使用更新的常量名称:IMREAD_GRAYSCALE代替CV_LOAD_IMAGE_GRAYSCALE,CHAIN_APPROX_SIMPLE而不是CV_CHAIN_APPROX_SIMPLE等...
  • 最好不要在代码中加入魔术值(例如ROI值300,600).
  • 如果使用默认值,则无需指定参数.
  • 带有大写字母的名称通常用于类和结构名称,而不是变量(这在某种程度上是主观的,但我个人认为它使代码更容易阅读).
  • 如果没有检测到任何轮廓,请跳过计算.
  • 如果您使用的是VisualStudio,而不是将所有这些imshow用于调试目的,则可以使用Image Watch.
  • 评论代码!

这里提供了以下提示的工作代码:

#include <opencv2/opencv.hpp>
#include <vector>
#include <string>

using namespace std;
using namespace cv;

int main()
{
    // Load images
    Mat1b originalImage = imread("path_to_original_image", IMREAD_GRAYSCALE);
    Mat1b backgroundImage = imread("path_to_bkg_image", IMREAD_GRAYSCALE);

    // Create binary mask
    Mat1b grayImage;
    absdiff(originalImage, backgroundImage, grayImage);
    Mat1b binary;
    threshold(grayImage, binary, 80, 255, THRESH_BINARY);

    imshow("OriginalImage", originalImage);
    imshow("BackgroundImage", backgroundImage);
    imshow("GrayImage", grayImage);
    imshow("Binary", binary);

    // Take a ROI
    Rect roi(binary.cols / 3, 0, (binary.cols * 2) / 3, binary.rows);
    Mat1b imageROI = binary(roi);

    imshow("ImageROI", imageROI);

    // Apply morphological dilate, 2 times
    Mat1b binaryMorph;
    Mat1b kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    dilate(imageROI, binaryMorph, kernel, Point(-1, -1), 2);

    imshow("BinaryMorph", binaryMorph);

    // Find blob contours
    vector<vector<Point>> contours;
    double largest_area = 0.0;
    int largest_contour_index = 0;
    findContours(binaryMorph.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, roi.tl());

    if (!contours.empty())
    {
        // Find largest contour
        for (size_t i = 0; i < contours.size(); i++)
        {
            double a = contourArea(contours[i], false);
            if (a > largest_area)
            {
                largest_area = a;
                largest_contour_index = i;
            }
        }

        // Draw largest contors
        Mat3b contour(binary.rows, binary.cols, Vec3b(0, 0, 0));
        drawContours(contour, contours, largest_contour_index, Scalar(255, 255, 255), CV_FILLED);

        // Find convex hull of largest contour
        vector<Point>hull;
        convexHull(contours[largest_contour_index], hull, CV_CLOCKWISE, true);

        // Draw the convex hull
        vector<vector<Point>> tmp;
        tmp.push_back(hull);
        drawContours(contour, tmp, 0, Scalar(0, 0, 255), 3);

        imshow("Contour", contour);
    }

    waitKey(0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)