CV_32FC1到位图

时间:2015-06-08 08:04:55

标签: c++ winforms opencv bitmap

我在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+ 张贴我的结果。

DFT Magnitude

问题是,我的幅度在CV_16UC1 (因为我创建了Format16bppRgb555),所以要选择Mat_<unsigned short int> 没有意义,即使它看起来接近好结果。

任何想法都会受到赞赏!

提前谢谢你

编辑:我一直在用Format16bppRgb555来表达它只画第一个频道(我唯一的一个频道,B-GR)所以结果正是我想要的,但在蓝色通道......

编辑2 编辑 5:你可以从这里跳到编辑5):我已经尝试了@ BoykoPerfanov告诉我的内容,到C ++代码是:

Format16bppRgb555

现在,当我画它时,我得到:

enter image description here

所以我想我不太了解它,或者我在编码时错过了一些东西..

编辑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类型相同。现在我的结果是:

enter image description here

编辑4 (天哪):我意识到我没有将绘图步骤从位图更改为新Mat,因此将该行更改为:

src_pixelval

现在我得到了(这次调整了一下):

enter image description here

编辑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

enter image description here

2 个答案:

答案 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_tfloat(知道我的浮点数大小相同,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方式也很好。

然后,我终于得到了:

enter image description here

相关问题