[英]CV_32FC1 to bitmap
我已經在Mat
加載了圖像。 由此,我計算出DFT,因此在新的Mat中,我已經存儲了DFT(包括實部和img。部分)。
從這里開始,我打算畫出DFT的大小 。 我已經與OpenCV的實現了這個已經,通過計算它,把它的范圍0 - 1
,並顯示它imshow
。
但是,現在我正在使用winform ,因此需要將圖像轉換為bitmap
才能在PictureBox
進行繪制。
我還實現了在其中繪制一些圖像的功能,例如:
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);
}
我能夠將CV_8UC1繪制到控件(PictureBox)中。 但是我還沒有實現將CV_32FC1納入其中的努力 。
我嘗試了幾種可能性,但我認為問題是這樣的 :由於我的圖像是CV_32FC1,並且在這種配置下位圖沒有pixelFormat ,因此我需要先對其進行轉換 。
我到底做了什么?
我已經縮放了CV_32FC1 Mat,以確保值在16b范圍內 ( magI
是我的幅度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;
}
}
我檢查了unsigned short int
大小為2個字節,以便與Format16bppGrayScale
pixelFormat中的16b匹配。 但是,當我嘗試這種組合時(是的,如果我選擇另一個pixelFormat,它會顯示一個廢話,但它會顯示),我得到:
A generic error occurred in GDI+
最后,我將結果發布在這里Format16bppRgb555
。
問題是, 我的大小在CV_16UC1中 (因為我創建了Mat_<unsigned short int>
),因此選擇Format16bppRgb555
沒有任何意義 ,即使它看起來接近良好的結果。
任何想法,將不勝感激!
提前謝謝你
編輯 :我一直在想,用Format16bppRgb555
它只繪制第一個通道(我唯一的通道,B-GR),所以結果正是我想要的,但是在藍色通道中...
編輯2 ( 編輯 5:您可以從此處跳至編輯5):我已經嘗試過@ BoykoPerfanov告訴我的內容,翻譯為C ++代碼是:
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));
}
}
現在,當我繪畫它時,我得到:
所以我想我不太了解它,或者我在編碼時缺少一些東西。
編輯3 :由於我的Mat是CV_32F
,所以我注意到了我的聲明:
uint16_t * pixelPtr = (uint16_t *) colorImage.data;
錯誤,並將其更改為uint32_t
,與src_pixelval
類型相同。 現在我的結果是:
編輯4 (我的天哪):我意識到我沒有將繪畫步驟從位圖更改為新的Mat,因此將該行更改為:
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap(adaptada.cols,adaptada.rows,adaptada.step,System::Drawing::Imaging::PixelFormat::Format16bppRgb555 ,ptr);
現在我得到了(這次調整了一點):
編輯5 :我再次編碼該函數以獲取值,將其繪制為Format48bppRgb
,其中每個16b是我的CV_32FC1
Mat的16b原始值。 我想我的問題現在只是溢出,而且我必須規范化這些值,因為在OpenCV中繪制它時,我遇到了同樣的問題(幅度似乎是黑白顛倒的)。 讓我們看一下代碼和結果:
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);
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));
}
它有什么作用? 在內存中,像素數據以浮點布局( 在此說明)保存,並具有符號,指數和尾數。
浮點數:(-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,則應該知道(或輕松地找到自己的方法)按位運算,例如位移和按位或。
u(未使用/未定義)| 紅色11001 | 藍色11001 | 綠色11001-> u110011100111001。
感謝Boyko的回答,我設法解決了這個問題,但是做了一些改動,所以我要解釋一下我做了什么。
正如博伊科所說:
Format16bppRgb555的內存布局為1位(未使用),5位紅色(0-32),5位綠色(0-32),5位藍色(0-32)。 您需要手動打包位,因為opencv不支持從灰度圖像創建灰度圖像,除非輸入類型為CV_8UC1。
然后,他的方法如何獲取每個像素的值給了我錯誤的值,因為我從CV_32FC1
獲取了值,所以當我使用uint32_t *
轉到像素時,返回的值是int
而不是float。 這使程序做錯了(即使我從uint32_t
獲得了這些值,然后將其放入float var中)。
因此,我將指向原始Mat的指針從uint32_t
更改為float
(知道我的float具有相同的大小,即4個字節),因此我可以獲得正確的值,並將其也存儲在float
var中。
foreachpixel
{
float src_pixelval;
float * dst = ...; //Get the pointer to my pixel, from my Mat
然后,我必須將其傳遞給新的Mat。 由於我的價值很高,因此我最終對其進行了更改,以免丟失數據。 因此,我更改為Format48bppRgb
以便不必對其進行太大縮放(我沒有將浮點值設置在0到1之間,也不想對其進行四舍五入)。
所以我16B的每一個值,改變了我的DST墊到CV_16UC3
,以適應從48B Format48bppRgb
。 因此,我的價值被獲得並轉移到我的新墊子上,例如:
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方式也可以正常工作。
然后,我終於得到:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.