Loading 12-Bit Raw GreyScale Image using Opencv - c++

I'm working with opencv 2.4.9. I would like to load a 12-Bit grey scale raw(.raw) image stored as Y16(16-Bit) format.This format contains only a single, 16 bit Y plane for monochrome images. Each pixel is represented by a 16 bit, little endian format.
I used the following code for loading the image.
Mat Img_Source16Bit_Gray(m_ImgWidth,m_ImgHeight,CV_16UC1);
Mat Img_Destination8Bit_Gray;
FILE * f;
f=fopen(FileName_S.c_str(),"rb");
if ( !f )
{
MessageBox(L"File Not Found");
return;
}
uchar* Pixels_Char_16Bit;
Pixels_Char_16Bit = new uchar[m_ImgWidth * m_ImgHeight *2];
fread(Pixels_Char_16Bit,m_ImgWidth * m_ImgHeight*2,1,f);
fclose(f);
Img_Source16Bit_Gray.data= Pixels_Char_16Bit;
Img_Source16Bit_Gray.convertTo(Img_Destination8Bit_Gray,CV_8UC1,1);
imshow("Img_Source16Bit_Gray",Img_Source16Bit_Gray);
imshow("Img_Destination8Bit_Gray",Img_Destination8Bit_Gray);
Actual image is shown in the right side & the output left hand side I'm getting is not correct & the Result8 bit image is full of white pixels. Can anyone please provide me the steps to load a 16 Bit grey scale image?

Thank you for helping me to find the answer! Here is my updated code.
Mat Img_Source16Bit_Gray(m_ImgHeight,m_ImgWidth,CV_16UC1);
Mat Img_Destination8Bit_Gray(m_ImgHeight,m_ImgWidth,CV_8UC1);
FILE * f;
f=fopen(FileName_S.c_str(),"rb");
if ( !f )
{
MessageBox(L"File Not Found");
return;
}
char16_t* pY16Pixels;//w-2592 h- 1944
pY16Pixels = new char16_t[m_ImgWidth * m_ImgHeight];
fread(pY16Pixels,m_ImgWidth*m_ImgHeight*2,1,f);
Img_Source16Bit_Gray.data= reinterpret_cast<uchar*>(pY16Pixels);
double minVal, maxVal;
minMaxLoc(Img_Source16Bit_Gray, &minVal, &maxVal); //find minimum and maximum intensities
Img_Source16Bit_Gray.convertTo(Img_Destination8Bit_Gray, CV_8U, 255.0/(maxVal - minVal), -minVal * 255.0/(maxVal - minVal));
namedWindow("Img_Source16Bit_Gray",WINDOW_NORMAL);
namedWindow("Img_Destination8Bit_Gray",WINDOW_NORMAL);
imshow("Img_Source16Bit_Gray",Img_Source16Bit_Gray);
imshow("Img_Destination8Bit_Gray",Img_Destination8Bit_Gray);

Related

Understanding why it doesn't copy correctly using memcpy

