Change all white pixels of image to transparent in OpenCV C++ - c++

I have this image in OpenCV imgColorPanel = imread("newGUI.png", CV_LOAD_IMAGE_COLOR);:
When I load it in with grey scale imgColorPanel = imread("newGUI.png", CV_LOAD_IMAGE_GRAYSCALE); it looks like this:
However I want to remove the white background or make it transparent (only it's white pixels), to be looking like this:
How to do it in C++ OpenCV ?

You can convert the input image to BGRA channel (color image with alpha channel) and then modify each pixel that is white to set the alpha value to zero.
See this code:
// load as color image BGR
cv::Mat input = cv::imread("C:/StackOverflow/Input/transparentWhite.png");
cv::Mat input_bgra;
cv::cvtColor(input, input_bgra, CV_BGR2BGRA);
// find all white pixel and set alpha value to zero:
for (int y = 0; y < input_bgra.rows; ++y)
for (int x = 0; x < input_bgra.cols; ++x)
{
cv::Vec4b & pixel = input_bgra.at<cv::Vec4b>(y, x);
// if pixel is white
if (pixel[0] == 255 && pixel[1] == 255 && pixel[2] == 255)
{
// set alpha to zero:
pixel[3] = 0;
}
}
// save as .png file (which supports alpha channels/transparency)
cv::imwrite("C:/StackOverflow/Output/transparentWhite.png", input_bgra);
This will save your image with transparency.
The result image opened with GIMP looks like:
As you can see, some "white regions" are not transparent, this means your those pixel weren't perfectly white in the input image.
Instead you can try
// if pixel is white
int thres = 245; // where thres is some value smaller but near to 255.
if (pixel[0] >= thres&& pixel[1] >= thres && pixel[2] >= thres)

Related

How to change the color of a pixel in HSV?

I have the infamous yoshi image in HSV and I want to change the color of the pixels in certain parts of the image.
cv::cvtColor(frame, frame_hsv, cv::COLOR_BGR2HSV);
for (int y = 0; y < mask.size().height; y++) {
for (int x = 0; x < mask.size().width; x++) {
cv::Vec3b pixelM = mask.at<cv::Vec3b>(cv::Point(x, y));
if ((pixelM[0] == 255) && (pixelM[1] = 255) && (pixelM[2] = 255)) { // If white
cv::Vec3b& pixelF = frame_hsv.at<cv::Vec3b>(cv::Point(x, y));
pixelF[0] = 280;
pixelF[1] = 100;
pixelF[2] = 100;
}
}
}
cv::cvtColor(frame_hsv, frame, cv::COLOR_HSV2BGR);
Here frame is the original yoshi image and mask is the image that shows me where exactly to change the color of the pixel. The color is changing exactly where I want BUT the color, that I am expecting is different. In the image (output) below you see a "dirty green" but I am expecting a purpe color (HSV: 280, 100, 100). Why is the color not being set correctly?
yoshi
yoshi attempted color red and Hue/2 (HSV: 180, 100, 100)

access and change color of pixels based on another image - opencv c++

I have an image in two different formats. one is BGR and the other is black and white (there is only black and white, no gray colored pixels). Its the same exact image (same size and pixels). I want to find all the white pixels in the black and white image, mark them down and then find the exact same pixels in the BGR image (obviously they are colored in the BGR image) and color them black.
I tried it but the thing is the black and white image has 1 channel and the BGR one has 3 channels so i failed...
i am using opencv in c++
thanks for your help! :)
for(int y=0;y<inputImage.rows;y++){
for(int x=0;x<inputImage.cols;x++){
Vec3b color = inputImage.at<Vec3b>(Point(x,y));
if(blackWhite.at<uchar>(y,x) == 255){
//cout << "found white pixel\n";
color[0] = 0;
color[1] = 0;
color[2] = 0;
inputImage.at<Vec3b>(Point(x,y)) = color;
}
}
}
inputImage is my BGR image and blackWhite is an image of same size with black and white pixels. both are Mat objects.
i want to go through the blackWhite image and whenever i find a white pixel, color the same pixel from the inputImage image in black color.
My strategy is to construct an array similar to your blackWhite image. This array will be zeros and ones and we'll multiply it with inputImage to get the desired output.
Currently, your blackWhite image looks something like (for example)
blackWhite = 255 255 0 0 ....
....
in pseudocode. If we transform this image to become
newArray = 0 0 1 1 ....
....
You could then use cv::multiply(newArray, inputImage) to get the desired output.
One way to directly transform your existing blackWhite image into newArray would be to perform y = (-1/255)*x + 1 on every pixel in blackWhite. You can accomplish this with cv::Mat::convertTo(outputImage, 8, -1/255, 1)

Is there a way to change the pixel of an 2 image?

enter image description here
jpg
I want to check the 2nd image to see if the pixel is white, if it is white i should change it into a black pixel, and also i should be able to change the pixel of the same spot in the 2nd image to the 1st image to black or white..
Example:
img at the cooridnate (100,100) the pixel is white from the 2nd image and i should be able to change it into black. Then the 1st img at the same cooridnate (100,100) the pixel would be black and i should be able to change it into white. to reduce the noise.
The below code shows you how to find a point in an image, see if it i white, and change it to black if it is.
Scalar colourInSecondImage = img2.at<uchar>(y,x);
if(colourInSecondImage .val[0]==255 && colourInSecondImage .val[1]==255 && colourInSecondImage .val[2]==255)
{
// Then your point is a white point
img2.at<uchar>(y,x) = Scalar(0,0,0);
}
I'm a little confused by your question, it seems to be that you then want to access the same point in another image and set that to black? Or the same colour? either way you would use the same method as in the code above. change change im2 to img1
This is how you can loop through all your pixel values and manipulate them
for(int r = 0; r < image.rows; r++) {
for(int c = 0; c < image.cols; c++) {
// if pixel is white
if(image.at<uchar>(r,c) == 255) {
image.at<uchar>(r,c) = 0;
}
}
}
//// split channels
split(image,spl);
imshow("spl1",spl[0]);//b
imshow("spl2",spl[1]);//g
imshow("spl3",spl[2]);//r

