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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16365129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:17:59  来源:igfitidea点击:

OpenCV: howto use mask parameter for feature point detection (SURF)

c++opencvfeature-detectionsurfroi

提问by Hyndrix

I want to limit a SurfFeatureDetector to a set of regions (mask). For a test I define only a single mask:

我想将 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

When I pass the "roi" as the mask I get this error:

当我将“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

What is wrong with this? How can I correctly pass a mask to the SurfFeatureDetector's "detect" method?

这有什么问题?如何正确地将掩码传递给 SurfFeatureDetector 的“检测”方法?

Regards,

问候,

回答by Alexey

Two things about the mask.

关于面具的两件事。

  • the mask should be a 1-channel matrix of 8-bit unsigned chars, which translates to opencv type CV_8U. In your case the mask is of type srcImage.type(), which is a 3-channel matrix
  • you are passing roito the detector but you should be passing mask. When you are making changes to roi, you are also changing mask.
  • 掩码应该是一个 8 位无符号字符的 1 通道矩阵,转换为 opencv 类型CV_8U。在您的情况下,掩码的类型为 srcImage.type(),这是一个 3 通道矩阵
  • 您正在通过roi检测器,但您应该通过mask。当您对 进行更改时roi,您也在更改mask

the following should work

以下应该工作

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

回答by alrikai

I tacked your ROI code onto some existing code I was working on, with the following changes it worked for me

我将您的 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);

Without the changes to the type and the use of maskinstead of roias your mask, I'd get a runtime error as well. This makes sense, as the detect method wants a mask -- it should be the same size as the original image, and roi isn't (it's a 100x100 rectangle). To see this visually, try displaying the mask and the roi

如果不更改类型和使用mask代替roi作为掩码,我也会收到运行时错误。这是有道理的,因为检测方法需要一个掩码——它应该与原始图像的大小相同,而 roi 不是(它是一个 100x100 的矩形)。要直观地看到这一点,请尝试显示掩码和 roi

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

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

The type has to match also; the mask should be single channel, while your image type is likely of type 16, which maps to CV_8UC3, a triple channel image

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

回答by Spandan

If you are looking to apply the same for irregular mask then:

如果您希望将相同的方法应用于不规则蒙版,则:

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
    }

Then as usual, generate SIFT/SURF/... pointer

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

// Create smart pointer for SIFT feature detector.

// 为 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);