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
Related
I am trying to make an image that is completely black except for a white rectangle at the centre of the image. However, on my first attempt, I got a weird result so I changed my code to nail down the problem.
So with for loops, I tried to set all the horizontal pixels at the centre to white to draw a white line across the image. Below is my code.
//--Block Mask--//
block_mask = cv::Mat::zeros(image_height, image_width, CV_8UC3);
int img_height = block_mask.rows;
int img_width = block_mask.cols;
for (int row = (img_height / 2); row < ((img_height / 2) + 1); row++)
{
for (int column = 0; column < img_width; column++)
{
block_mask.at<uchar>(row, column) = 255;
}
}
cv::namedWindow("Block Mask", CV_WINDOW_AUTOSIZE);
cv::imshow("Block Mask", block_mask);
img_height = 1080
img_width = 1920
image_height and image_width are defined from another image.
With this code I expected to see a white line drawn across the entire image, however, the white line extends only part way across the image. See the image below.
To troubleshoot I made a variable to count the iterations of the inner for loop and it counted up to 1920 as I expected it to. This leaves me wondering if it is something to do with the image being displayed? When simply setting individual pixels (not in loops) to white past where the line comes to, no results can be seen either.
I am at a loss as to what is going on here so any help, or perhaps a better way of achieving this, would be greatly appreciated.
Solved: The image block_mask is a three channel BGR image as it was created with the type CV_8UC3. However, when setting the pixel values to white the type uchar was used. Moreover, this was set to a signal integer type of value 255.
To properly set the colour of each pixel all three channels must be set. This can be achieved using a cv::Vec3b type variable that contains values for each channel and can be individually set. This can be done by:
cv::Vec3b new_pixel_colour;
new_pixel_colour[0] = 255; //Blue channel
new_pixel_colour[1] = 255; //Green channel
new_pixel_colour[2] = 255; //Red channel
From here, pixels can be assigned with this variable to change their colour, making sure to change the type in the .at operator to cv::Vec3b also. The corrected code is below.
//--Block Mask--//
block_mask = cv::Mat::zeros(image_height, image_width, CV_8UC3);
cv::Vec3b new_pixel_colour;
new_pixel_colour[0] = 255; //Blue channel
new_pixel_colour[1] = 255; //Green channel
new_pixel_colour[2] = 255; //Red channel
int img_height = block_mask.rows;
int img_width = block_mask.cols;
for (int row = (img_height / 2); row < ((img_height / 2) + 1); row++)
{
for (int column = 0; column < img_width; column++)
{
block_mask.at<cv::Vec3b>(row, column) = new_pixel_colour;
}
}
cv::namedWindow("Block Mask", CV_WINDOW_AUTOSIZE);
cv::imshow("Block Mask", block_mask);
An alternative solution for drawing is using the in-buit drawing functions of OpenCV. Specifically, for drawing a rectangle the OpenCV function cv::rectangle() can be used. A tutorial on basic drawing in OpenCV can be found here: https://docs.opencv.org/master/d3/d96/tutorial_basic_geometric_drawing.html
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)
I'm using Libraw to a project which is about manipulating raw image files. I need to implement a feature that from a raw file I need to export an image just with the red pixels (and other 3 images for blue, green and green2 pixels). I've tried the 4channels sample but that just gave me a picture with a black and gray scale. I've tried modifying the code with this before export the image:
for (int c = 0; c < S.iwidth; c++){
for(int r=0;r<S.iheight;r++){
printf("Row:%d Column:%d Color:%d Max Rows:%d Max Col:%d\n",r,c,RawProcessor.COLOR(r,c),S.iheight,S.iwidth);
//check if is a red pixel
if(RawProcessor.COLOR(r,c)!=0){
RawProcessor.imgdata.image[r*c][0] = 20000;
RawProcessor.imgdata.image[r*c][1] = 0;
RawProcessor.imgdata.image[r*c][2] = 0;
RawProcessor.imgdata.image[r*c][3] = 0;
}
}
This just give me a grayscale image with black dots in pixels which are not red. I want an image when you can see clearly the red color.
Can anyone help me with this problem?
Best regards
I have a question for us. I'm a newbe of OpenCV and I need to understand if that lib can help me to reach my goals.
I need to use OpenCV to open a Tiff file (big Tiff file) and split it on two different file with a mask like that Mask, in the end the file 1 have pixel black and the file 2 have the negative - pixel white of the original image.
Any ideas or example for me?
Thank you all!
To read the file, you can use the function imread. This stores it in a cv::Mat object. Since your mask is black and white, I would read the mask-image as a grayscale using IMREAD_GRAYSCALE. This gives you each pixel with a value from 0-255. That should cover the first part of your question.
I have to admit I am having trouble understandig your question, but I expect you want to create two images. The first contains all the pixels where your mask has a black pixel. The second one contains an image where in the mask all the pixels are white.
You could look at this thread. Additionally I would like to give you the way that I would do it.
The problem you would run in to is that your .tiff-image has a different type than your chessboard. Tiff is probably CV_8UC3 and chessboard is probably CV_8UC1. But this should be easily solvable.
I think you would probably want to look at each individual pixel and leave the be if, at that same pixel of the chessboard, your color is white. Then if it is not, make that pixel from your original pixel black. I have not tested this, but it would look something like this.
for (int i = 0; i < originalImage.rows; i++) {
for (int j = 0; j < originalImage.cols; j++) {
if (chessboard.at<uchar>(Point(j, i)) != 255) {
originalImage.at<Vec3b>(Point(j, i)) = Scalar(0, 0, 0);
}
else {
// Do nothing.
}
}
}
Scalar is used, since the originalImage has three channels instead of one. I hope this helps!
Try this to create the mask:
cv::Mat tiff;
cv::Mat maskDark = tiff == 0; // comparison like '< 10' also works
cv::Mat maskDark = tiff == 255;
I've wrote a code which detects squares (white) in realtime and draws a frame around it. Each side of length l of the squares is divided in 7 parts. Then I draw a line of length h=l/7 at each of the six points evolving from the deviation perpendicular to the side of the triangle (blue). The corners are marked in red. It then looks something like this:
For the drawing of the blue lines and circles I have a 3 Channel (CV_8UC3) matrix drawing, which is zero everywhere except at the positions of the red, blue and white lines. Then what I do to lay this matrix over my webcam image is using the addWeighted function of opencv.
addWeighted( drawing, 1, webcam_img, 1, 0.0, dst); (Description for addWeighted here).
But then, as you can see I get the effect that the colors for my dashes and circles are wrong outside the black area (probably also not correct inside the black area, but better there). It makes totally sense why it happens, as it just adds the matrices with a weight.
I'd like to have the matrix drawing with the correct colors over my image. Problem is, I don't no how to fix it. I somehow need a mask drawing_mask where my dashes are, sort of, superimposed to my camera image. In Matlab something like dst=webcam_img; dst(drawing>0)=drawing(drawing>0);
Anyone an idea how to do this in C++?
1. Custom version
I would write it explicitly:
const int cols = drawing.cols;
const int rows = drawing.rows;
for (int j = 0; j < rows; j++) {
const uint8_t* p_draw = drawing.ptr(j); //Take a pointer to j-th row of the image to be drawn
uint8_t* p_dest = webcam_img.ptr(j); //Take a pointer to j-th row of the destination image
for (int i = 0; i < cols; i++) {
//Check all three channels BGR
if(p_draw[0] | p_draw[1] | p_draw[2]) { //Using binary OR should ease the optimization work for the compiler
p_dest[0] = p_draw[0]; //If the pixel is not zero,
p_dest[1] = p_draw[1]; //copy it (overwrite) in the destination image
p_dest[2] = p_draw[2];
}
p_dest += 3; //Move to the next pixel
p_draw += 3;
}
}
Of course you can move this code in a function with arguments (const cv::Mat& drawing, cv::Mat& webcam_img).
2. OpenCV "purist" version
But the pure OpenCV way would be the following:
cv::Mat mask;
//Create a single channel image where each pixel != 0 if it is colored in your "drawing" image
cv::cvtColor(drawing, mask, CV_BGR2GRAY);
//Copy to destination image only pixels that are != 0 in the mask
drawing.copyTo(webcam_img, mask);
Less efficient (the color conversion to create the mask is somehow expensive), but certainly more compact. Small note: It won't work if you have one very dark color, like (0,0,1) that in grayscale will be converted to 0.
Also note that it might be less expensive to redraw the same overlays (lines, circles) in your destination image, basically calling the same draw operations that you made to create your drawing image.