I have some misunderstanding about OpenCV 4.1.0 and memcpy in C++. The question is why the image is zoomed in a lot?
I read an image like this:
Mat img = imread("lena512.bmp", 1); // Black and White Image
namedWindow("Display window", WINDOW_AUTOSIZE);
imshow("Display window", img);
After this I have 2 byte array:
int inputSize = width * height * channels;
byte* pixels = new byte[width * height * channels];
byte* out = new byte[width * height * channels];
I copy the img to pixels array:
memcpy(pixels, img.data, inputSize * sizeof(byte));
And then I want to check if retrieving image is the same as input:
Mat image = Mat(width, height , CV_8U);
memcpy(image.data, out, inputSize * sizeof(byte));
Mat img = imread("lena512.bmp", 1); // Black and White Image
That's the problem, the comment is a lie, and by using a magic number instead of a named constant, you can't easily tell that's the case. 1 in this context means IMREAD_COLOR -- i.e. the image is always read as a 3 channel BGR image.
However, after the shenanigans with memcpy and raw pointers, you create new Mat in the following manner:
Mat image = Mat(width, height , CV_8U);
Note that CV_8U is equivalent to CV_8UC1. Hence, you create a single channel (grayscale) Mat, but give it 3-channel data.
Getting garbage as a result is the lesser issue. The much more serious issue is that you copy 3x as much data as the target pixel buffer can hold -- basically you clobber half a megabyte of memory that doesn't belong to the Mat. That can either end with a segfault, or some really hard to find bugs (in case you overwrite some memory used by other data structures).
Update: There's another issue that I've missed (thanks to #Micka for catching that). The order of parameters of the cv::Mat constructor is rows, columns, datatype. It appears you switched width and height, although since your input image appears to be square (i.e. width == height) it didn't matter.
The correct way to allocate the second Mat would be
Mat image = Mat(height, width, CV_8UC3);

OpenCV: PNG image with alpha channel

I'm new to OpenCV and I've done a small POC for reading an image from some URL.
I'm reading the image from an URL using video capture. The code is as follows:
VideoCapture vc;
vc.open("http://files.kurento.org/img/mario-wings.png");
if(vc.isOpened() && vc.grab())
{
cv::Mat logo;
vc.retrieve(logo);
cv::namedWindow("t");
imwrite( "mario-wings-opened.png", logo);
cv::imshow("t", logo);
cv::waitKey(0);
vc.release();
}
This image is not opened correctly, possibly due to alpha channel.
What is the way to preserve alpha channel and get the image correctly?
Any help is appreciated.
-Thanks
Expected output
Actual output
if you are only loading an image, I recommend you to use imread instead, also, you will need to specified the second parameter of imread to load the alpha channel too, that is CV_LOAD_IMAGE_UNCHANGED or cv::IMREAD_UNCHANGED, depending on the version (in the worst case a -1 also works).
As far as I know, the VideoCaptureclass do not load images/video with a 4th channel. Since you are using a web url, loading the image won't work with imread, but you may use any method to download the data (curl for example) and then use imdecode with the data buffer to get the cv::Mat. OpenCV is a library for image processing, not for downloading images.
If you wanna draw it over another image you can do that:
/**
* #brief Draws a transparent image over a frame Mat.
*
* #param frame the frame where the transparent image will be drawn
* #param transp the Mat image with transparency, read from a PNG image, with the IMREAD_UNCHANGED flag
* #param xPos x position of the frame image where the image will start.
* #param yPos y position of the frame image where the image will start.
*/
void drawTransparency(Mat frame, Mat transp, int xPos, int yPos) {
Mat mask;
vector<Mat> layers;
split(transp, layers); // seperate channels
Mat rgb[3] = { layers[0],layers[1],layers[2] };
mask = layers[3]; // png's alpha channel used as mask
merge(rgb, 3, transp); // put together the RGB channels, now transp insn't transparent
transp.copyTo(frame.rowRange(yPos, yPos + transp.rows).colRange(xPos, xPos + transp.cols), mask);
}

Create a transparent image in opencv

I am trying to rotate an image in x, y and z axis as in this.
The image should not be cropped while rotating So I am doing this
Mat src = imread("path");
int diagonal = (int)sqrt(src.cols*src.cols+src.rows*src.rows);
int newWidth = diagonal;
int newHeight =diagonal;
Mat targetMat(newWidth, newHeight, src.type());
I am creating a bigger image targetMat. The input image is a png image.
But I want this image as a transparent image. So I tried this
Mat targetMat(newWidth, newHeight, src.type(), cv::Scalar(0,0,0,0));
But the output image was
What I need is (Transparent image is here)
So what change do I have to do?
The problem is, that your input image is type CV_8UC3 but you need CV_8UC4 to use the alpha channel. So try Mat targetMat(newHeight, newWidth, CV_8UC4, cv::Scalar(0,0,0,0)); or cvtColor of src before creation of new mat
To use your original image, there are two possibilities:
use cv::cvtColor(src, src, CV_BGR2BGRA) (and adjust later code to use a 4 channel matrix - cv::Vec4b instead of cv::Vec3b etc)
if your input file is a .png with alpha channel you can use the CV_LOAD_IMAGE_ANYDEPTH (hope this is the right one) flag to load it as a CV_xxC4 image (might be 16 bit too) and to use the original alpha values.

Convert jpg image in ppm P3 ASCII format using Opencv

Using opencv imwrite function I managed to convert jpg image in ppm P6 format.
Mat image = imread(picPath);
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_PXM_BINARY);
compression_params.push_back(1);
imwrite("bez.ppm", image, compression_params);
Problem is that I actually have to convert jpg image in ppm P3 ASCII format.
Does anyone know how to do it?
Thanks!
EDIT:
In the project I have the following piece of code where I check the maximum value of pixels:
int maxVal;
fscanf(in, "%d", &maxVal);
if (maxVal != 255)
{
printf("Input file error: Not a Netpbm color image with 256 levels\n");
exit(0);
}
When I set parameter 0 then I get: Not a Netpbm color image with 256 levels!
When I do the conversion from jpg to ppm p3 with irfanview program works.
The code involved is in the file modules/imgcodecs/src/grfmt_pxm.cpp in the OpenCV source tree.
It sets the internal flag isBinary like this according to the compression parameters:
for( size_t i = 0; i < params.size(); i += 2 )
if( params[i] == CV_IMWRITE_PXM_BINARY )
isBinary = params[i+1] != 0;
so, if you want ASCII (P3) you need to have
compression_params.push_back(0)
and have image type CV_8UC1, CV_8UC3 or CV_16UC1.

