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

22,575

Solution 1

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 roi to the detector but you should be passing mask. When you are making changes to roi, you are also changing 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

Solution 2

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

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 mask instead of roi as 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

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

Share:
22,575
Hyndrix
Author by

Hyndrix

Updated on September 26, 2020

Comments

  • Hyndrix
    Hyndrix over 3 years

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

    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:

    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?

    Regards,

  • Martin R.
    Martin R. over 8 years
    I think it should be Scalar(255); as the mask is 1-dimensional.