BGR -> преобразование YCbCr не работает правильно - PullRequest
0 голосов
/ 23 июня 2019

Я пытаюсь вручную преобразовать изображение из RBG (BGR в OpenCV) в цветовое пространство YCbCr.

Мое изображение - это цветное изображение png, ширина 800 и высота 600, 3 канала, 16Битовая глубина.

Вот как я пытался решить эту проблему.

cv::Mat convertToYCbCr(cv::Mat image) {                                         
    // converts an RGB image to YCbCr                                           
    // cv::Mat: B-G-R                                                           
    std::cout << "Converting image to YCbCr color space." << std::endl;         
    int i, j;                                                                   
    for (i = 0; i <= image.cols; i++) {                                         
        for (j = 0; j <= image.rows; j++) {                                     

            // R, G, B values                                                   
            auto R = image.at<cv::Vec3d>(j, i)[2];                              
            auto G = image.at<cv::Vec3d>(j, i)[1];                              
            auto B = image.at<cv::Vec3d>(j, i)[0];                              

            // Y'                                                               
            auto Y = image.at<cv::Vec3d>(j,i)[0] = 0.299 * R + 0.587 * G + 0.114 * B + 16;

            // Cb                                                               
            auto Cb = image.at<cv::Vec3d>(j,i)[1] = 128 + (-0.169 * R -0.331 * G + 0.5 * B);

            // Cr                                                               
            auto Cr = image.at<cv::Vec3d>(j,i)[2] = 128 + (0.5 * R -0.419 * G -0.081 * B);
            std::cout << "At conversion: Y = " << Y << ", Cb = " << Cb << ", "  
                << Cr << std::endl;                                             
        }                                                                       
    }                                                                           
    std::cout << "Converting finished." << std::endl;                           
    return image;                                                               
}

Полученное изображение выглядит так:

Result Image

Чего я ожидаю (используя метод OpenCV):

enter image description here

Возможно, что-то намекает на вертикальные линии?Мой цикл неправильный?Могу ли я просто «заменить» значения RGB на значения YCbCr и ожидать, что изображение будет выглядеть как пример?typeid() возвращает одинаковое значение для обоих изображений, N2cv3MatE.

Ответы [ 2 ]

1 голос
/ 23 июня 2019

Основной причиной неправильных результатов является неверный тип данных, используемый для доступа к изображению. Правильный тип для доступа к 16-битным неподписанным пикселям: cv::Vec3w (не cv::Vec3d).

Следующая проблема заключается в том, что коэффициенты, которые используются для преобразования, предназначены для аналоговых сигналов (YPbPr). Для цифровых изображений мы должны использовать коэффициенты, предназначенные для цифровых изображений (YCbCr). Более подробную информацию можно найти в статье Википедии о YCbCr в разделе Преобразование МСЭ-R BT.601 .

В статье отсутствует информация о том, как изменятся коэффициенты, если изображения имеют 16-битную глубину без знака или 32-битную глубину с плавающей запятой? Ответ заключается в том, что нам придется масштабировать коэффициенты в соответствии с битовой глубиной нашего изображения.

Для изображений с глубиной без знака 16 бит масштабирование должно выполняться следующим образом:

auto Y = (R * 65.481f * scale) + (G * 128.553f * scale) + (B * 24.966f * scale) + (16.0f * offset);
auto Cb = (R * -37.797f * scale) + (G * -74.203f * scale) + (B * 112.0f * scale) + (128.0f * offset);
auto Cr = (R * 112.0f * scale) + (G * -93.786f * scale) + (B * -18.214f * scale) + (128.0f * offset);

, где scale равно 257.0/65535.0, а offset равно 257.0.

Этот метод преобразования был принят из исходного кода MATLAB для функции rgb2ycbcr, которая ссылается на следующую книгу, описывающую масштабирование:

C.A. Пойнтон, «Техническое введение в цифровое видео», Джон Уайли & Sons, Inc., 1996, глава 9, стр. 175`

Теперь, когда преобразование выполнено, третья проблема, с которой мы сталкиваемся, - это визуализация изображения, аналогичная OpenCV. Когда мы выполняем преобразование цветов с помощью OpenCV, выходное изображение сохраняется в порядке YCrCb вместо обычного YCbCr. Таким образом, чтобы получить то же изображение с нашей пользовательской логикой преобразования, мы должны хранить значения в соответствующем порядке.

Пример кода преобразования может выглядеть следующим образом:

if(image.type() == CV_16UC3)
{
    const float scale = 257.0f / 65535.0f;
    const float offset = 257.0f;
    for (int i = 0; i < image.cols; i++)
    {
        for (int j = 0; j < image.rows; j++)
        {
            auto R = image.at<cv::Vec3w>(j, i)[2];
            auto G = image.at<cv::Vec3w>(j, i)[1];
            auto B = image.at<cv::Vec3w>(j, i)[0];

            auto Y = (R * 65.481f * scale) + (G * 128.553f * scale) + (B * 24.966f * scale) + (16.0f * offset);
            auto Cb = (R * -37.797f * scale) + (G * -74.203f * scale) + (B * 112.0f * scale) + (128.0f * offset);
            auto Cr = (R * 112.0f * scale) + (G * -93.786f * scale) + (B * -18.214f * scale) + (128.0f * offset);

            image.at<cv::Vec3w>(j, i)[0] = (unsigned short)Y;
            image.at<cv::Vec3w>(j, i)[1] = (unsigned short)Cr;
            image.at<cv::Vec3w>(j, i)[2] = (unsigned short)Cb;
        }
    }
}
1 голос
/ 23 июня 2019

Вы должны использовать cv::cvtColor

cvtColor(src, target_image, cv::COLOR_RGB2YCrCb);

Затем просто переключите второй и третий каналы.

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

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