2011-12-14 47 views
5

我認爲在MFC上顯示OpenCV2墊視圖很簡單,但不是。 This is only relevant material I found on google。請原諒我的無知,但我找不到任何其他材料顯示如何使用SetDIBitsToDevice一維數組「數據」成員返回。更具體地說,我需要知道如何爲函數指定BITMAPINFO。我是否會回到Old C-style OpenCV來使用MFC?如何顯示在MFC視圖上的OpenCV墊

UPDATE:

我發現an example of SetDIBitsToDevice這實際上是老C風格的OpenCV。但將其轉換爲OpenCV2很簡單。有些事情我必須要提到,使其工作:

  1. BPP方法不作爲墊的深度以及工作返回0。我只是改變這樣的:

    static int Bpp(cv::Mat img) { return 8 * img.channels(); } 
    
  2. 墊不具有產地會員。但簡單地把0放在FillBitmapInfo方法的原始參數上就可以了。

除此之外,下面的代碼很好用。希望這可以幫助其他開發者。

void COpenCVTestView::OnDraw(CDC* pDC) 
{ 
COpenCVTestDoc* pDoc = GetDocument(); 
ASSERT_VALID(pDoc); 
if (!pDoc) 
    return; 
if(pDoc->m_cvImage.empty()) return; 
// TODO: add draw code for native data here 
int height=pDoc->m_cvImage.rows; 
int width=pDoc->m_cvImage.cols; 
uchar buffer[sizeof(BITMAPINFOHEADER) + 1024]; 
BITMAPINFO* bmi = (BITMAPINFO*)buffer; 
FillBitmapInfo(bmi,width,height,Bpp(pDoc->m_cvImage),0); 
SetDIBitsToDevice(pDC->GetSafeHdc(), 0, 0, width, 
    height, 0, 0, 0, height, pDoc->m_cvImage.data, bmi, 
    DIB_RGB_COLORS); 
} 
void COpenCVTestView::FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin) 
{ 
assert(bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32)); 

BITMAPINFOHEADER* bmih = &(bmi->bmiHeader); 

memset(bmih, 0, sizeof(*bmih)); 
bmih->biSize = sizeof(BITMAPINFOHEADER); 
bmih->biWidth = width; 
bmih->biHeight = origin ? abs(height) : -abs(height); 
bmih->biPlanes = 1; 
bmih->biBitCount = (unsigned short)bpp; 
bmih->biCompression = BI_RGB; 

if (bpp == 8) 
{ 
    RGBQUAD* palette = bmi->bmiColors; 

      for (int i = 0; i < 256; i++) 
    { 
     palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; 
     palette[i].rgbReserved = 0; 
    } 
} 
} 
+2

的,什麼是錯,你提供的鏈接? – Sam

+0

@vasile儘管在SetDIBitsToDevice上有文檔,但我無法弄清楚如何在一維數組「數據」成員返回時使用SetDIBitsToDevice。 –

+0

@Paul我已經將你的例子看作其他幾個問題/答案的基礎。但是,我想知道,如何避免在'FillBitmapInfo'函數中使用'memset'的內存泄漏?或以某種方式自動釋放?你能否詳細說明這一點。 – adn

回答

1

從MSDN:

lpvBits [IN] 一個指針,指向存儲作爲一個字節數組的顏色數據。有關更多信息,請參閱以下備註部分。

這是您必須用Mat :: data返回的數據初始化的指針。

+0

這裏是你所需要的。 http://msdn.microsoft.com/en-us/library/dd162974(v=vs.85).aspx請自己閱讀它 – Sam

+0

BITMAPINFO是一個結構,其字段名稱清楚地說明它們包含的內容:BITMAPINFOHEADER->寬度,高度等。你真的讀過那個頁面嗎?請閱讀Mat文檔。 – Sam

+0

好的,我前段時間用過它,但是看上面的編輯,它不像記住的那麼簡單。抱歉。 – Sam

2

這裏是顯示在MFC OpenCV的數據,我用的另一種可能的方式和偉大工程:

IplImage* image// <-- this contains the image you want to display 
CvvImage tempdefault; 
RECT myrect; // <-- specifiy where on the screen you want it to be displayed 
myrect.top = 0; 
myrect.bottom = _pictureh; 
myrect.left = _picturex; 
myrect.right = _picturew+_picturex; 
tempdefault.Create(_pictureh,_picturew,32); 
tempdefault.CopyOf(image); 
tempdefault.DrawToHDC(pDC->GetSafeHdc(),&myrect); 
+1

不知道我是否使用相同版本的OpenCV,但是從墊轉換爲IplImage,我只需要: 'CvMat mat = cvMat(height,width,CV_8UC1,data); IplImage * img = cvCreateImage(cvSize(height,width),IPL_DEPTH_8U,1); cvGetImage(&mat,img);' – Smash

+0

nope我不知道它是否更快,它更容易;) – Smash

1

CvvImage不是在OpenCV中的新版本。使用下面的代碼,你可以轉換墊的CImage,然後顯示的CImage無處不在,你想:

int Mat2CImage(Mat *mat, CImage &img){ 
    if(!mat || mat->empty()) 
    return -1; 
    int nBPP = mat->channels()*8; 
    img.Create(mat->cols, mat->rows, nBPP); 
    if(nBPP == 8) 
    { 
    static RGBQUAD pRGB[256]; 
    for (int i = 0; i < 256; i++) 
     pRGB[i].rgbBlue = pRGB[i].rgbGreen = pRGB[i].rgbRed = i; 
    img.SetColorTable(0, 256, pRGB); 
    } 
    uchar* psrc = mat->data; 
    uchar* pdst = (uchar*) img.GetBits(); 
    int imgPitch = img.GetPitch(); 
    for(int y = 0; y < mat->rows; y++) 
    { 
    memcpy(pdst, psrc, mat->cols*mat->channels());//mat->step is incorrect for those images created by roi (sub-images!) 
    psrc += mat->step; 
    pdst += imgPitch; 
    } 

    return 0; 
}