CGBitmapContextCreate для CV_8UC3 (для использования в OpenCV) - PullRequest
6 голосов
/ 30 марта 2012

Я пытаюсь использовать функцию обнаружения людей в OpenCV:

cv::HOGDescriptor hog;
hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());
std::vector<cv::Rect> found;
hog.detectMultiScale(noMask, found, 0.2, cv::Size(8,8), cv::Size(16,16), 1.05, 2);

Но я получаю следующее утверждение:

Ошибка OpenCV: утверждение не выполнено (img.type () == CV_8U || img.type () == CV_8UC3) в файле computeGradient, файл /Users/robin/Projects/OpenCVForiPhone/opencv/opencv/modules/objdetect/src/hog.cpp, линия 174

И это имеет смысл, потому что я передаю изображение CV_8UC4.

Так что я догадался, что мне следует создать cvmat с этими характеристиками. Прямо сейчас у меня есть эти 2 метода. которые позволяют мне получать серые или цветные цвета (CV_8UC1 / CV_8UC4)

для цвета:

-(cv::Mat)CVMat
{

    CGColorSpaceRef colorSpace = CGImageGetColorSpace(self.CGImage);
    CGFloat cols = self.size.width;
    CGFloat rows = self.size.height;

    cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels

    CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,                 // Pointer to backing data
                                                    cols,                      // Width of bitmap
                                                    rows,                     // Height of bitmap
                                                    8,                          // Bits per component
                                                    cvMat.step[0],              // Bytes per row
                                                    colorSpace,                 // Colorspace
                                                    kCGImageAlphaNoneSkipLast |
                                                    kCGBitmapByteOrderDefault); // Bitmap info flags

    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage);
    CGContextRelease(contextRef);

    return cvMat;
}

Для оттенков серого:

-(cv::Mat)CVGrayscaleMat
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
    CGFloat cols = self.size.width;
    CGFloat rows = self.size.height;

    cv::Mat cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channel

    CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,                 // Pointer to backing data
                                                    cols,                      // Width of bitmap
                                                    rows,                     // Height of bitmap
                                                    8,                          // Bits per component
                                                    cvMat.step[0],              // Bytes per row
                                                    colorSpace,                 // Colorspace
                                                    kCGImageAlphaNone |
                                                    kCGBitmapByteOrderDefault); // Bitmap info flags

    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage);
    CGContextRelease(contextRef);
    CGColorSpaceRelease(colorSpace);

    return cvMat;
}

И это мое предположение сделать 3 канала:

-(cv::Mat)CVMat3Channels
{

    //CGColorSpaceRef colorSpace = CGImageGetColorSpace(self.CGImage);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat cols = self.size.width;
    CGFloat rows = self.size.height;

    cv::Mat cvMat(rows, cols, CV_8UC3); // 8 bits per component, 3 channels

    CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,                // Pointer to backing data
                                                    cols,                      // Width of bitmap
                                                    rows,                     // Height of bitmap
                                                    8,                          // Bits per component
                                                    cvMat.step[0],              // Bytes per row
                                                    colorSpace,                 // Colorspace
                                                    kCGImageAlphaNoneSkipLast |
                                                    kCGBitmapByteOrderDefault); // Bitmap info flags

    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage);
    CGContextRelease(contextRef);
    CGColorSpaceRelease(colorSpace);

    return cvMat;
}

Но я получаю следующую ошибку:

<Error>: CGBitmapContextCreate: invalid data bytes/row: should be 
         at least 9792 for 8 integer bits/component, 3 components, 
         kCGImageAlphaNoneSkipLast. 
<Error>: CGContextDrawImage: invalid context 0x0

Итак, мой вопрос: как правильно создать 8UC3-совместимый CGBitmapContext? (Я предполагаю, что 8UC3 означает 8 бит на пиксель с каналами RGB)

Спасибо.

PD: Код трансформации изображения от Робина Саммерхилла.

Ответы [ 4 ]

6 голосов
/ 20 августа 2012

Я использовал ваш микс, но он не работает: в результате получается цветное изображение RGB, но теряется много цветов.

Итак, у меня есть очень простой способ конвертации, и он успешен

Этот код в XCode:

lastImage = [firstImage CVMat];
cv::cvtColor(lastImage , lastImage , CV_RGBA2RGB);

Он преобразует lastImage в цвет RGB со стилем CV_8UC3.

Извините, потому что я впервые комментирую, и я не знаю, какотформатируйте это.

3 голосов
/ 09 августа 2012

Другим подходом может быть создание матрицы CV_8UC4 с последующим разделением каналов, получение матрицы bgr и альфа-матрицы (в данном случае отбрасывается):

cv::Mat CVMat(CGImageRef cgimage)
{

    CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgimage);
    CGFloat cols = CGImageGetWidth(cgimage);
    CGFloat rows = CGImageGetHeight(cgimage);

    cv::Mat rgba(rows, cols, CV_8UC4, Scalar(1,2,3,4)); // 8 bits per component, 4 channels

    CGContextRef contextRef = CGBitmapContextCreate(rgba.data,                 // Pointer to backing data
                                                    cols,                      // Width of bitmap
                                                    rows,                     // Height of bitmap
                                                    8,                          // Bits per component
                                                    rgba.step[0],              // Bytes per row
                                                    colorSpace,                 // Colorspace
                                                    kCGImageAlphaNoneSkipLast |
                                                    kCGBitmapByteOrderDefault); // Bitmap info flags

    CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), cgimage);
    CGContextRelease(contextRef);

    Mat bgr( rgba.rows, rgba.cols, CV_8UC3 );
    Mat alpha( rgba.rows, rgba.cols, CV_8UC1 );

    Mat out[] = { bgr, alpha };
    // rgba[0] -> bgr[2], rgba[1] -> bgr[1],
    // rgba[2] -> bgr[0], rgba[3] -> alpha[0]
    int from_to[] = { 0,2, 1,1, 2,0, 3,3 };
    mixChannels( &rgba, 1, out, 2, from_to, 4 );

    return bgr;
}
0 голосов
/ 17 июля 2012

Нельзя создать контекст с 24 байтами (8 бит * 3 компонента) на пиксель. См. cgbitmapcontextcreate-with-kcgimagealphanone . Один из вариантов - создать матрицу CV_8UC4, а затем преобразовать ее в матрицу CV_8UC3 с помощью cvtColor. Если вам нужен пример кода, посмотрите на cant-make-opencv-detect-people-on-ios .

0 голосов
/ 30 марта 2012

Вы правильно создаете 3-канальное изображение, используя CV_8UC3. Поскольку CGBitmapContextCreate ожидает 9792 байтов / строку, это означает, что должно быть 3264 столбцов (из 3-канальных пикселей). Если я запускаю следующий код,

int cols = 3264;
int rows = 1960; // assuming a ~1.66 aspect ratio here...
Mat temp(rows, cols,  CV_8UC3);
cout << temp.step[0] << endl;

выводит 9792, как того требует CGBitmapContextCreate. Можете ли вы сказать, что cvMat.step[0] возвращает в вашем коде? Это выглядит правильно, но, возможно, что-то еще происходит.

Кроме того, обратите внимание, что OpenCV изначально сохраняет данные в формате BGR, если вы получаете данные изображения из функций OpenCV, таких как imread и т. Д. Итак, если цвет выглядит странно, обратите на это внимание.

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