2011-12-14 16 views
5

Myślałem, że wyświetlenie maty OpenCV2 w widoku MFC jest proste, ale nie jest. This is only relevant material I found on google. Przepraszam za moją ignorancję, ale nie mogę znaleźć żadnych innych materiałów pokazujących, jak korzystać z SetDIBitsToDevice z jednowymiarowymi tablicami zwracanymi przez "dane". Dokładniej, muszę wiedzieć, jak określić BITMAPINFO dla funkcji. Czy wracam do OpenCV w starym stylu C, aby współpracować z MFC?Jak wyświetlić Matę OpenCV na MFC View

UPDATE:

znalazłem an example of SetDIBitsToDevice która jest faktycznie na starym stylu C OpenCV. Łatwo było jednak przekonwertować go na OpenCV2. Są rzeczy, muszę wspomnieć, że praca:

  1. metoda

    BPP nie działa dobrze jak głębokość Mat wraca 0. Właśnie zmienił tak:

    static int Bpp(cv::Mat img) { return 8 * img.channels(); } 
    
  2. Mat nie ma pochodzenie członek. Ale wprowadzenie 0 jest w porządku dla argumentu pochodzenia metody FillBitmapInfo.

Poza tym poniższy kod działa świetnie. Mam nadzieję, że to pomoże także innym programistom.

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

A co jest nie tak z linkiem, który podałeś? – Sam

+0

@vasile Pomimo dokumentów na SetDIBitsToDevice, nie mogę dowiedzieć się, jak korzystać z SetDIBitsToDevice z jednowymiarowymi tablicami zwracanymi przez "dane". –

+0

@Paul Widziałem twój przykład jako podstawę dla innych pytań/odpowiedzi. Zastanawiam się jednak, w jaki sposób uniknąć wycieku pamięci z użycia 'memset' w funkcji' FillBitmapInfo'? lub w jakiś sposób jest automatycznie zwalniany? Czy możesz rozwinąć w tym zakresie. – adn

Odpowiedz

1

od MSDN:

lpvBits [w] wskaźnik danych koloru zapisanych w tablicy bajtów. Aby uzyskać więcej informacji, zobacz następującą sekcję Uwagi.

To jest wskaźnik, który należy zainicjować danymi zwróconymi z Mat :: data.

+0

tutaj jest wszystko, czego potrzebujesz. http://msdn.microsoft.com/en-us/library/dd162974(v=vs.85).aspx Po prostu przeczytaj to sam. – Sam

+0

BITMAPINFO to struktura z nazwami pól, które wyraźnie mówią, co zawierają: BITMAPINFOHEADER-> szerokość, wysokość itp. Czy naprawdę kiedykolwiek czytałeś tę stronę? Przeczytaj także dokumentację Mata. – Sam

+0

Ok, użyłem go jakiś czas temu, ale patrząc na powyższą edycję, nie jest to tak proste, jak zapamiętano. Przepraszam. – Sam

2

Oto inny możliwy sposób wyświetlania danych OpenCV w MFC, które używam i działa świetnie:

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

Nie jestem pewien, czy używam tej samej wersji OpenCV, ale aby przekonwertować z macie na IplImage, po prostu: 'CvMat mat = cvMat (wysokość, szerokość, CV_8UC1, dane); IplImage * img = cvCreateImage (cvSize (wysokość, szerokość), IPL_DEPTH_8U, 1); cvGetImage (& mat, img); ' – Smash

+0

nie wiem, czy to jest szybsze, to jest o wiele łatwiejsze;) – Smash

1

CvvImage nie jest dostępny w nowej wersji OpenCV. Korzystanie poniższy kod można konwersji matę CImage a następnie wyświetlić CImage wszędzie chcesz:

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; 
}