简体   繁体   English

使用findContours时如何避免检测图像帧

[英]How to avoid detecting image frame when using findContours

How can I avoid detecting the frame of an image when using findContours (OpenCV)? 使用findContours (OpenCV)时如何避免检测图像的帧? Until I found OpenCV findContours allways finds two contours for every object and implemented that answer, I was not detecting the internal object consistently (object line was broken into several pieces), but now I detect the image frame every time. 直到我发现OpenCV findContours始终为每个对象找到两个轮廓并实现该答案之前,我一直没有始终如一地检测内部对象(对象线被分成几部分),但是现在我每次都检测到图像帧。

The image is of a quad-rotor UAV seen from the bottom; 该图像是从底部看到的四旋翼无人机的图像; I am using a series of pictures for 'training' object detection. 我正在使用一系列图片来“训练”物体检测。 For that, I need to be sure that I can consistently get the UAV object. 为此,我需要确保我能够始终如一地获得UAV对象。 I guess I could invert the colors, but that seems like a dirty hack. 我想我可以反转颜色,但这似乎是一个肮脏的技巧。

The images are first the input image just before findContours , and the resulting contours. 图像首先是findContours之前的输入图像,以及最终得到的轮廓。 I have seven test images, and all seven has a frame and the UAV. 我有七个测试图像,所有七个都有一个框架和一个无人机。 The hu moments are very similar (as expected). 的时刻非常相似(如预期)。

侵蚀后的二进制图像

二进制图像,检测到轮廓

The code (C++11, and quite messy) for finding the contours/objects and calculating the hu moments: 查找轮廓/对象并计算hu力矩的代码(C ++ 11,相当混乱):

#include <opencv/cv.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <fstream>
#include <string>

using namespace cv;
using namespace std;

#define EROSION_SIZE 1
#define ERODE_CANNY_PREP_ITERATIONS 5

int main() {
    Mat image, canny_output, element, padded;
    RNG rng(12345);
    int numbers[] = {195, 223, 260, 295, 331, 368, 396};
    string pre = "/home/alrekr/Pictures/UAS/hu-images/frame_";
    string middle = "_threshold";
    string post = ".png";
    string filename = "";
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    ofstream fout("/home/alrekr/Pictures/UAS/hu-data/hu.dat");
    element = getStructuringElement(MORPH_RECT,
            Size(2*EROSION_SIZE + 1, 2*EROSION_SIZE+1),
            Point(EROSION_SIZE, EROSION_SIZE));
    namedWindow("Window", CV_WINDOW_AUTOSIZE);
    for (int i : numbers) {
        filename = pre + to_string(i) + middle + post;
        image = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
        erode(image, image, element, Point(-1,-1), ERODE_CANNY_PREP_ITERATIONS);
        imwrite("/home/alrekr/Pictures/UAS/hu-data/prep_for_canny_" + to_string(i) + ".png", image);
    findContours(image, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
        vector<Moments> mu(contours.size());
        if(contours.size() < 1) {
            cout << "No contours found" << endl;
        } else {
            cout << "Contours found: " << contours.size() << endl;
        }
        vector<Point2f> mc(contours.size());
        for(int j = 0; j < (int)contours.size(); j++) {
            mc[j] = Point2f(mu[j].m10/mu[j].m00 , mu[j].m01/mu[j].m00);
        }
        Mat drawing = Mat::zeros(image.size(), CV_8UC3);
        for(int j = 0; j < (int)contours.size(); j++) {
            Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255));
            drawContours(drawing, contours, j, color, 2, 8, hierarchy, 0, Point());
            imshow("Window", drawing);
            waitKey(0);
        }
        imwrite("/home/alrekr/Pictures/UAS/hu-data/cannied_" + to_string(i) + ".png", drawing);
        fout << "Frame " << i << "\n";
        for(int j = 0; j < (int)contours.size(); j++) {
            mu[j] = moments(contours[j]);
            double hu[7];
            HuMoments(mu[j], hu);
            fout << "Object " << to_string(j) << "\n";
            fout << hu[0] << "\n";
            fout << hu[1] << "\n";
            fout << hu[2] << "\n";
            fout << hu[3] << "\n";
            fout << hu[4] << "\n";
            fout << hu[5] << "\n";
            fout << hu[6] << "\n";
        }
    }
    fout.close();
    return 0;
}

The function cv::findContours describes the contour of areas consisting of ones. 函数cv::findContours描述了由一个组成的区域的轮廓。 The areas in which you are interested are black, though. 但是,您感兴趣的区域是黑色的。

So the solution is simple. 因此,解决方案很简单。 Invert the input image before detecting contours: 在检测轮廓之前反转输入图像:

image = 255 - image;

Below is a code example which I derived from your example above: 下面是一个代码示例,该代码示例是从您上面的示例得出的:

#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
#include <string>

#define EROSION_SIZE 1
#define ERODE_CANNY_PREP_ITERATIONS 5

int main( int argc, char ** argv )
{
    // Display the version of the linked OpenCV library.
    std::cout << "Using OpenCV " << CV_VERSION_MAJOR << "." << CV_VERSION_MINOR << ".";
    std::cout << CV_VERSION_REVISION << CV_VERSION_STATUS << std::endl;

    // Load the input file.
    std::string filename = std::string( argv[ 1 ] );
    cv::Mat image = imread( filename, cv::IMREAD_GRAYSCALE );

    // Invert the image so the area of the UAV is filled with 1's. This is necessary since
    // cv::findContours describes the boundary of areas consisting of 1's.
    image = 255 - image;

    // Detect contours.
    std::vector< std::vector< cv::Point> > contours;
    std::vector< cv::Vec4i > hierarchy;

    cv::findContours( image, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE );
    std::cout << "Contours found: " << contours.size() << std::endl;

    // Display and save the results.
    cv::RNG rng( 12345 );
    cv::Mat contourImage = cv::Mat::zeros( image.size(), CV_8UC3);

    for( size_t j = 0; j <  contours.size(); j++ )
    {
        cv::Scalar color( rng.uniform( 0, 255 ), rng.uniform( 0,255 ), rng.uniform( 0, 255 ) );
        cv::drawContours( contourImage, contours, j, color, 2, 8, hierarchy, 0, cv::Point() );
    }

//  cv::imwrite( "contours.png", contourImage );

    cv::imshow( "contours", contourImage );
    cv::waitKey( 0 );

    return 0;
}

The console output is as follows: 控制台输出如下:

$ ./a.out gvlGK.png 
Using OpenCV 3.0.0-beta
Contours found: 1

and the resulting contour image is this: 得到的轮廓图像是这样的:

等高线

Another solution would be :- 另一个解决方案是:

find the bounding Rectangle of the contour 找到轮廓的边界矩形

x,y,w,h = cv2.boundingRect(c)

compare the size of the image with the size of the bounding Rectangle for example 例如,将图像的大小与边界矩形的大小进行比较

cnt_size=w*h
if(abs(cnt_size-img_size<=ERROR_THRESHOLD):
    ##discard this contour 

If you have white background, first inverse it using THRESH_BINARY_INV type and then use contour. 如果您有白色背景,请先使用THRESH_BINARY_INV类型反转背景,然后再使用轮廓。

    image = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
    threshold(image,image,100,255,THRESH_BINARY_INV);
    findContours( image, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE );

This will only return the contour that you need. 这只会返回您需要的轮廓。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM