how to display a Mat in Opencv - c++

For the mat which stores images, it is easy to show it using imshow.But if the data type of the Mat is CV_32FC1, how can I display this mat ?
I tried imshow, but the display figure is totally white and when I zoom int, it is still totally blank, and I cannot see the float numbers in mat.
Is there anyone who knows how to show entire mat matrix ?
p.s.: thanks for replying. I will post some codes and figures to show more details:
codes:
Mat mat1;
mat1 = Mat::ones(3,4,CV_32FC1);
mat1 = mat1 * 200;
imshow("test", mat1);
waitKey(0);
Mat dst;
normalize(mat1, dst, 0, 1, NORM_MINMAX);
imshow("test1", dst);
waitKey(0);
mat1.convertTo(dst, CV_8UC1);
imshow("test2", dst);
waitKey(0);
return 0;
output:
after I zoom in by 150%:
Then after I zoom in by 150%, we can see that 'test' is totally white and we cannot see its element values. 'test1' is totally black and we still cannot see its element values. But for 'test2', it is gray and we can see its element value which is 200.
Does this experiment mean that imshow()can only show CV_8UC1 and we cannot show any other datatyes ?

If image is a Mat of type CV_32F, If the image is 32-bit floating-point, imshow() multiplies the pixel values by 255 - that is, the value range [0,1] is mapped to [0,255].
So your floating point image has to have a range 0 .. 1.
This will display a CV32F image, no matter what the range is:
cv::Mat dst
cv::normalize(image, dst, 0, 1, cv::NORM_MINMAX);
cv::imshow("test", dst);
cv::waitKey(0);

Related

Opencv C++ grayscale image black pixeled result (when replacing image values)

I'm new in opencv and I had this problem...
Given the following Mat type (globally declarated)
Mat src_gray;
Mat dst;
I have dst being a zero grayscale Mat with this initialization
dst=Mat::zeros(src_gray.size(), CV_BGR2GRAY);
It seems I can't edit the pixels on the dst image (when I use imwrite, it gives me a black image as if I hadn't done anything).
This is the code I currently have:
for(int i=0;i<=dst.cols;i++)
for(int j=0;j<=dst.rows;j++)
{
dst.at<uchar>(j,i)=255;
}
imwrite( "img_res.png", dst );
The result Image has the dimensions it's supposed to have, but it is a black pixeled picture, shouldn't it be a white pixeled Image?
I don't know if it is relevant if I mention that I have 3 global Mats
Mat image;
Mat src_gray;
Mat dst;
Which are initialized this way:
image = imread( argv[1], 1 );
cvtColor( image, src_gray, CV_BGR2GRAY );
Then, I release them as:
image.release();
dst.release();
src_gray.release();
The other problem I get is that when I release the Mats (during execution), I get the "Segmentation fault (core dumped)" error. (I code from Linux Ubuntu distri)
Try:
dst=Mat::zeros(src_gray.size(), CV_8UC1);
When you use CV_BGR2GRAY, you are creating a Mat with 3 color channels, then, it's not possible to assign a number when you have an array of numbers (B,G,R).
With CV_8UC1, you create a Mat with 1 color channel of uchar then it should works with:
dst.at<uchar>(j,i)=255;

How to display PGM image using OpenCV

I'm trying to load and display a .PGM image using OpenCV(2.4.0) for C++.
void open(char* location, int flag, int windowFlag)
{
Mat image = imread(location, flag);
namedWindow("Image window", windowFlag);
imshow("Image window", image);
waitKey(0);
}
I'm calling open like this:
open("./img_00245_c1.pgm", IMREAD_UNCHANGED, CV_WINDOW_AUTOSIZE);
The problem is that the image shown when the window is opened is darker than if I'm opening the file with IrfanView.
Also if I'm trying to write this image to another file like this:
Mat imgWrite;
imgWrite = image;
imwrite("newImage.pgm", imgWrite)
I will get a different file content than the original one and IrfanView will display this as my function displays with imshow.
Is there a different flag in imread for .PGM files such that I can get the original file to be displayed and saved ?
EDIT: Image pgm file
EDIT 2 : Remarked that: IrfanView normalizes the image to a maximum pixel value of 255 .
In order to see the image clearly using OpenCV I should normalize the image also when loading in Mat. Is this possible directly with OpenCV functions without iterating through pixels and modifying their values ?
The problem is not in the way data are loaded, but in the way they are displayed.
Your image is a CV_16UC1, and both imshow and imwrite normalize the values from original range [0, 65535] to the range [0, 255] to fit the range of the type CV_8U.
Since your PGM image has max_value of 4096:
P2
1176 640 // width height
4096 // max_value
it should be normalized from range [0, 4096] instead of [0, 65535].
You can do this with:
Mat img = imread("path_to_image", IMREAD_UNCHANGED);
img.convertTo(img, CV_8U, 255.0 / 4096.0);
imshow("Image", img);
waitKey();
Please note that the values range in your image doesn't correspond to [0, 4096], but:
double minv, maxv;
minMaxLoc(img, &minv, &maxv);
// minv = 198
// maxv = 2414
So the straightforward normalization in [0,255] like:
normalize(img, img, 0, 255, NORM_MINMAX);
img.convertTo(img, CV_8U);
won't work, as it will produce an image brighter than it should be.
This means that to properly show your image you need to know the max_value (here 4096). If it changes every time, you can retrieve it parsing the .pgm file.
Again, it's just a problem with visualization. Data are correct.

How to show the vector<Point2f> as a image?

I just start to learn opencv, I have defined a vector like:
vector<Point2f> cornersB;
and after that i have done some calculations like:goodFeaturesToTrack,cornerSubPix and calcOpticalFlowPyrLK using cornersB.
And now I want to show cornerB to see the points that has been drawn, my code is:
pointmat = Mat(cornersB);
imshow("Window", pointmat);
But I got error said that bad number of channels (Source image must have 1, 3 or 4 channels) in cvConvertImage.
Anyone can teach me how to show the points of cornerB in an image?
I just want to see the points (points in white and the background in black).
The simpler is to use cv::drawKeypoints
drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, InputOutputArray outImage,const Scalar& color=Scalar::all(-1), int flags=DrawMatchesFlags::DEFAULT );
In your case, let define a black image as image:
cv::Mat image(512,512,CV_8U)
image.setTo(0);
Then convert cornersB to cv::KeyPoint kp_cornerB and define the color as white with CV_RGB(255, 255, 255)
std::vector<cv::KeyPoint> kp_cornerB ;
// TODO convert cornersB to kp_cornerB
cv::Mat pointmat;
cv::drawKeypoints(image, kp_cornerB, pointmat, CV_RGB(255, 255, 255));
imshow("Window", pointmat);
The conversion can be done with a for loop on the vector:
for(vector<Point2f>::const_iterator it = cornersB.begin();
it != cornersB.end(); it++) {
cv::KeyPoint kp(*it, 8);
kp_cornerB.push_back(kp);
}
Here, the value '8' is the 'size' of the keypoint.

Getting masked area to be transparent?

So far i have managed to use masks and get the second image from the first. But what i want is the black area in second image to be transparent (i.e the output i an trying to get is the third image) Here is the code so far. Please advice me on this.
EDIT: Third one is from photoshop
//imwrite parameters
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(100);
//reading image to be masked
image = imread(main_img, -1);
//CV_LOAD_IMAGE_COLOR
namedWindow("output", WINDOW_NORMAL);
//imshow("output", image);
//Creating mask image with same size as original image
Mat mask(image.rows, image.cols, CV_8UC1, Scalar(0));
// Create Polygon from vertices
ROI_Vertices.push_back(Point2f(float(3112),float(58)));
ROI_Vertices.push_back(Point2f(float(3515),float(58)));
ROI_Vertices.push_back(Point2f(float(3515),float(1332)));
ROI_Vertices.push_back(Point2f(float(3112),float(958)));
approxPolyDP(ROI_Vertices, ROI_Poly, 1, true);
// Fill polygon white
fillConvexPoly(mask, &ROI_Poly[0] , ROI_Poly.size(), 255, 8, 0);
//imshow("output", mask);
// Create new image for result storage
imageDest = cvCreateMat(image.rows, image.cols, CV_8UC4);
// Cut out ROI and store it in imageDest
image.copyTo(imageDest, mask);
imwrite("masked.jpeg", imageDest, compression_params);
imshow("output", imageDest);
cvWaitKey(0);
This can be done by first setting its alpha value to 0 of the regions that you want to make them fully transparent (255 for others), and then save it to PNG.
To set the alpha value of pixel-(x,y), it can be done:
image.at<cv::Vec4b>(y, x)[3] = 0;
PS: you need to convert it to 4-channel format first if the image is not currently. For example:
cv::cvtColor(image, image, CV_BGR2BGRA);
Updated: It will be easier if you have already computed the mask for the ROI region, where you can simply merge it with the original image (assume having 3 channels) to get the final result. Like:
cv::Mat mask; // 0 for transparent regions, 255 otherwise (serve as the alpha channel)
std::vector<cv::Mat> channels;
cv::split(image, channels);
channels.push_back(mask);
cv::Mat result;
cv::merge(channels, result);

How to get cv::calcOpticalFlowSF to work?

I am useing the 2.4.4 version of OpenCV. - i know its a beta
but there is an example about cv::calcOpticalFlowSF the method in the example folder called: simpleflow_demo.cpp. But when i copy this demo and use it with my input images, it starts processing and after some seconds it came back a crash report.
The documentation about the method is a little bit strange, saying the output files are a x- and yflow instead of the cv::Mat& flow which the method actually wants.
Any ideas how to fix the problem to get the function working?
Try this simple demo that worked for me, then modify for your needs (display help from here):
Mat frame1 = imread("/home/radford/Desktop/1.png");
Mat frame2 = imread("/home/radford/Desktop/2.png");
namedWindow("flow");
Mat flow;
calcOpticalFlowSF(frame1, frame2, flow, 3, 2, 4);
Mat xy[2];
split(flow, xy);
//calculate angle and magnitude
Mat magnitude, angle;
cartToPolar(xy[0], xy[1], magnitude, angle, true);
//translate magnitude to range [0;1]
double mag_max;
minMaxLoc(magnitude, 0, &mag_max);
magnitude.convertTo(magnitude, -1, 1.0/mag_max);
//build hsv image
Mat _hsv[3], hsv;
_hsv[0] = angle;
_hsv[1] = Mat::ones(angle.size(), CV_32F);
_hsv[2] = magnitude;
merge(_hsv, 3, hsv);
//convert to BGR and show
Mat bgr;//CV_32FC3 matrix
cvtColor(hsv, bgr, COLOR_HSV2BGR);
imshow("flow", bgr);
waitKey(0);
In the example opencv/samples/cpp/simpleflow_demo.cpp there is a code block
if (frame1.type() != 16 || frame2.type() != 16) {
printf(APP_NAME "Images should be of equal type CV_8UC3\n");
exit(1);
}
So, grey images should be converted to CV_8UC3. For example using cvtColor(grey, grey3, CV_GRAY2RGB);