我在Mat
中加载了一张图片。由此,我计算了DFT,所以在一个新的Mat中我存储了DFT(真实和img。部分)。
从这里开始,我的目标是绘制DFT的幅度。我已经通过OpenCV实现了这一点,通过计算它,将其带到范围0 - 1
并用imshow
显示。
但是,现在我正在使用 winform ,所以我需要将我的图片转换为bitmap
,以便在{{1}中绘制它}}
我也已经实现了在其中绘制某些类型的图像,例如:
PictureBox
我能够将CV_8UC1绘制到控件(PictureBox)中。但我没有实现将CV_32FC1绘制到其中。
我尝试了几种可能性,但我认为问题就是这个:由于我的图像是CV_32FC1,并且位图没有pixelFormat这种配置,我会需要先转换。
我到底做了什么?
我已将我的CV_32FC1 Mat缩放到确保16b范围内的值(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);
}
是我的幅度Mat):
magI
我已检查// 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;
}
}
的大小为2个字节,以便与unsigned short int
pixelFormat的16b匹配。但是当我尝试这种组合时(是的,如果我选择另一个pixelFormat,它会描绘一个废话,但它会画出来)我得到了一个:
Format16bppGrayScale
要最终确定,我会在A generic error occurred in GDI+
张贴我的结果。
问题是,我的幅度在CV_16UC1 (因为我创建了Format16bppRgb555
),所以要选择Mat_<unsigned short int>
没有意义,即使它看起来接近好结果。
任何想法都会受到赞赏!
提前谢谢你
编辑:我一直在用Format16bppRgb555
来表达它只画第一个频道(我唯一的一个频道,B-GR)所以结果正是我想要的,但在蓝色通道......
编辑2 (编辑 5:你可以从这里跳到编辑5):我已经尝试了@ BoykoPerfanov告诉我的内容,到C ++代码是:
Format16bppRgb555
现在,当我画它时,我得到:
所以我想我不太了解它,或者我在编码时错过了一些东西..
编辑3 :由于我的垫片是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));
}
}
,我注意到了我的声明:
CV_32F
错误,并将其更改为uint16_t * pixelPtr = (uint16_t *) colorImage.data;
,与uint32_t
类型相同。现在我的结果是:
编辑4 (天哪):我意识到我没有将绘图步骤从位图更改为新Mat,因此将该行更改为:
src_pixelval
现在我得到了(这次调整了一下):
编辑5 :我再次编码获取值的函数,将其绘制为System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(adaptada.cols,adaptada.rows,adaptada.step,System::Drawing::Imaging::PixelFormat::Format16bppRgb555 ,ptr);
,其中每个16b是我Format48bppRgb
的16b原始值垫。我想现在我的问题就是溢出了,我必须对这些值进行规范化,因为我在OpenCV中绘制它时会遇到同样的问题(这个数字看起来是黑色/白色)。让我们看看代码和结果:
CV_32FC1
答案 0 :(得分:1)
Format16bppRgb555的存储器布局为1位(未使用),5位红色(0-32),5位绿色(0-32),5位蓝色(0-32)。您需要手动打包这些位,因为opencv不支持从灰度图像创建灰度图像,除非输入类型是CV_8UC1。
一个非常基本的解决方案如下:
foreachpixel
{
float src_pixelval;
uint16_t* dst = ...;
uint16_t conv = round(src_pixelval * 32); //converted value to integral 5-bit type
现在通过以下方式写入红色,绿色和蓝色输出通道(以生成灰度位图):
dst = (conv<<0 | (conv<<5) | (conv<<10));
}
它做什么?在内存中,您的像素数据以浮点布局(解释为here)保存,具有符号,指数和尾数
float:( - 1 ^符号(位a到b)*尾数(位c到d)* 2 ^指数(位e到f))
当我们将值转换为uint16_t(重要:平台非特定,保证为16位数)时,我们转换了标准二进制积分布局中的数字:
2 ^ 16 *(senior_bit)+ 2 ^ 15 *(bit1)+ 2 ^ 14 *(bit2)+ ... 1 *(junior_bit)
但我们实际上将该数字视为5位数(由rgb555标准定义)。假设您的浮点值从0变为1,您希望将它们缩放到5位整数(0到32)的范围内。
最后,我们将这个5位数字复制到目标像素的r,g和b通道,形成所需的布局。例如,像素亮度= 0.78 - >转换后的亮度= 0.78 * 32 = 25,即11001.如果您正在做DFT机会,您应该知道(或轻松找到自己的方式)比特操作,如bitshift和bitwise或。
u(未使用/未定义)|红11001 |蓝色11001 |绿色11001 - &gt; u110011100111001。
答案 1 :(得分:0)
由于Boyko的答案,我设法解决了这个问题,但稍有改动,所以我将解释我做了什么。
正如Boyko所说:
Format16bppRgb555的内存布局为1位(未使用),5位为红色 (0-32),5位绿色(0-32),5位蓝色(0-32)。你需要打包 手动比特,因为opencv不支持创建灰色图像 来自灰度图像,输入类型为CV_8UC1时除外。
然后,他对如何获取每个像素的值的方法给了我错误的值,因为我从CV_32FC1
获取值,所以当我使用uint32_t *
转到像素时,返回值为int
而不是浮点数。这使得程序做错了(即使我从uint32_t
获取这些值然后将它放入float var中。)
所以我将指针改为我原来的Mat,从uint32_t
到float
(知道我的浮点数大小相同,4个字节),所以我可以得到正确的值,然后存储它在float
var中。
foreachpixel
{
float src_pixelval;
float * dst = ...; //Get the pointer to my pixel, from my Mat
然后我不得不将它传递给我的新垫子。由于我的价值很高,我最终改变了它,以免丢失数据。所以我改为Format48bppRgb
以便不需要将它缩放那么多(我没有将浮点值设置在0和1之间,我也不想将它们舍入那么多)。
因此我为每个值获得了16b,将我的dst Mat更改为CV_16UC3
以适应来自Format48bppRgb
的48b。因此,我的价值被获得并转移到我的新垫子,如:
uint16_t conv = cvRound(src_pixelval * 512);
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;
}
将它与512相乘的原因是我在CV_32FC1
中的值在0到255之间,因此我将它们带到16b范围内。
我也改变了对新Mat的访问方式,但这只是一种代码方式,Boyko方式也很好。
然后,我终于得到了: