Java 重叠形状识别(OpenCV)

Java 重叠形状识别(OpenCV),java,opencv,contour,shapes,image-recognition,Java,Opencv,Contour,Shapes,Image Recognition,我有一张包含一些形状的简单图像:一些矩形和一些椭圆,总数为4或5。形状可以旋转、缩放和重叠。有一个示例输入: 我的任务是检测所有这些图形,并准备一些关于它们的信息:大小、位置、旋转等。在我看来,核心问题是形状可以相互重叠。我试图搜索有关此类问题的一些信息,发现OpenCV库非常有用 OpenCV能够检测轮廓,然后尝试将椭圆或矩形拟合到这些轮廓。问题是当形状重叠时,轮廓会混淆 我考虑以下算法:检测所有特征点:并在其上放置白点。我得到了这样的东西,每个图形都被分成不同的部分: 然后,我可以尝试使用一

我有一张包含一些形状的简单图像:一些矩形和一些椭圆,总数为4或5。形状可以旋转、缩放和重叠。有一个示例输入: 我的任务是检测所有这些图形,并准备一些关于它们的信息:大小、位置、旋转等。在我看来,核心问题是形状可以相互重叠。我试图搜索有关此类问题的一些信息,发现OpenCV库非常有用

OpenCV能够检测轮廓,然后尝试将椭圆或矩形拟合到这些轮廓。问题是当形状重叠时,轮廓会混淆

我考虑以下算法:检测所有特征点:并在其上放置白点。我得到了这样的东西,每个图形都被分成不同的部分: 然后,我可以尝试使用一些信息链接这些部分,例如复杂度值(我将曲线approxPolyDP拟合到轮廓,并读取它有多少部分)。但这开始变得非常困难。另一个想法是尝试所有的排列方式,将轮廓连接起来,并尝试将图形与之匹配。最好的编译将被输出


你知道如何创建简单而优雅的解决方案吗?

模糊图像有助于找到代码中所示的交点

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;

int main( int argc, char** argv )
{
    Mat src = imread( argv[1] );
    Mat gray, blurred;
    cvtColor( src, gray, COLOR_BGR2GRAY );
    threshold( gray, gray, 127, 255, THRESH_BINARY );
    GaussianBlur( gray, blurred, Size(), 9 );
    threshold( blurred, blurred, 200, 255, THRESH_BINARY_INV );
    gray.setTo( 255, blurred );
    imshow("result",gray);
    waitKey();

    return 0;
}
结果图像:

步骤2

简单地说,借用了

#包括“opencv2/imgproc.hpp”
#包括“opencv2/highgui.hpp”
使用名称空间cv;
使用名称空间std;
int main(int argc,字符**argv)
{
Mat src=imread(argv[1]);
席灰色,模糊;
CVT颜色(src、灰色、灰色);
阈值(灰色、灰色、127、255、阈值二元);
高斯模糊(灰色,模糊,大小(),5);
阈值(模糊,模糊,180,255,阈值二值化);
灰色。设置为(255,模糊);
imshow(“步骤1的结果”,灰色);
矢量等值线;
///寻找轮廓
findContours(gray.clone()、等高线、重建树、链近似简单);
///找到每个轮廓的旋转矩形和椭圆
向量minRect(contours.size());
向量minEllipse(contours.size());
对于(size_t i=0;i5)
{
minEllipse[i]=fitEllipse(Mat(等高线[i]);
}
}
///绘制轮廓+旋转矩形+椭圆
对于(size_t i=0;i
您可以在其他图像中获得以下结果图像。我希望你们能解决最后一步。

如何找到连接点?我认为下面建议的模糊并不是基于某种数学性质,它只是一种特别的尝试和观察——如果你能找到连接点,那么它就变成了一个图形问题;每个传入段都将有一个可能的输出段,并基于您可以匹配的曲率。但是如何检测交叉点呢?我尝试了许多用于查找角点的方法,发现“goodFeaturesToTrack”在这种情况下效果最好。缺点是它不仅检测交叉点,还检测矩形的核心点。在我看来,只检测交叉点的能力只会简化算法。如果它检测到矩形角点,它同样好——你必须将一个线段与一个线段配对——如果goodFeaturesToTrack准确地找到所有高亮显示的点,那么这就是你需要的。是的,没错,我正在考虑创建一个图形。当我有一个只有两条边的顶点时,我可以将它们作为矩形的一部分连接起来。更有趣的是,我有更多边的顶点,如4(简单连接)或3(两个矩形连接的特殊情况)。谢谢,我将尝试分析您的解决方案,与我的想法相反,它似乎非常简单和直接。我希望它会有所帮助。您可以尝试更改
GaussianBlur
threshold
的参数(请参见我在第一个和第二个代码中如何更改)
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    Mat src = imread( argv[1] );
    Mat gray, blurred;
    cvtColor( src, gray, COLOR_BGR2GRAY );
    threshold( gray, gray, 127, 255, THRESH_BINARY );
    GaussianBlur( gray, blurred, Size(), 5 );
    threshold( blurred, blurred, 180, 255, THRESH_BINARY_INV );
    gray.setTo( 255, blurred );
    imshow("result of step 1",gray);

    vector<vector<Point> > contours;

    /// Find contours
    findContours( gray.clone(), contours, RETR_TREE, CHAIN_APPROX_SIMPLE );

    /// Find the rotated rectangles and ellipses for each contour
    vector<RotatedRect> minRect( contours.size() );
    vector<RotatedRect> minEllipse( contours.size() );

    for( size_t i = 0; i < contours.size(); i++ )
    {
        minRect[i] = minAreaRect( Mat(contours[i]) );
        if( contours[i].size() > 5 )
        {
            minEllipse[i] = fitEllipse( Mat(contours[i]) );
        }
    }

    /// Draw contours + rotated rects + ellipses
    for( size_t i = 0; i< contours.size(); i++ )
    {
        Mat drawing = src.clone();
        // contour
        //drawContours( drawing, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
        // ellipse
        ellipse( drawing, minEllipse[i], Scalar( 0, 0, 255 ), 2 );
        // rotated rectangle
        Point2f rect_points[4];
        minRect[i].points( rect_points );
        for( int j = 0; j < 4; j++ )
            line( drawing, rect_points[j], rect_points[(j+1)%4], Scalar( 0, 255, 0 ), 2 );
        /// Show in a window
        imshow( "results of step 2", drawing );
        waitKey();
    }

    return 0;
}