OpenCV : imwrite changes the channels pixels values when saving - c++

I'm reading an image and doing some processing on the blue channel without changing the Red nor the green channels.
When i finished processing the blue channel, i merged back the three channels into one RGB image. and when i use imshow to view the channels, every thing is alright and i can see that the changes i've made only affect the Blue channel and they do not affect the red nor the green ones.
Up to this point every thing is alright !
But when i save the image using imwrite, the resulting image is slightly different, in that the changes made on the blue channel seem to get propagated to the red and green channels, it's like imwrite is doing some kind of mean between the 3 channels :
image = imread('image.jpg', IMREAD_COLOR);
split(image, channels);
// Create some changes on channels[0]
merge(channels, 3, image);
// Up to this point every thing is alright
imwrite("modified.jpg", image); // Image changes when written;
Is there any solution to avoid this behavior ?

JPG is a lossy format: https://en.wikipedia.org/wiki/JPEG
JPEG (/ˈdʒeɪpɛɡ/ JAY-peg)1 is a commonly used method of lossy
compression for digital images, particularly for those images produced
by digital photography. The degree of compression can be adjusted,
allowing a selectable tradeoff between storage size and image quality.
JPEG typically achieves 10:1 compression with little perceptible loss
in image quality.
Solution: Use a lossles Format like PNG to save your image.

Related

how many channels does a bayer image have?

i am working on bayer images. i use basler camera and i get bayerBG8 image from it. in pylon i can directly converted to RGB, but i want to save the bayer image so i need to specify its channels to define a mat file. when i use 1 channel for it i get gray scale image and if i choose more than on channel, images repeated in one frame as shown:
Bayer filter is a technique to use a single-channel image sensor to receive color image by defining which pixel should represent which color, so a bayer image should have one channel.

How to encode grayscale video in libvpx (webm)?

I have a stream of raw images that cames from a network grayscale camera that we are developing. In this case, our images are arrays of 8bits pixels (640x480). Since this camera outputs more than 200 frames per second, I need to store these images as a WebM video, as quickly as possible, in order to not lose any frame.
What is the best way of doing that, using libvpx?
The fastest and easiest thing to do would be to provide the gray scale plane directly into libvpx compression function vpx_codec_encode with VPX_IMG_FMT_I420. You'll have to input two 2x2 subsampled color planes with it though - 320x240 in your case - make all the octets of those planes have the value 128.

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

Is there a way to have both grayscale and rgb pixels on the same image opencv C++?

I need to be able to work with images where some regions are grayscale while others are kept on the RGB format. I don't want to convert an image into a grayscale since it will lose the channels and will become simply one channeled, is there a way to keep the RGB channels of some pixels on the picture and turn the others into a grayscale?
NO.
I see two solutions to this:
Have both a gray (Mat1b) and a rgb (Mat3b) image, and work on the image you need.
Have a single rgb (Mat3b) image, and set r,g,b channels to the same gray value where you need. In this way you can mimic to have a mixed gray/rgb image.

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