Replacement of grayscale color with rgb color with open cv

I want to replace grayscale color with rgb color for each pixel. I am new to open cv.
GrayScale val = 25
replace by
rgb value = 0,0,255
This is how to do it with a LUT:
I create some dummy image with grayscale values:
cv::Mat input = cv::Mat(512,512,CV_8UC1, cv::Scalar(0));
for(int j=0; j<input.rows; ++j)
for(int i=0; i<input.cols; ++i)
{
input.at<unsigned char>(j,i) = i/2;
}
Then I set up the LUT:
// create replacement look-up-table:
// 1. basic => gray values of given intensity
cv::Mat lookUpTable(1, 256, CV_8UC3);
for( int i = 0; i < 256; ++i)
lookUpTable.at<cv::Vec3b>(0,i) = cv::Vec3b(i,i,i);
// 2. replace whatever colors you want:
lookUpTable.at<cv::Vec3b>(0,25) = cv::Vec3b(25,0,0);
lookUpTable.at<cv::Vec3b>(0,100) = cv::Vec3b(0,255,0); // means to replace each gray == (100) value by a (0,255,0) color value after LUT call
lookUpTable.at<cv::Vec3b>(0,115) = cv::Vec3b(255,0,0);
lookUpTable.at<cv::Vec3b>(0,200) = cv::Vec3b(0,100,255);
afterwards: convert input to COLOR and call LUT:
// unfortunately, we have to convert to color, because OpenCV doesnt allow LUT from single channel to 3 channel directly. (LUT must have same number of channels as input)
cv::Mat input_3channels;
cv::cvtColor(input, input_3channels, CV_GRAY2BGR);
cv::Mat output;
cv::LUT(input_3channels, lookUpTable, output);
Giving me that output for this input:
In your comments you like to replace "black" color by "red" color. You have to define what you mean by "black". In theory, black color is intensity = 0 and everything > 0 is just a very dark gray. So here I show how to set some ranges to a color:
cv::Mat lookUpTable(1, 256, CV_8UC3);
for( int i = 0; i < 256; ++i)
lookUpTable.at<cv::Vec3b>(0,i) = cv::Vec3b(i,i,i);
// 2. replace "black color" by red:
// you have to define what black means. If you mean pure black (intensity == 0) then use this:
//lookUpTable.at<cv::Vec3b>(0,0 /* intensity == 0 */) = cv::Vec3b(0,0,255);
// if you mean something that appears mostly black for a human eye, use something like this:
unsigned char startIntensity = 0; // start at intensity 0 (black)
unsigned char endIntensity = 20; // the higher this value, the more "dark grey" will be replaced by red too
cv::Vec3b replacementColor = cv::Vec3b(0,0,255); // red
for(int i=startIntensity ; i < endIntensity ; ++i)
lookUpTable.at<cv::Vec3b>(0,i) = replacementColor;
for example giving this result:
Here you have a small test code (the key is inRange):
create a rectangle in a gray image (with value of 25)
create a mask where the 25 values are (inRange)
transform the gray image into color image
change the value of the pixels where the mask is
cv::Mat image = cv::Mat::zeros(cv::Size(200,200), CV_8U); //create zero image
cv::rectangle(image, cv::Rect(50, 50, 100, 100), cv::Scalar::all(25), -1); //write a rectangle
cv::imshow("image", image); //show image
cv::Mat mask;
cv::inRange(image,25,25,mask); //mask the 25 values
cv::cvtColor(image, image, CV_GRAY2BGR); //convert gray image to BGR
cv::Scalar red(0,0,255);
image.setTo(red,mask); //change all 25 values into red color
cv::imshow("colorImage", image); //show result image
cv::waitKey(0); //wait until you press a key

Detecting black/gray elements in OpenCV

You guys know how to detect/return the points of all black/grayish element in an image?
If possible, please include any tutorial codes for me.
Edit: I've made a thresholded image from the source "img". and I'm trying to make all the colored pixel into white.
for(x=0; x<img->width; x++) {
for(y=0;y<img->height; y++) {
uchar* temp_ptr = &((uchar*)(img_result_threshold->imageData + img_result_threshold->widthStep*y))[x];
s = cvGet2D(img_hsv, y, x);
if(s.val[1] >= 100 && s.val[2] >= 100) {
temp_ptr[0]=255; //White to greater of threshold
printf("Point(%d, %d) = (%.1f, %.1f, %.1f)\n", x, y, s.val[0], s.val[1], s.val[2]);
} else {
temp_ptr[0]=0; //Black other
}
}
}
Assuming the input image is in 24 bit format i.e. R G B then a pixel is greyscale if all three values (R G and B) are the same.
So loop through the image, check if the current pixel's R, G and B elements have the same value and if they don't then set the pixel to white.
You will then be left with an image with just the greyscale pixels.
If you want just dark grey pixels, then when you check to see if RGB values are the same you can do a second check to see if the value is less than say 127 (or whatever you want the threshold to be).
Convert the color image into gray image first by the following, provided your image is RGB
cvtColor(im_rgb,im_gray,CV_RGB2GRAY);
Convert the image into binary using your threshold, say 127
cvThreshold(im_gray, im_bw, 127, 255, CV_THRESH_BINARY);