Cannot load and overlay transparent image in OpenCV - c++

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();

Related

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

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

Create mask to select the black area

I have a black area around my image and I want to create a mask using OpenCV C++ that selects just this black area so that I can paint it later. How can i do that without affecting the image itself?
I tried to convert the image to grayscale and then using threshold to convert it to binary, but it affects my image since the result contains black pixels from inside the image.
Another Question : if i want to crop the image instead of paint it, how can i do it??
Thanks in advance,
I would solve the problem like this:
Inverse-binarize the image with a threshold of 1 (i.e. all pixels with the value 0 are set to 1, all others to 0)
use cv::findContours to find white segments
remove segments that don't touch image borders
use cv::drawContours to draw the remaining segments to a mask.
There is probably a more efficient solution in terms of runtime efficiency, but you should be able to prototype my solution quite quickly.

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).

transparent colour being shown some of the time

I am using a LPDIRECT3DTEXTURE9 to hold my image.
This is the function used to display my picture.
int drawcharacter(SPRITE& person, LPDIRECT3DTEXTURE9& image)
{
position.x = (float)person.x;
position.y = (float)person.y;
sprite_handler->Draw(
image,
&srcRect,
NULL,
&position,
D3DCOLOR_XRGB(255,255,255));
return 0;
}
According to the book I have the RGB colour shown as the last parameter will not be displayed on screen, this is how you create transparency.
This works for the most part but leaves a pink line around my image and the edge of the picture. After trial and error I have found that if I go back into photoshop I can eliminate the pink box by drawing over it with the pink colour. This can be see with the ships on the left.
I am starting to think that photoshop is blending the edges of the image so that background is not all the same shade of pink though I have no proof.
Can anyone help fix this by programming or is the error in the image?
If anyone is good at photoshop can they tell me how to fix the image, I use png mostly but am willing to change if necessary.
edit: texture creation code as requested
character_image = LoadTexture("character.bmp", D3DCOLOR_XRGB(255,0,255));
if (character_image == NULL)
return 0;
You are loading a BMP image, which does not support transparency natively - the last parameter D3DCOLOR_XRGB(255,0,255) is being used to add transparency to an image which doesn't have any. The problem is that the color must match exactly, if it is off even by only one it will not be converted to transparent and you will see the near-magenta showing through.
Save your images as 24-bit PNG with transparency, and if you load them correctly there will be no problems. Also don't add the magenta background before you save them.
As you already use PNG, you can just store the alpha value there directly from Photoshop. PNG supports transparency out of the box, and it can give better appearance than what you get with transparent colour.
It's described in http://www.toymaker.info/Games/html/textures.html (for example).
Photoshop is anti-aliasing the edge of the image. If it determines that 30% of a pixel is inside the image and 70% is outside, it sets the alpha value for that pixel to 70%. This gives a much smoother result than using a pixel-based transparency mask. You seem to be throwing these alpha values away, is that right? The pink presumably comes from the way that Photoshop displays partially transparent pixels.