How to convert an image with 16 bit integers into a QPixmap - c++

I am working with software that has a proprietary image format. I need to be able to display a modified version of these images in a QT GUI. There is a method (Image->getpixel(x,y)) that returns a 16 bit integer (16 bits per pixel). To be clear, the 16 bit number does not represent an RGB color format. It literally represents a measurement or dimension to that particular point (height map) on the part that is being photographed. I need to take the range of dimensions (integers) in the image and apply a scale to be represented in colors. Then, I need to use that information to build an image for a QPixmap that can be displayed in a Qlabel. Here is the general gist...
QByteArray Arr;
unsigned int Temp;
for (int N = 0; N < Image->GetWidth(); N++) {
for (int M = 0; M < Image->GetHeight(); M++) {
Temp = Image.GetPixel(N,M);
bytes[0] = (Temp >> 8) & 0xFF;
bytes[1] = Temp & 0xFF;
Arr.push_back(bytes[0]);
Arr.push_back(bytes[1]);
}
}
// Take the range of 16 bit integers. Example (14,982 to 16,010)
// Apply a color scheme to the values
// Display the image
QPixmap Image2;
Image2.loadFromData(Arr);
ui->LabelPic->setPixmap(Image2);
Thoughts?
This screenshot is an example of what I am trying to replicate. It is important to note that the coloration of the image is not inherent to the underlying data in the image. It is the result of an application scaling the height values and applying a color scheme to the range of integers.

The information on proprietary image format is limited so the below is guess or thought (as requested) according to explanation above:
QImage img(/*raw image data*/ (const uchar*) qbyteArr.data(),
/*columns*/ width, /*height*/ rows,
/*bytes per line*/ width * sizeof(uint16),
/*format*/ QImage::Format_RGB16); // the format is likely matching the request
QPixpam pixmap(img); // if the pixmap is needed

I found pieces of the answer here.
Algorithm to convert any positive integer to an RGB value
As for the actual format, I chose to convert the 16 bit integer into a QImage::Format_RGB888 to create a heat map. This was accomplished by applying a scale to the range of integers and using the scale to plot different color equations.

Related

can't access pixel intensities in image using cimg (returns 0)

I'm tries to access Cimg pixel values to print out the pixel intensity that my mouse is at, as well as calculating a histogram. However, I got all zeros from Cimg object.
The cimg image is initiated from memory buffer and it is 12 bit gray scale image, but padded to 16 bit to save in memory.
The code below is defined in a function that is called multiple times. I want to refresh the images in the current display and not to produce a new one every time the function is called. So the Cimgdisp is defined outside the function.
#include "include\CImg.h"
int main(){
CImg <unsigned short> image(width,height,1,1);
CImgDisplay disp(image);
//showImg() get called multiple times here
}
void showImg(){
unsigned short* imgPtr = (unsigned short*) (getImagePtr());
CImg <unsigned short> img(imgPtr,width,height);
img*=(65535/4095);//Renormalise from 12 bit input to 16bit for better display
//Display
disp->render(img);
disp->paint();
img*=(4095/65535);//Normalise back to get corect intensities
CImg <float> hist(img.histogram(100));
hist.display_graph(0,3);
//find mouse position and disp intensity
mouseX = disp->mouse_x()*width/disp->width();//Rescale the position of the mouse to true position of the image
mouseY = disp->mouse_y()*height/disp->height();
if (mouseX>0&mouseY>0){
PxIntensity = img(mouseX,mouseY,0,0);}
else {
PxIntensity = -1;}
}
All the intensities I retrieve are zero and the histogram is also zero.
img*=(4095/65535);//Normalise back to get corect intensities is incorrect, as (4095/65535)=0 in C/C++ (division of an integer by a larger one).
Maybe img*=(4095/65535.); ?
If you just want to scale between 12-bit and 16-bit and back then just using bit-shifts might be better.
img<<=4;//Renormalise from 12 bit input to 16bit for better display
//Display
disp->render(img);
disp->paint();
img>>=4;//Normalise back to get corect intensities

OpenCV image analysis on 32x32 image sections?

Im trying to divide a passed in, 1920x1080, gray scaled image and divide it into 32x32 "blocks" or "sections". Sort of like an imaginary, overlay grid.
Once this is done, I need to loop through each pixel in each individual section to perform analysis on the single channel, gray scale value that is returned by each pixel.
For example:
//For block (x,y):
if (pixelVal >= 120 && pixelVal <= 130) {
bitStream += "1";
} else if (pixelVal >= 135 && pixelVal <= 140) {
bitstream += "0";
} else {
bitStream += "X";
}
Does this make sense? I'm very new to OpenCV and C++ and basically I know how to show, loop through, and return the pixel value at a given point, just not within a certain, predetermined area. I asked a similar question the other day but it was for thresholding, not the single channel value. Im thinking about creating some sort of window that loops through and with each window, the pixel values within are compared using the conditionals I have above.
Since the value of gray scale pixels is already defined from 0-255, so you may create an array of size 256 and pre-fill that array with "0", "1" and "x" as per your conditions. This lookup table would later help you to substitute values very efficiently. This technique is used internally by OpenCV methods such as cv::threshold.
Then you may crop the image using cv::Mat cropped = bigger_mat(rect), where bigger_mat is 1920x1080 dimension matrix and rect is cv::Rect(x, y, w, h) object which defined the position and size for cropping.
Then you can loop each of the cropped mats' using two nested for loops for rows and columns and access each pixel using img.at<uchar>(j,i). For each value retrieved you can use the above created look-up array to get the substitution and append to your bitstream.

OpenCV - RGB Channels in Float Data Type and Intensity Range within 0-255

