Efficient Background subtraction with OpenCV - opencv

I want to do background subtraction in a video file using OpenCV method. Right now I'm able to do background subtraction, but the problem is that I couldn't get the output in color mode. All the output after subtracting the background is coming in grayscale color mode :(. I want to get the color information to the foreground which is the resulting output after background got subtracted.
Can I do it using masking technique?? like the following procedure which I'm thinking about.
Capture Input -- InputFrame (RGB)
Process InputFrame
Subtract background, store foreground in TempFrame (which is coming in grayscale :( )
Create a mask using TempFrame
Apply the created mask to the InputFrame
Get colored foreground as OutFrame
I'm struck up with doing the masking using OpenCV. I'm just a very beginner in OpenCV. Please help me to overcome this.
Thanks in advance.

http://vimeo.com/27477093
code is here
http://code.google.com/p/derin-deli-mavi/downloads/detail?name=denemeOpenCv23.zip&can=2&q=
to reach a colored foreground
just copy image by using foreground mask
// image.copyTo(foreground,foreground);

Okay, I don't understand how TempFrame (your foreground) could be greyscale if you are using background subtraction. You must be using a very special algorithm. But assuming TempFrame is greyscale, then you would do this:
cv::Mat mask = tempFrame > 0.5;
cv::Mat outFrame;
capturedFrame.copyTo(outFrame, mask);
That is OpenCV 2.0 code above. The number 0.5 is a threshold, you'll need to set it to something appropriate. If you're not using floating-point images, you'd probably set it to 128 or something like that. This is the same thing in OpenCV 1.1 code:
CvMat* mask = cvCreateMat(tempFrame.rows, tempFrame.cols, CV_8UC1);
cvCmpS(tempFrame, 0.5, mask);
CvMat* outFrame = cvCreateMat(capturedFrame.rows, capturedFrames.cols, CV_32FC3);
cvCopy(capturedFrame, outFrame, mask);

Related

OpenCV Circle mask anti-aliasing

I'm trying to use OpenCV to overlay two images together.
Input 1 background (b.jpg):
Input 2 foreground (f.jpg):
Desired output:
Real output:
The idea is to overlay circular part of foreground onto background.
I'm using the code:
Mat background = imread("b.jpg");
Mat foreground = imread("f.jpg");
Mat mask{foreground.size(), foreground.type(), Scalar::all(0)};
circle(mask, Point{foreground.cols / 2, foreground.rows / 2}, foreground.cols / 2 - 10, Scalar::all(255), -1, CV_AA);
imwrite("mask.jpg", mask);
foreground.copyTo(background, mask);
imwrite("overlay.jpg", background);
For the mask itself, I can see a perfect circle draw with very smooth edge.
But as soon as I call copyTo with the circular mask. The resulting image has abrupt edges and seems the anti-aliasing part is completely missing.
Is there a way to make the copyTo honoring the anti-aliasing fact? Or there is an easier way to achieve the same output?

OpenCV: How to ignore background pixels from colour custers

I am trying to find the dominant colors in dresses.
1) First step is to remove the background. I did this using the solution mentioned here. It works perfectly and makes the background black.
2) Now with the result of the first step I am trying to find dominant colors using the solution mentioned here. But I am getting black (the background) as one of the dominant colours.
How can I ignore the background pixels in step 2?
Depending on the case, you could find the bounding rectangle of the region that you're interested in. If the number of color pixels is much higher than the number of black pixels inside that bounding rectangle, black shouldn't be detected as the dominant color.
Call findContours(binaryMask) on the binary image of your mask. Make sure you found just the contour you were looking for. If not, filter them to get the best one for the application. Then call boundingRect(cnt) on the contour. Then crop the image using that rectangle and run your function. If that's insufficient, try minAreaRect(cnt), but the cropping is a bit trickier: see this answer.
If that doesn't work, I'd probably go for the "dumb" solution, by changing the color of the mask to a color that will for 99% not appear on a dress and then - knowing it exact RGB values - filter it out from the results.
Next time please remember to provide an image of your case, so the answers may be more accurate.
One easy way to do it would be to simply discard black as a dominant colour. Grab one more cluster than you really want, ignore black. If black may genuinely be the dominant colour, repeat the operation with a different background colour and discard that; compare results. This would be slow, but simple to do.
Alternatively, you could only sample from pixels in your foreground. From your foreground extraction method, you should have a binary black and white foreground/background mask. If you only sample from white areas of the mask, then only these colours should be taken into consideration.
I have a rough C++ implementation of this, but it's almost certainly not the most efficient possible. Maybe it's a start you could work from?
Mat src; //Your source image
Mat mask; //Your black & white foreground/background image
Mat samples(src.rows * src.cols, 3, CV_32F);
//Set up samples with only foreground pixels
for (int y = 0; y < src.rows; y++) {
for (int x = 0; x < src.cols; x++) {
if (mask.at<uchar>(y, x) == 255) {
for (int z = 0; z < 3; z++) {
samples.at<float>(y + x*src.rows, z) = src.at<Vec3b>(y, x)[z];
}
}
}
}
int clusterNo = 3;
int attempts = 5;
Mat labels;
Mat centers;
kmeans(samples, clusterNo, labels, TermCriteria(), attempts, KMEANS_RANDOM_CENTERS, centers);
Your dominant colours will be stored in the rows of centres, where you can do what you want with them.
Remove the background. That gives you a binary image - foreground and background pixels. Now do a morphological closing to close up little holes in foreground images and generally clean up the contours. Finally substitute pixels back in again to get a colour foreground image.

