Omar Tariq
Omar Tariq

Reputation: 7726

Extracting Background Image Using GrabCut

I've an image (.jpg image), and I want to extract the background from the original image. I've googled a lot but have only found tutorials of extracting foreground image.

I've taken the code from another stackoverflow question. The code is working fine for me, and I've successfully extracted the foreground (as per my requirements). Now I want to completely remove this foreground from the original image. I want it to be something like this:-

Background = Original Image - Foreground

The empty space can be filled with black or white color. How can I achieve this?

I've tried using this technique:-

Mat background = image2 - foreground;

but it gives a complete black image.

Code:-

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main( )
{
// Open another image
Mat image;
image= cv::imread("images/abc.jpg");

Mat image2 = image.clone();

// define bounding rectangle
cv::Rect rectangle(40,90,image.cols-80,image.rows-170);

cv::Mat result; // segmentation result (4 possible values)
cv::Mat bgModel,fgModel; // the models (internally used)

// GrabCut segmentation
cv::grabCut(image,    // input image
            result,   // segmentation result
            rectangle,// rectangle containing foreground
            bgModel,fgModel, // models
            1,        // number of iterations
            cv::GC_INIT_WITH_RECT); // use rectangle
cout << "oks pa dito" <<endl;
// Get the pixels marked as likely foreground
cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);
// Generate output image
cv::Mat foreground(image.size(),CV_8UC3,cv::Scalar(255,255,255));
//cv::Mat background(image.size(),CV_8UC3,cv::Scalar(255,255,255));
image.copyTo(foreground,result); // bg pixels not copied

// draw rectangle on original image
cv::rectangle(image, rectangle, cv::Scalar(255,255,255),1);

imwrite("img_1.jpg",image);

imwrite("Foreground.jpg",foreground);
Mat background = image2 - foreground;
imwrite("Background.jpg",background);

return 0;
}

Note: I'm an opencv beginner and don't have much knowledge of it right now. I shall be very thankful to you if you can either post the complete code (as required by me) or just post the lines of code and tell me where these lines of code be placed. Thanks.

P.S. This is my second question at StackOverflow.com. apologies ... if not following any convention.

Upvotes: 8

Views: 14414

Answers (4)

Vimukthi Gunasekara
Vimukthi Gunasekara

Reputation: 41

Maybe another example helps, in which I assumed that the middle portion of the image is definitely foreground. So try this link. Example

Upvotes: 0

JiChong
JiChong

Reputation: 56

Just a small suggestion,@William's answer can be written more concisely as:

result = result & 1;

in order to get the binary mask.

Upvotes: 0

LovaBill
LovaBill

Reputation: 5139

What if you //Get the pixels marked as likely background:

// Get the pixels marked as likely background
cv::compare(result,cv::GC_PR_BGD,result,cv::CMP_EQ);

Edit: The above code is missing GC_BGD pixels. Despite a more efficient answer was given, let's finish what we started:

// Get the pixels marked as background
cv::compare(result,cv::GC_BGD,result_a,cv::CMP_EQ);
// Get the pixels marked as likely background
cv::compare(result,cv::GC_PR_BGD,result_b,cv::CMP_EQ);
// Final results
result=result_a+result_b;

Upvotes: 3

sietschie
sietschie

Reputation: 7543

Instead of copying all the pixels that are foreground, it copies all pixels which are not foreground. You can do this by using ~, which negates the mask:

image.copyTo(background,~result);

Upvotes: 12

Related Questions