Loading & Saving Bitmap Images In OpenCV (OpenCV Version = 3.1.0) - c++

My problem is simple at least as I see, or how I feel about it.
I tried to load and write Bitmap images with OpenCV in C++ and got sucessed in it, my problem is about the way the image is loaded and written.
Here is the thing: I working on 256-color palette (8bpp), trying to edit or add somethings on it, and then I write it or you can say I save it.
The problem is that the color palette before and after loading the image is not the same.
It seems like OpenCV is not just load the image but also change the palette color, in my case it is changed to RGB color (24bpp) which cause of an output image with size 3 x original image size after I saved the loaded image.
My question is there a way to load it or write without changing image color palette? if not possible, is there a way to write it with specific color palette? so I can specify it to 256-color palette (8bpp), if not possible either any possible converter will be good (from RGB color (24bpp) to 256-color palette (8bpp)).
Here is my code to load and write the Bitmap image:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
int main()
{
Mat BitImage = imread("BitImage_Intput.bmp", -1); // -1 To load image as it is (without changing) but not working.
imwrite("BitImage_Output.bmp", BitImage); // To write or save the image.
waitKey(0);
return 0;
}
I found this function, imread("BitImage_Intput.bmp", CV_8UC1);, It does the job in a side but ruins it on the other side, the color palette not changed but I got a GRAYSCALE image (All colors except white and black are removed or replaced).
The 256-color palette (8bpp) Bitmap Image
The RGB color (24bpp) Bitmap Image
The GRAYSCALE (8bpp) Bitmap Image

Related

Cannot load and overlay transparent image in OpenCV

I have transparentGUI.png image with transparent background - in GIMP it looks like that:
When I load it in OpenCV by Mat imgColorPanel = imread("transparentGUI.png", -1); and then display it by imshow("widok", imgColorPanel);, i can see this image with white background (which is wrong, because it should be transparent):
Eventually I want to overlay this image (with it's transparent background) on camera captured image. If I do it using other image, which has background (so it's not transparent) - then it's correctly overlayed.
However, when I want to overlay transparentGUI.png image on captured camera image by addWeighted(imgColorPanel, 0.8, imgOriginal, 0.6, 0, imgOriginal);, program crashes with console error:
as well as Debugging error:
Everything works unless I want to load and display image with transparent background. I assume it may be a conflict with imgOriginal, because it's in HSV - I am building program for object detection by HSV colors, so i cannot change it. Is it ok with overlaing HSV image with BGRA image (the transparent one)? Default color range of OpenCV is BGR, so even camera capture image is converted to HSV, then I can overlay it by other image which is BGR - so, I think that something else must be a problem.
imgColorPanel and imgOriginal should have the same size. From your statement, imgColorPanel has 4 channels (RGBA). To make "addWeighted" work, imgOriginal should also have 4 channels, instead of 3 HSV channels.
For "imshow", I think it is just display issue, and you may print out the size of imgColorPanel to check if it has 4 channels.
You are having two different problems:
i can see this image with white background (which is wrong, because it
should be transparent)
well, it's not wrong because you can't see transparency anyway and there's no standard consensus on how it should be rendered independent of context. In the case of GIMP you do see something - the background of the context-window containing the image. In the case of HighGui you probably get a white-background simply because that's the nominal background in this case. The only way around this is to tell the program what exactly seeing transparency means in the context of your program. This might require using another GUI-system, depends on what you want to do.
program crashes with console error
as the error message says, the problem is that the images you are trying to overlay have a different size. A solution would be to first create a transparent base image of the desired size, e.g. like this:
cv::Mat imgColorPanel {imgOriginal.rows, imgOriginal.cols, CV_8UC4, cv::Scalar{0,0,0,0}};
and then load the panel from your image in the desired part of the base using a ROI (the image has to be smaller than the base of course..) e.g.:
cv::Mat panel {cv::imread("PATH/TO/FILE")};
cv::Rect roi {0,0,panel.rows,panel.cols}; // x,y,width,height
cv::Mat imRoi {imgColorPanel(roi)};
imRoi = panel.clone();

opencv background subtraction get color objects

I've used below tutorial to do background subtraction,
http://docs.opencv.org/master/d1/dc5/tutorial_background_subtraction.html#gsc.tab=0
But using pMOG2->apply( frame, fgMaskMOG2 ) method return output as a binary image.
Is there any method to get only color objects after removing the background or get color image using binary image?
One thing you can do is to use the binary image as a mask for coping the objects from the color image into another image:
// create an image like frame but initialized to zeros
cv::Mat colorForeground = cv::Mat::zeros(frame.size(), frame.type());
// copy color objects into the new image using mask
frame.copyTo(colorForeground, fgMaskMOG2);
Now, in colorForeground, you can see the objects in color.

How to creat and initialized an image with alpha channel in opencv

I have this code, but it doesn't work: (it create an image which is all black)
eqr.create(size,CV_8UC4);
eqr.setTo( cv::Scalar(255,255,255,0)) ;
cv::imwrite("test.png", eqr);
this is also did not work: it creates an image which is all white.
eqr.create(size,CV_8UC4);
eqr.setTo( cv::Scalar(255,255,255,255)) ;
cv::imwrite("test.png", eqr);
What is the correct way to create an image with alpha channel and set all of its pixels to transparent?
You can find similar kind of example here
And if you need load transparent image(with alpha) use
imread("map.jpg",-1)
instead of
imread("map.jpg", CV_LOAD_IMAGE_COLOR)
which will load alpha, See OpenCV Doc for more info.

Transparent pixels in OpenCV C++ (when using GrabCut)

I am using OpenCV 's implementation of GrabCut in order to remove the background from images. But for now the new background is black. Is there any way to make it transparent?
For now this part of the code looks like this:
Mat binMask( image.size(), CV_8UC1 );
binMask = mask & 1;
image.copyTo( result, binMask );
Can I somehow fill the binMask with transparent pixels?
I've read some tutorials for overlaying images, but I don't need a transparent image in front of my picture but behind.
I hope someone could help.
Many thanks!
Since you are using a 8UC1 image type, it's not possible to have transparent pixels.
These are allowed only if you have an alpha channel, with alpha set to 0: you must use a 4-channel image (3 for colors, 1 for alpha channel). The alpha channel is supported in file formats such as PNG, but not in JPG.
In case of masking, you don't need by the way the usage of transparent pixels, since the black ones actually correspond to 0 and they don't influence the result when you're blending two images (addWeighted for example, or also in case of bitwise_or operation).

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.
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);
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;
Just a small suggestion,#William's
answer can be written more concisely as:
result = result & 1;
in order to get the binary mask.
Maybe another example helps, in which I assumed that the middle portion of the image is definitely foreground.
So try this link.
Example