How can I achieve the values of the RGB channels as
Float data type
Intensity range within 0-255
I used CV_32FC4 as the matrix type since I'll perform floating-point mathematical operations to implement Daltonization. I was expecting that the intensity range is the same with the intensity range of the RGB Channels in CV_8UC3, just having a different data type. But when I printed the matrix I noticed that the intensities of the channels are not within 0-255. I realized that it due to the range of the float matrix type.
Mat mFrame(height, width, CV_32FC4, (unsigned char *)pNV21FrameData);
for(int y = 0 ; y < height ; y++){
for(int x = 0 ; x < width ; x++){
Vec4f BGRA = mFrame.at<Vec4f>(y,x);
// Algorithm Implementation
mFrame.at<Vec4f>(y,x) = BGRA;
}
}
Mat mResult;
mFrame.convertTo(mResult, CV_8UC4, 1.0/255.0);
I need to manipulate the pixels like BGRA[0] = BGRA[0] * n; then assign it back to the matrix.
By your comments and the link in it I see that the data comes in BGRA. The data is in uchar.
I assume this from this line:
Mat mResult(height, width, CV_8UC4, (unsigned char *)poutPixels);
To solve this you can create the matrix and then convert it to float.
Mat mFrame(height, width, CV_8UC4, (unsigned char *)pNV21FrameData);
Mat mFloatFrame;
mFrame.convertTo(mFloatFrame, CV_32FC4);
Notice that this will keep the current ranges (0-255) if you need another one (like 0-1) you may put the scaling factor.
Finally you can convert back, but beware that this function does saturate_cast. If you have an specific way you want to manage the overflow or the decimals, you will have to do it before converting it.
Mat mResult;
mFloatFrame.convertTo(mResult, CV_8UC4);
Note that 1.0/255.0 is not there, since the data is already in the range of 0-255 (at least before the operations).
One final comment, the link in your comments use IplImage and other old C (deprecated) versions of OpenCv. If you are working in c++, stick to the c++ versions like Mat. This is not in the code you show here, but in the you linked. This comment is more for you to avoid future headaches.

Converting float to unsigned char causes wrong values

I've created a function that creates a BMP image using RGB values.
The RGB values are stored as floats that range from 0.0 to 1.0.
When writing the values to the BMP file they need to range from 0 to 255.0 so I multiply the floats by 255.0
They also need to be unsigned chars.
EDIT: Unless one of you can think of a better type.
So basically what I do is this
unsigned char pixel[3]
//BMP Expects BGR
pixel[0] = image.b*255.0;
pixel[1] = image.g*255.0;
pixel[2] = image.r*255.0;
fwrite(&pixel, 1, 3, file);
Where image.r is a float.
There seems to be some kind of loss of data in the conversion because some parts of the image are black when they shouldn't be.
The BMP image is set to 24 bits per pixel
I was going to post images but I don't have enough reputation.
edit:
BMP image
http://tinypic.com/r/2qw3cdv/8
Printscreen
http://tinypic.com/r/2q3rm07/8
Basically light blue parts become black.
If I multiply by 128 instead the image is darker but otherwise accurate. It starts getting weird around 180 ish

Image Processing How to Apply gradient [-1 | 0 | 1 ] to RGB image

I need to apply gradient operator to RGB bitmap image. It works for 8 bit image but having the difficulty in implementing same for 24 bit image. Here is my code. Can anyone see how
to correct the zorizontal gradient operation to RGB image.
if (iBitPerPixel == 24) ////RGB 24 bits image
{
for(int i=0; i<iHeight; i++)
for(int j=1; j<iWidth-4; j++)
{
//pImg_Gradient[i*Wp+j] = pImg[i*Wp+j+1] - pImg[i*Wp+j-1] ;
int level = pImg[i*Wp+j*3+1] - pImg[i*Wp+j*3-1] ;
pImg_Gradient[i*Wp+j*3] = level;
// pImg_Gradient[i*Wp+j*3] = level;
// pImg_Gradient[i*Wp+j*3+1] = level;
// pImg_Gradient[i*Wp+j*3+2]= level;
}
for(int i=0; i<iHeight; i++)
for(int j=0; j<iWidth; j++)
{
// Copy the convetred values to original image.
pImg[i*Wp+j] = (BYTE) pImg_Gradient[i*Wp+j];
}
//delete pImg_Gradient;
}
Unfortunately, it is not clear how to define a gradient of an RGB image. The best way to go is to transform the image into a color space that separates intensity from color, such as HSV, and compute the gradient of the intensity component. Alternatively, you can compute the gradient of each color channel separately, and then combine the results in some way, such as taking the average.
Also see Edge detectors for RGB images?
In order to calculate the Gradient of an image (Which is a vector) you need to calculate both the horizontal and vertical derivative of the image.
Since we're dealing with a discrete image we should use Finitie Difference approximations of the derivative.
There are many ways to approximate, many of them are listed on the Wikipedia Pages:
http://en.wikipedia.org/wiki/Finite_difference
http://en.wikipedia.org/wiki/Finite_difference_method
http://en.wikipedia.org/wiki/Finite_difference_coefficients
Basically those are Spatial Coefficients hence you can define a filter using them and just filter the image.
This would be the most efficient way to calculate the gradient.
So, all you need is to find a library (Such as Open CV) which supports filtering images and you're done.
For color images, usually, you just calculate the Gradient per Color Channel.
Good Luck.
From your code; you are trying to calculate gradient from RGB but there is nothing to indicate how RGB is stored in your image. A complete guess is that in your image you have BGRBGRBGR...etc.
In that case your code is getting the gradient from the green channel, then storing it in the red of the gradient image. You don't show the gradient image being cleared to 0 - if you don't do this then it will probably be full of junk.
My suggestion is to convert to a greyscale image first; then you can use your original code.
Or calculate a gradient for each colour channel.