I've an image loaded in a Mat
. From this, I calculate the DFT, so in a new Mat I've the DFT stored (both the real and img. parts).
Since here, I aim to draw the magnitude of the DFT. I've achieved this already with OpenCV, by calculating it, take it to the range 0 - 1
and show it with imshow
.
However, now I'm working with winform, so I need to convert my image to bitmap
in order to draw it in a PictureBox
.
I've also achieved to draw some kinds of images in it, using for example:
private: void DrawCVImageGrayScale(System::Windows::Forms::Control^ control, cv::Mat& colorImage) {
System::Drawing::Graphics^ graphics = control->CreateGraphics();
System::IntPtr ptr(colorImage.ptr());
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(colorImage.cols,colorImage.rows,colorImage.step,System::Drawing::Imaging::PixelFormat::Format8bppIndexed,ptr);
System::Drawing::RectangleF rect(0,0,control->Width,control->Height);
graphics->DrawImage(b,rect);
}
I was able to draw a CV_8UC1 into the control (PictureBox). But I've no achieved to draw my CV_32FC1 into it.
I had tried with several possibilities, but I think the problem is this one: Since my image is CV_32FC1, and bitmap has no pixelFormat with this configuration, I would need to convert it first.
What have I exactly done?
I've scaled my CV_32FC1 Mat, to ensure values in the 16b range (magI
is my magnitude Mat):
// Ahora lo llevamos de 0 a 255
double OldMax, OldMin;
double NewMax = 65535, NewMin=0;
minMaxLoc(magI, &OldMin, &OldMax);
double OldRange = (OldMax - OldMin);
double NewRange = (NewMax - NewMin);
magI = (((magI - OldMin) * NewRange) / OldRange) + NewMin;
Mat_<unsigned short int> resultado(magI.size());
for(int i = 0; i < magI.rows; i++)
{
for(int j = 0; j < magI.cols; j++)
{
float grayPixel = magI.at<float>(i, j);
resultado.at<unsigned short int>(i, j) = grayPixel;
}
}
I've checked that unsigned short int
has 2 bytes as size, in order to match with 16b from Format16bppGrayScale
pixelFormat. But when I try this combination (yes, If I choose another pixelFormat, it paints a nonsense, but it paints) I get a:
A generic error occurred in GDI+
To finalize, I post here my result with Format16bppRgb555
.
The problem is, that my magnitude is in a CV_16UC1 (since I created a Mat_<unsigned short int>
), so to choose Format16bppRgb555
makes no sense, even if it appears to be near to the good result.
Any idea about it would be appreciated!
Thanks you in advance
EDIT: I've been thiking that with Format16bppRgb555
it's painting only the first channel (the only one I've, B-GR) so the result is exactly what I want, but in blue channel...
EDIT 2 (EDIT 5: you can jump from here to EDIT 5): I've tried what @BoykoPerfanov has told me, which translated to C++ code is:
cv::Mat adaptada(Image.size(), CV_16UC3);
uint16_t* pixelPtr = (uint16_t*) Image.data;
uint16_t* pixelPtrDest = (uint16_t*) adaptada.data;
for(int i = 0; i < Image.rows; i++)
{
for(int j = 0; j < Image.cols; j++)
{
float src_pixelval = pixelPtr[Image.channels()*(Image.cols*i + j)];
uint16_t conv = cvRound(src_pixelval * 32); //converted value to integral 5-bit type
pixelPtrDest[adaptada.channels()*(adaptada.cols*i + j)] = (conv<<0 | (conv<<5) | (conv<<10));
}
}
Now, when I paint it, I get:
So I guess I've not understood it well, or I'm missing something at coding time..
EDIT 3: Since my Mat is CV_32F
, I've noticed my declaration:
uint16_t * pixelPtr = (uint16_t *) colorImage.data;
Was wrong, and changed it to uint32_t
, same as src_pixelval
type. Now my result is:
EDIT 4 (oh my god): I realized that I had not changed the painting step from the bitmap to the new Mat, so changed that line to:
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(adaptada.cols,adaptada.rows,adaptada.step,System::Drawing::Imaging::PixelFormat::Format16bppRgb555 ,ptr);
Now I get (resized a bit this time):
EDIT 5: I've coded again the function to get the values, painting it as a Format48bppRgb
, where each 16b are my 16b original values from my CV_32FC1
Mat. I guess my problem now is just that overflow, and I must normalize that values, cause I got the same problem when painting it in OpenCV (that the magnitude seems inverted black/white). Let's see code and results:
cv::Mat adaptada(colorImage.size(), CV_16UC3);
uint32_t * pixelPtr = (uint32_t *) colorImage.data;
uint16_t* pixelPtrDest = (uint16_t*) adaptada.data;
for(int i = 0; i < colorImage.rows; i++)
{
for(int j = 0; j < colorImage.cols; j++)
{
uint32_t src_pixelval = pixelPtr[colorImage.channels()*(colorImage.cols*i + j)];
uint16_t conv = cvRound(src_pixelval * 32);
pixelPtrDest[adaptada.channels()*(adaptada.cols*i + j) + 0] = conv;
pixelPtrDest[adaptada.channels()*(adaptada.cols*i + j) + 1] = conv;
pixelPtrDest[adaptada.channels()*(adaptada.cols*i + j) + 2] = conv;
}
}
System::IntPtr ptr(adaptada.ptr());
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(adaptada.cols,adaptada.rows,adaptada.step,System::Drawing::Imaging::PixelFormat::Format48bppRgb ,ptr);