【问题标题】:How to identify polygon using opencv or javacv?如何使用 opencv 或 javacv 识别多边形?
【发布时间】:2012-06-28 07:56:43
【问题描述】:

我正在做一个项目,该项目使用图像处理技术来识别不同的对象及其长度。我浏览了 javaCV 和 OpenCV 中的许多示例。但不幸的是,我无法识别多边形的 T 形。

我尝试使用以下矩形识别方法,但失败了。

public static CvSeq findSquares( final IplImage src,  CvMemStorage storage)
{

CvSeq squares = new CvContour();
squares = cvCreateSeq(0, sizeof(CvContour.class), sizeof(CvSeq.class), storage);

IplImage pyr = null, timg = null, gray = null, tgray;
timg = cvCloneImage(src);

CvSize sz = cvSize(src.width() & -2, src.height() & -2);
tgray = cvCreateImage(sz, src.depth(), 1);
gray = cvCreateImage(sz, src.depth(), 1);
pyr = cvCreateImage(cvSize(sz.width()/2, sz.height()/2), src.depth(), src.nChannels());

// down-scale and upscale the image to filter out the noise
cvPyrDown(timg, pyr, CV_GAUSSIAN_5x5);
cvPyrUp(pyr, timg, CV_GAUSSIAN_5x5);
cvSaveImage("ha.jpg",   timg);
CvSeq contours = new CvContour();
// request closing of the application when the image window is closed
// show image on window
// find squares in every color plane of the image
for( int c = 0; c < 3; c++ )
{
    IplImage channels[] = {cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1), cvCreateImage(sz, 8, 1)};
    channels[c] = cvCreateImage(sz, 8, 1);
    if(src.nChannels() > 1){
        cvSplit(timg, channels[0], channels[1], channels[2], null);
    }else{
        tgray = cvCloneImage(timg);
    }
    tgray = channels[c];
    // try several threshold levels
    for( int l = 0; l < N; l++ )
    {
    //             hack: use Canny instead of zero threshold level.
    //             Canny helps to catch squares with gradient shading
        if( l == 0 )
        {
    //                apply Canny. Take the upper threshold from slider
    //                and set the lower to 0 (which forces edges merging)
                      cvCanny(tgray, gray, 0, thresh, 5);
    //                 dilate canny output to remove potential
    //                // holes between edge segments
                      cvDilate(gray, gray, null, 1);
                 }
          else
        {
    //                apply threshold if l!=0:
                      cvThreshold(tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY);
          }
        //            find contours and store them all as a list
                      cvFindContours(gray, storage, contours, sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

                      CvSeq approx;

        //            test each contour
                      while (contours != null && !contours.isNull()) {
                      if (contours.elem_size() > 0) {
                           approx = cvApproxPoly(contours, Loader.sizeof(CvContour.class),storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0);
                    if( approx.total() == 4
                            &&
                            Math.abs(cvContourArea(approx, CV_WHOLE_SEQ, 0)) > 1000 &&
                        cvCheckContourConvexity(approx) != 0
                        ){
                        double maxCosine = 0;
                        //
                        for( int j = 2; j < 5; j++ )
                        {
            // find the maximum cosine of the angle between joint edges
                                                double cosine = Math.abs(angle(new CvPoint(cvGetSeqElem(approx, j%4)), new CvPoint(cvGetSeqElem(approx, j-2)), new CvPoint(cvGetSeqElem(approx, j-1))));
                                                maxCosine = Math.max(maxCosine, cosine);
                         }
                         if( maxCosine < 0.2 ){
                                 CvRect x=cvBoundingRect(approx, l);
                                 if((x.width()*x.height())<5000 ){
                                     System.out.println("Width : "+x.width()+" Height : "+x.height());
                             cvSeqPush(squares, approx);
                                     //System.out.println(x);
                                 }
                         }
                    }
                }
                contours = contours.h_next();
            }
        contours = new CvContour();
    }
}
return squares;
}

请帮助我修改此方法以从图像中识别 T 形状。输入图像是这样的。

这是我要识别的T形

【问题讨论】:

  • 您需要识别这张图片的哪一部分?
  • 我已经更新了这个问题,现在它包含了有关它的详细信息。

标签: java c++ opencv javacv


【解决方案1】:

我找到了解决您问题的方法:

  • 将图像转换为灰度:

  • 做一个阈值(转换为1bit图像):

  • 找到轮廓并填充它们:

提示: 在 OpenCV 中填充轮廓使用 -1 作为 thickness 函数中的 thickness 参数。

  • 使用相同的内核进行膨胀和腐蚀:

就是这样!在此之后,您在图像上找到您的T形身材不是问题!

很遗憾我不知道JavaCV,但我可以与你分享c++代码:

Mat src = imread("in.jpg"), gray;

cvtColor(src, gray, CV_BGR2GRAY);

threshold(gray, gray, 230, 255, THRESH_BINARY_INV);

vector<Vec4i> hierarchy;
vector<vector<Point> > contours;

findContours(gray, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

gray = Scalar::all(255);
for (size_t i=0; i<contours.size(); i++)
{
    drawContours(gray, contours, i, Scalar(0), -1);
}

Mat element = getStructuringElement(MORPH_RECT, Size(2, 2), Point(1, 1));
dilate(gray, gray, element);
erode(gray, gray, element);

imshow("window", gray);

提示: 如果您愿意,可以将此代码转换为 JavaCV。为此,请阅读 this tutorial

【讨论】:

  • 那么我怎样才能获得这种多边形的长度呢?
  • @LBNCons 首先你必须识别这个多边形。有很多方法可以做到这一点。检测到多边形后,不仅仅使用approxPolyDP 函数。
  • @Astor 我尝试了 approxPolyDP mrthod 它返回一个 CvSeq。那么我怎样才能提取边缘的坐标呢?你能解释一下吗?我已经尝试使用 cvCvtSeqToArray() 方法以及关于此的问题。 stackoverflow.com/questions/11464759/…
【解决方案2】:

你可能会更好地找到轮廓并使用CvApproxPoly()。您可以找到一个很好的示例,说明如何使用此功能查找矩形here 并对其进行调整以找到您的 T 形。此示例使用 OpenCV 创建并用 c++ 编写。

遍历序列中的所有点:

for (int i = 0; i < cornerPoints->total; i++) {
 CvPoint *cornerPoints = (CvPoint*) cvGetSeqElem(cornerPoints, i);
}

【讨论】:

  • 我通过了 CvApproxPoly() 方法,但它也返回了一个 CvSeq。但我必须提取多边形上边缘的坐标
  • 如果你想用轮廓上的所有点创建一个 CvPoint,你可以使用 for 循环遍历所有点。我将此添加到我的答案中。
【解决方案3】:

听起来像家庭作业

@Astor 带来的预处理肯定是有帮助的。 但我还是觉得这种形状识别与图像处理密切相关:形态学

您可以准备一个 T 形模板然后“卷积”吗?具有预处理结果的模板。不记得更多细节了,只是调查一下 TAG Morphology and Convolution

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-06
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多