iOS how to mask the image background color

I want to do following thing within in my iOS app:
user can draw something on white background paper.
my app allows user to capture the drawn image. Here the image will capture with background white color.
finally from the captured image i need to mask the white background color and just get the image alone into UIImage object.
I completed the steps 1 and 2. But i do not have any idea how to do the last step. Is there any openCV library that i can use it with my iOS app?.
Any help that might be really appreciated.
Well, since OpenCV itself is THE library, I guess that you are looking for a way to do that with OpenCV.
First, convert the input image to Mat, which is the data type OpenCV uses to represent an image;
Then, assuming the background is white, threshold the Mat to separate the background from whatever the user draw. According to the example below, the result of this operation makes the background black, and every pixel that is not black will represent something the user has draw:
Finally, convert the resulting Mat to UIImage: for this, iterate on the Mat and copy every pixel that is not black to the UIImage to have an UIImage that contains only what the user draw.
A better idea is to iterate on the thresholded Mat, figure out which pixel is not black, and instead of copying it directly to the new UIImage, copy that pixel (x,y) from the original UIImage, so you have a colored pixel at the end, which gives a more realistic result.

How to generate foreground-only image given the foreground silhouette in OpenCV?

I did the background substraction part for my foreground extraction task. Now that i have silhouette representing foreground in white and background in black, I dont know how to make a foreground image containing only the pixels values (from the original frame). I am using Opencv 2.3 and i am using Mat for storing images. Any ideas?
Thanks in advance..
You can do as follow:
Mat image; // the original image
Mat foreground_bw; // the foreground in black and white
background_subtractor ( image, foreground_bw, -1.0 );
// getting the corresponding pixel values for the foreground.
Mat foreground = Mat::zeros ( image.rows, image.cols, image.type() );
image.copyTo ( foreground, foreground_bw );
make a new image with the dimensions of the original, cycle through all the pixels in the background / foreground image (the one where background is black and foreground white) and for each pixel either copy from the current / original image (the one from the camera etc) or from your background estimate. done.

OpenCV image conversion from RGB to Grayscale using imread giving poor results

I'm loading a 24 Bit RGB image from a PNG file into my OpenCV application.
However loading the image as grayscale directly using imread gives a very poor result.
Mat src1 = imread(inputImageFilename1.c_str(), 0);
Loading the RGB image as RGB and converting it to Grayscale gives a much better looking result.
Mat src1 = imread(inputImageFilename1.c_str(), 1);
cvtColor(src1, src1Gray, CV_RGB2GRAY);
I'm wondering if I'm using imread for my image type correctly. Has anyone experienced similar behavior?
The image converted to grayscale using imread is shown here:
The image converted to grayscale using cvtColor is shown here:
I was having the same issue today. Ultimately, I compared three methods:
//method 1
cv::Mat gs = cv::imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
//method 2
cv::Mat color = cv::imread(filename, 1); //loads color if it is available
cv::Mat gs_rgb(color.size(), CV_8UC1);
cv::cvtColor(color, gs_rgb, CV_RGB2GRAY);
//method 3
cv::Mat gs_bgr(color.size(), CV_8UC1);
cv::cvtColor(color, gs_bgr, CV_BGR2GRAY);
Methods 1 (loading grayscale) and 3 (CV_BGR2GRAY) produce identical results, while method 2 produces a different result. For my own ends, I've started using CV_BGR2GRAY.
My input files are jpgs, so there might be issues related to your particular image format.
The simple answer is, that openCV functions uses the BGR format. If you read in a image with imread or VideoCapture, it'll be always BGR. If you use RGB2GRAY, you interchange the blue channel with the green. The formula to get the brightness is
y = 0.587*green + 0.299*red + 0.114*blue
so if you change green and blue, this will cause an huge calculation error.
Greets
I have had a similar problem once, working with OpenGL shaders. It seems that the first container that OpenCV reads your image with does not support all the ranges of color and hence you see that the image is a poor grayscale transformation. However once you convert the original image into grayscale using cvtColor the container is different from the first one and supports all ranges. In my opinion the first one uses less than 8 bits for grayscale or changing to the grayscale uses a bad method. But the second one gives smooth image because of more bits in gray channel.

Resources