Count the black pixels using OpenCV

I'm working in opencv 2.4.0 and C++
I'm trying to do an exercise that says I should load an RGB image, convert it to gray scale and save the new image. The next step is to make the grayscale image into a binary image and store that image. This much I have working.
My problem is in counting the amount of black pixels in the binary image.
So far I've searched the web and looked in the book. The method that I've found that seems the most useful is.
int TotalNumberOfPixels = width * height;
int ZeroPixels = TotalNumberOfPixels - cvCountNonZero(cv_image);
But I don't know how to store these values and use them in cvCountNonZero(). When I pass the the image I want counted from to this function I get an error.
int main()
{
Mat rgbImage, grayImage, resizedImage, bwImage, result;
rgbImage = imread("C:/MeBGR.jpg");
cvtColor(rgbImage, grayImage, CV_RGB2GRAY);
resize(grayImage, resizedImage, Size(grayImage.cols/3,grayImage.rows/4),
0, 0, INTER_LINEAR);
imwrite("C:/Jakob/Gray_Image.jpg", resizedImage);
bwImage = imread("C:/Jakob/Gray_Image.jpg");
threshold(bwImage, bwImage, 120, 255, CV_THRESH_BINARY);
imwrite("C:/Jakob/Binary_Image.jpg", bwImage);
imshow("Original", rgbImage);
imshow("Resized", resizedImage);
imshow("Resized Binary", bwImage);
waitKey(0);
return 0;
}
So far this code is very basic but it does what it's supposed to for now. Some adjustments will be made later to clean it up :)
You can use countNonZero to count the number of pixels that are not black (>0) in an image. If you want to count the number of black (==0) pixels, you need to subtract the number of pixels that are not black from the number of pixels in the image (the image width * height).
This code should work:
int TotalNumberOfPixels = bwImage.rows * bwImage.cols;
int ZeroPixels = TotalNumberOfPixels - countNonZero(bwImage);
cout<<"The number of pixels that are zero is "<<ZeroPixels<<endl;