Преобразование GDIPlus :: Bitmap в cv :: Mat (интерфейс OpenCV C ++) - PullRequest
0 голосов
/ 18 августа 2011

Я пытаюсь преобразовать GDIPlus :: Bitmap в объект openCV Mat, но у меня возникают проблемы с нарушениями доступа, что означает, что я что-то не так делаю, но я просмотрел код и снова, и я думаю, что это должно работать.

Кто-нибудь видит очевидную проблему?

cv::Mat ConvertToOpenCV(Gdiplus::Bitmap &image) {
    cv::Mat *retval = new cv::Mat(
        image.GetWidth(), image.GetHeight(), CV_8UC3
    );

    Gdiplus::BitmapData source;

    Gdiplus::Rect rect( 0, 0, image.GetWidth(), image.GetHeight() );
    Gdiplus::Status status =
        image.LockBits( &rect, Gdiplus::ImageLockModeRead, PixelFormat24bppRGB, &source );
    if ( status != Gdiplus::Ok ) {
        // Some error condition
        return retval; // No image copied
    }

    BYTE *destination = (BYTE *)retval->data;

    for ( int y = 0; y != source.Height; ++y ) {
        BYTE *src = (BYTE *) source.Scan0 + y * source.Stride;
        BYTE *dst = (BYTE *)(destination + y * retval->step);
        memcpy( dst, src, 3 * source.Width );  // Access Violation happens here
    }

    image.UnlockBits(&source);

    return retval;
}

Ответы [ 3 ]

2 голосов
/ 18 августа 2011

Вот одна проблема:

cv::Mat *retval = new cv::Mat(
    image.GetWidth(), image.GetHeight(), CV_8UC3
);

Первый аргумент конструктора Mat - это строки, второй - столбцы.Так что вы должны делать это:

cv::Mat *retval = new cv::Mat(
    image.GetHeight(), image.GetWidth(), CV_8UC3
);

Это может привести к нарушению доступа.

Редактировать

Кроме того, изображения OpenCV по умолчанию BGR, а не RGB.Так что если вы работаете, а затем отображаете изображение с помощью imshow, ваши значения синего и красного будут обратными.Вы можете исправить это с помощью вызова cv::cvtColor(retval, retval, CV_RGB2BGR) перед выпиской.

0 голосов
/ 21 апреля 2016

Как отмечает SSteve, конструкторы Mat переходят в строки, затем в столбцы, поэтому используйте height, а затем width.Однако нет необходимости делать фактическую копию самостоятельно.Вы можете использовать один из конструкторов Mat, который обернет существующие данные без копирования, а затем заставит их копировать, вызвав функцию-клон.

Единственная другая проблема заключается в том, что Gdiplus :: Bitmap в теории поддерживает множество пикселеймакеты;однако большинство из них довольно экзотические.Вы можете обрабатывать простой случай следующим образом:

cv::Mat GdiPlusBitmapToOpenCvMat(Gdiplus::Bitmap* bmp)
{
    auto format = bmp->GetPixelFormat();
    if (format != PixelFormat24bppRGB)
        return cv::Mat();

    int wd = bmp->GetWidth();
    int hgt = bmp->GetHeight();
    Gdiplus::Rect rcLock(0, 0, wd, hgt);
    Gdiplus::BitmapData bmpData;

    if (!bmp->LockBits(&rcLock, Gdiplus::ImageLockModeRead, format, &bmpData) == Gdiplus::Ok)
        return cv::Mat();

    cv::Mat mat = cv::Mat(hgt, wd, CV_8UC3, static_cast<unsigned char*>(bmpData.Scan0), bmpData.Stride).clone();

    bmp->UnlockBits(&bmpData);
    return mat;
}
0 голосов
/ 13 июля 2014

Вы можете использовать мой готовый к использованию класс CGdiPlus, который выполняет автоматическое преобразование из cv :: Mat в Gdiplus :: Bitmap и наоборот:

OpenCV / Tesseract: Как заменить libpng, libtiff и т. Д. С GDI + Bitmap (загрузка в cv :: Mat через GDI +)

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