Матрица обрезанных изображений OpenCV неправильно отображается в представлении MFC - PullRequest
3 голосов
/ 17 декабря 2011

Я использую следующие процедуры для отображения OpenCV Mat на MFC View. И это хорошо работает для необрезанных изображений. Но для предварительно обрезанных изображений отображаются пустые или странные изображения, подобные приведенным ниже:

Первый отображается в обычном графическом программном обеспечении, таком как MS Paint, а второй - в моем представлении MFC. Сложно то, что распакованные файлы изображений отображаются просто отлично. Я не уверен, что это вина SetDIBitsToDevice или OpenCV. Но ясно, SetDIBitsToDevice теряет постоянное количество байтов в каждой строке. У кого-нибудь есть идеи, чтобы решить эту проблему?

Correct Displayed

cv::Mat m_cvImage;
static int Bpp(cv::Mat img) { return 8 * img.channels(); } 


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 ]

3 голосов
/ 22 декабря 2011

Как говорит Рул , данные растрового изображения должны быть выровнены по DWORD. Однако это неполное описание проблемы; каждая строка данных должна начинаться с границы DWORD. Как правило, вы вставляете от 0 до 3 байтов заполнения в конце каждой строки, чтобы гарантировать это.

Если заполнение строк неудобно или невозможно, просто убедитесь, что ширина изображения делится равномерно на 4.

3 голосов
/ 21 декабря 2011

Я не исследовал ваш пример подробно, но учтите, что данные, передаваемые в SetDIBitsToDevice, должны быть выровнены по границам DWORD (IIRC). Может быть, ваши 90% случаев, когда это работает, имеют одинаковый размер и все случайно, и когда вы поворачиваете выравнивающие переключатели.

Я ожидаю, однако, что в этом случае вы не увидите выходных данных, но, возможно, драйвер GDI обнаруживает неправильное выравнивание и вообще не выполняет никаких действий. Звучит разумно.

Я думаю, что опубликовал пример функции, которая корректно выравнивается по границам DWORD для использования с SetDIBitsToDevice для SO ранее, найдите мои сообщения для примера кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...