【问题标题】:Picking contours using the mouse?使用鼠标选择轮廓?
【发布时间】:2013-05-22 06:19:27
【问题描述】:

我的项目对给定窗口的客户区进行位图快照,并将此数据转换为IplImage 实例。然后在灰度转换、脱粒等之后,围绕任何超过给定最小尺寸(面积)的轮廓绘制边界框。
然后结果显示在cvNamedWindow

我现在需要做的就是允许用户在这些矩形内单击以有效地“选择”这个轮廓,以便应用程序可以将子矩形提取为新图像并将其保存到磁盘。

如何在 C++ 中使用 OpenCV 来实现这一点?

【问题讨论】:

  • 你为什么使用 IplImage (C) 而不是 cv::Mat (C++)?
  • @hetepeperfan 好吧,老实说,我对 C 和 C++ 实现(和版本)之间的差异以及几个代码示例似乎如何引用我的编译器未能引用的 OpenCV 函数有点困惑查找,以及这些函数本身是否是严格的 C 或 C++ 实现以及它们属于哪个版本的 OpenCV。所以至少在我学习 OpenCV 的时候,我只是在使用“什么对我有用”......而且在大多数情况下,这包括使用 IplImage 而不是 cv::Mat,即使我已经读过您不应该将实现混合在一起。
  • @hetepeperfan 简而言之,我发现 OpenCV 的文档非常模糊。
  • 不幸的是,确实有很多示例仍然使用旧的 IplImage 实现。要学习 OpenCV 的基础知识,这并不容易,而且文档确实没有帮助。 Gary Bradski 写的 O' Reilly 书是一本不错的入门书,但本书也使用了旧的 c 实现。你可以在这里找到至少一些解释(和其他教程):aishack.in/2010/07/opencvs-c-interface
  • 我必须同意,这有点可惜,最近没有一本很好地描述 C++ api 的书(据我所知)。但是 c++ 函数很好地映射到 c 函数,但使用 cv::Mat 而不是 CvMat 或 IplImage。但正如您在掌握了窍门后接受的答案中所指出的那样,这可能是一种祝福。

标签: c++ opencv mouse contour


【解决方案1】:

如果您存储边界框,您可以在鼠标事件处理程序中的 for 循环中检查一个框是否被单击以及哪个框被单击。创建鼠标事件的代码:

cvNamedWindow("MyWindow", CV_WINDOW_NORMAL);
cvSetMouseCallback("MyWindow", mouseEvent, 0);
imshow("MyWindow", image);

void mouseEvent(int evt, int x, int y, int flags, void *param) {
    if (evt == CV_EVENT_LBUTTONDOWN) {
        printf("%d %d\n", x, y);
    }
}

您可能会发现自己如何检查这些坐标是否在边界框内。我还建议使用 cmets 中所述的 C++ API,因为一旦掌握了它,它会容易得多。

【讨论】:

    【解决方案2】:

    如果其他人对如何实际提取所选图像感兴趣,
    我是这样做的:

    inline
    IplImage* getSubImage(IplImage *image, CvRect region)
    {
        cvSetImageROI(image, region);
        IplImage *imgRet = cvCreateImage( cvSize(region.width, region.height), image->depth, image->nChannels );
        cvCopy(image, imgRet);
        cvResetImageROI(image);
        return imgRet;
    }
    
    inline
    bool pointInRect(const int x, const int y, const CvRect& r)
    {
        return (
            (x > r.x) && (x < (r.x + r.width)) &&
            (y > r.y) && (y < (r.y + r.height))
        );
    }
    
    void onMouseEvent(int evt, int x, int y, int flags, void *param)
    {
        if (evt == CV_EVENT_LBUTTONDOWN) {
            // boundingBoxes is declared as a vector of CvRects and
            //    filled in the main loop using cvBoundingRect(contour)
            for(UINT i = 0; i < boundingBoxes.size(); i++)
            {
                CvRect rect = boundingBoxes[i].rect;
                if( pointInRect(x, y, rect) )
                {
                    IplImage* img = getSubImage(imgSource, rect);
                    // Do whatever you want with the sub-image here
                    cvNamedWindow("Selection");
                    cvShowImage("Selection", img);
                    cvReleaseImage(&img);
                    break;
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-06-19
      • 1970-01-01
      • 2016-06-29
      • 1970-01-01
      • 2014-11-16
      • 1970-01-01
      • 2013-08-02
      • 2023-02-23
      • 2011-07-08
      相关资源
      最近更新 更多