OpenCV:如何使用掩码参数进行特征点检测(SURF)

9
我希望您能帮助我限制SurfFeatureDetector的区域(掩码)。为了进行测试,我只定义了一个掩码:
Mat srcImage; //RGB source image
Mat mask = Mat::zeros(srcImage.size(), srcImage.type());
Mat roi(mask, cv::Rect(10,10,100,100));
roi = Scalar(255, 255, 255);
SurfFeatureDetector detector();
std::vector<KeyPoint> keypoints;
detector.detect(srcImage, keypoints, roi); // crash
//detector.detect(srcImage, keypoints); // does not crash

当我使用“roi”作为掩码时,出现了以下错误:
OpenCV Error: Assertion failed (mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size())) in detect, file /Users/ux/Downloads/OpenCV-iOS/OpenCV-iOS/../opencv-svn/modules/features2d/src/detectors.cpp, line 63

这有什么问题吗?我应该如何正确地将掩模传递给SurfFeatureDetector的“detect”方法?
谢谢,
3个回答

18

关于 mask 的两件事情:

  • mask 应该是一个 8 位无符号字符的单通道矩阵,对应 opencv 类型 CV_8U。在你的情况下,mask 是 srcImage.type() 的类型,它是一个三通道矩阵。
  • 你正在将 roi 传递给检测器,但你应该传递 mask。当你对 roi 进行更改时,你也在更改 mask

以下内容应该有效:

Mat srcImage; //RGB source image
Mat mask = Mat::zeros(srcImage.size(), CV_8U);  // type of mask is CV_8U
// roi is a sub-image of mask specified by cv::Rect object
Mat roi(mask, cv::Rect(10,10,100,100));
// we set elements in roi region of the mask to 255 
roi = Scalar(255);  
SurfFeatureDetector detector();
std::vector<KeyPoint> keypoints;
detector.detect(srcImage, keypoints, mask);     // passing `mask` as a parameter

1
我认为应该是 Scalar(255);,因为掩码是一维的。 - Martin R.

2
我将你的 ROI 代码与我正在处理的一些现有代码连接起来,通过以下更改,它对我有效。
cv::Mat mask = cv::Mat::zeros(frame.size(), CV_8UC1);  //NOTE: using the type explicitly
cv::Mat roi(mask, cv::Rect(10,10,100,100));
roi = cv::Scalar(255, 255, 255);

//SURF feature detection
const int minHessian = 400;
cv::SurfFeatureDetector detector(minHessian);
std::vector<cv::KeyPoint> keypoints;
detector.detect(frame, keypoints, mask);              //NOTE: using mask here, NOT roi
cv::Mat img_keypoints; 
drawKeypoints(frame, keypoints, img_keypoints, cv::Scalar::all(-1), cv::DrawMatchesFlags::DEFAULT);
cv::imshow("input image + Keypoints", img_keypoints);
cv::waitKey(0);

如果不改变类型并使用mask替代roi作为掩膜,我也会遇到运行时错误。这很有道理,因为detect方法需要一个掩膜——它应该与原始图像的大小相同,而roi不是(它是一个100x100的矩形)。要在可视化上看到这一点,请尝试显示掩膜和roi。

cv::imshow("Mask", mask);
cv::waitKey(0);

cv::imshow("ROI", roi);
cv::waitKey(0);

类型也必须匹配;掩膜应该是单通道的,而您的图像类型很可能是16型,它映射到CV_8UC3,即三通道图像


0
如果您想要将相同的方法应用于不规则掩码,则:
Mat& obtainIregularROI(Mat& origImag, Point2f topLeft, Point2f topRight, Point2f botLeft, Point2f botRight){

        static Mat black(origImag.rows, origImag.cols, origImag.type(), cv::Scalar::all(0));
        Mat mask(origImag.rows, origImag.cols, CV_8UC1, cv::Scalar(0));
        vector< vector<Point> >  co_ordinates;
        co_ordinates.push_back(vector<Point>());
        co_ordinates[0].push_back(topLeft);
        co_ordinates[0].push_back(botLeft);
        co_ordinates[0].push_back(botRight);
        co_ordinates[0].push_back(topRight);
        drawContours( mask,co_ordinates,0, Scalar(255),CV_FILLED, 8 );

       // origImag.copyTo(black,mask);
        //BasicAlgo::getInstance()->writeImage(black);
        return mask;  // returning the mask only
    }

然后像往常一样,生成SIFT/SURF/...指针

// 为SIFT特征检测器创建智能指针。

Ptr<FeatureDetector> SIFT_FeatureDetector = FeatureDetector::create("SIFT");
vector<KeyPoint> SIFT_Keypoints;
vector<KeyPoint> SIFT_KeypointsRotated; 
Mat maskedImg = ImageDeformationOperations::getInstance()->obtainIregularROI( rotatedImg,rotTopLeft,rotTopRight,rotBotLeft,rotBotRight);
SIFT_FeatureDetector->detect(rotatedImg, SIFT_KeypointsRotated, maskedImg);
Mat outputSIFTKeyPt;
drawKeypoints(rotatedImg, SIFT_KeypointsRotated, outputSIFTKeyPt, keypointColor, DrawMatchesFlags::DEFAULT);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接