簡體   English   中英

CV_32FC1到位圖

[英]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

DFT幅度

問題是, 我的大小在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM