OpenCV masking/split function - c++

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;

Related

There is an unclear issue in scaling and subtracting an image using OpenCV 3 C++

So I've generated a binary jpeg image as shown here :
as I know this image has either 255 or 0 values (I dunno why in paint I find some pixels at the edge with different values, but I ignored them they are so few, and I am not sure if they came from the JPEG format)
so my target is to convert this image to 0x00 for the dark spots and 0x01 for the light spots (note I mean 1 as one and not as 255)
for (int i = 0; i < eroded_dilated_binary.rows; i++)
{
for (int j = 0; j < eroded_dilated_binary.cols; j++)
{
pix=eroded_dilated_binary.at<char>(i, j); //pix is defined as char here
eroded_dilated_binary.at<char>(i, j) = (pix / 255);
}
}
out is here :
I checked the output and I got to deduce it is all 0's. but how is it possible?
I even tried to divide the first image by 2 I got non-logical answer. I even tried to subtract some value from each pixel but still got weird values.
I tried that other syntax shown in this topic OpenCV:Whats the easiest way to divide a Mat by a Scalar but it gives totally wrong values.
1-What is going on behind the scenes? I don't get how arithmetic operations work here!!
2- how to guarantee that my image is only 1's and 0's or only 0's and 255's?
3- when I and this binary mask with the original image to hide the background, I get the middle image correctly but the body of the bottle has more fluctuations and random pixilization in the middle and even Gaussian filter is not smoothing well. I thought anding function has different way of working too?

How to extract segmentation as images after applying K Means using OpenCV C++?

I am new to OpenCV.
My image consists of Red, Green and Blue color pixels spread throughout at random. I have applied K Means and want to save clustering as different images. Suppose if I consider the number of clusters as 3, I want three images saved with the segmentation done by K Means.
The language I am using is C++. And will also be helpful if any suggestions for EMGUCV.
Thankful for responses!
Any suggestions are welcome!
The bestLabels argument to kmeans (you call it 'Labels') lets you specify a cv::Mat where the method will store label indices for all input pixels. It has the same geometry as the input image.
Splitting the output to masks is rather simple. The masks can then be saved as files. Example code (not tested):
for (auto k = 0; k < K; ++k) {
cv::Mat1b mask = (bestLabels == k);
cv::imwrite("cluster_" + std::to_string(k) + ".png", mask);
}
Note you probably have to do a bit more for compositing the filename.

Image is multiplied three times in OpenCV, what causes this?

I have one gray scale image which is just the R channel of a photo, now I'm trying to write that R channel into a new image, which is an RGB image. Ideally, the new image would look just like the old image, but red.
What happens though is that in the new image, the old image appears three times squished next to each other.
Here you can see the gray scale image and the output image.
Here is my code, I think it's pretty straightforward:
Mat img_in = imread("in.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_out = Mat::zeros(img_in.size(), CV_8UC3);
for (int i = 0; i < img_in.rows; i++)
{
for (int j = 0; j < img_in.cols; j++)
{
img_out.at<Vec3b>(i,j)[2] = img_in.at<Vec3b>(i,j)[2];
}
}
imwrite("test_img_in.png", img_in);
imwrite("test_img_out.png", img_out);
At first I thought it was some kind of indices mixup, but I've tried a lot of combinations, and it always multiplies the output image three times horizontally, never vertically.
Now my thought is that it comes from some OpenCV specification, like the CV_8UC3 type (I've tried others too), which I've chosen because I think it support RGB images. Unfortunately, I don't know too much about OpenCV itself, that's why I'm seeking help here.
PS: This is part of a whole bigger program which wants to generate a color image from three gray scale channel images, but I'm currently stuck on combining the aligned gray scale images, since this happens. The code I posted is isolated from the rest of the program and works like this on its own.
My OpenCV version is 2.4.11.
The problem is here:
img_out.at<Vec3b>(i,j)[2] = img_in.at<Vec3b>(i,j)[2];
As you said the input image is gray. So, just use:
img_out.at<Vec3b>(i,j)[2] = img_in.at<unsigned char>(i,j);
you will get the same result by loading your image as 3 channel and subtract Scalar(255,255,0)
#include <opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char **argv)
{
Mat src = imread(argv[1]);
imshow("src", src );
src -= Scalar(255,255,0);
imshow("Red channel", src );
waitKey();
return 0;
}

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

Create mask from color Image in C++ (Superimposing a colored image mask)

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.