2

I'm trying to split two images along a seam, and then blend them together. In this process, I need to cut out each image along the seam by applying a mask. How can I apply a mask? I tried bitwise_and and multiplying the mask and the image, but neither worked.

int pano_width = left_template_width + right_template_width - roi_width;  
// add zeros to the right of the left template
Mat full_left = Mat::zeros(roi_height, pano_width, CV_32FC3);
Mat tmp_l = full_left(Rect(0,0, left_template_width, roi_height));
imshow("Scene mask", mask0f3);
imshow("Cropped scene", cropped_scene);
Mat left_masked;
//bitwise_and(cropped_scene, mask0f3, left_masked); // full_left looks all black
multiply(cropped_scene, mask0f3, left_masked); // full_left looks like the scene mask, but with an extra black rectangle on the right side
left_masked.copyTo(tmp_l);
imshow("Full left", full_left);

enter image description here

enter image description here

enter image description here

I resorted to a terribly efficient, but working, hack:

void apply_mask(Mat& img, Mat mask) {
    CV_Assert(img.rows == mask.rows);
    CV_Assert(img.cols == mask.cols);
    print_mat_type(img);
    print_mat_type(mask);
    for (int r = 0; r < mask.rows; r++) {
        for (int c = 0; c < mask.cols; c++) {
            if (mask.at<uchar>(r, c) == 0) {
                img.at<Vec3f>(r, c) = Vec3f(0, 0, 0);
            }
        }
    }
}
Rose Perrone
  • 61,572
  • 58
  • 208
  • 243
  • Use [Mat::copyTo](http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-copyto) using above mask, also see the answer [here](http://stackoverflow.com/questions/22315904/blending-does-not-remove-seams-in-opencv) might be helpful. – Haris Apr 28 '14 at 04:16
  • You might find [this answer](http://stackoverflow.com/a/20288616/176769) interesting. – karlphillip Apr 28 '14 at 13:59

1 Answers1

2

Here you have snippet that works using bitwise_and (look at docs how this methods works)

    Mat img = imread("lena.jpg");
    Mat mask = Mat::zeros(img.rows, img.cols, CV_8UC1);
    Mat halfMask = mask(cv::Rect(0,0,img.rows/2, img.cols/2));
    halfMask.setTo(cv::Scalar(255));
    Mat left_masked;
    bitwise_and(img, cv::Scalar(255,255,255), left_masked, mask);

So you can use something like:

bitwise_and(cropped_scene, cv::Scalar(255,255,255), left_masked, mask); // mask must be CV_8UC1!

But you have to change type, or create new mask, which has a type of CV_8UC1.

EDIT: Your function apply_mask can look like:

void apply_mask(Mat& img, Mat &mask, Mat &result) {
    CV_Assert(img.rows == mask.rows);
    CV_Assert(img.cols == mask.cols);
    CV_Assert(img.type() == CV_32FC3);
    bitwise_and(img, cv::Scalar(1.0f,1.0f,1.0f), result, mask);
}

Unfortunately if you pass input image as an output image in bitwise_and, you've got all black output. But passing another argument works fine.

marol
  • 4,034
  • 3
  • 22
  • 31
  • I want to use an irregular shape as a mask -- not just a rectangle. You can see in the comment above my attempt at using `bitwise_and`. – Rose Perrone Apr 28 '14 at 13:48