YUV420 в BGR изображение из пиксельных указателей - PullRequest
0 голосов
/ 08 мая 2018

Я получаю необработанный вывод из декодера, который является YUV420. У меня есть три указателя: Y (1920 * 1080), U (960 * 540) и V (960 * 540) отдельно.

Я хочу сохранить изображение в формате JPEG с использованием OpenCV. Я пытался использовать cvtcolor от opencv

cv::Mat i_image(cv::Size(columns, rows), CV_8UC3, dataBuffer);
cv::Mat i_image_BGR(cv::Size(columns, rows), CV_8UC3);
cvtColor(i_image, i_image_BGR, cv::COLOR_YCrCb2BGR);
cv::imwrite("/data/data/org.myproject.debug/files/pic1.jpg", i_image_BGR);

Но вот выходное изображение, которое сохраняется:

image

Может кто-нибудь подсказать, как правильно сохранить изображение?

YUV Двоичные файлы для справки

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Ниже приведен процесс преобразования предоставленных YUV-файлов в RGB-изображение.

  • Чтение двоичных файлов Y, U и V в байтовые буферы
  • Создание объекта OpenCV Mat из созданных буферов.
  • Изменение размера U и V Mats до размера Y.
  • Объединить Y и изменить размер U и V.
  • Конвертировать из YUV в BGR

Имейте в виду , что шаг изменения размера - это просто оптимизированный способ повторения значений U и V. Это справедливо только в случае, когда Y имеет двойное разрешение U и V в обоих измерениях. Этот подход должен быть недопустимым для изображений произвольного размера (не проверено).

Вот код для вышеупомянутого процесса.

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>

std::vector<unsigned char> readBytesFromFile(const char* filename)
{
    std::vector<unsigned char> result;

    FILE* f = fopen(filename, "rb");

    fseek(f, 0, SEEK_END);  // Jump to the end of the file
    long length = ftell(f); // Get the current byte offset in the file
    rewind(f);              // Jump back to the beginning of the file

    result.resize(length);

    char* ptr = reinterpret_cast<char*>(&(result[0]));
    fread(ptr, length, 1, f); // Read in the entire file
    fclose(f); // Close the file

    return result;
}

int main(int argc, char** argv)
{
    cv::Size actual_size(1920, 1080);
    cv::Size half_size(960, 540);

    //Read y, u and v in bytes arrays
    auto y_buffer = readBytesFromFile("ypixel.bin");
    auto u_buffer = readBytesFromFile("upixel.bin");
    auto v_buffer = readBytesFromFile("vpixel.bin");


    cv::Mat y(actual_size, CV_8UC1, y_buffer.data());
    cv::Mat u(half_size, CV_8UC1, u_buffer.data());
    cv::Mat v(half_size, CV_8UC1, v_buffer.data());

    cv::Mat u_resized, v_resized;
    cv::resize(u, u_resized, actual_size, 0, 0, cv::INTER_NEAREST); //repeat u values 4 times
    cv::resize(v, v_resized, actual_size, 0, 0, cv::INTER_NEAREST); //repeat v values 4 times

    cv::Mat yuv;

    std::vector<cv::Mat> yuv_channels = { y, u_resized, v_resized };
    cv::merge(yuv_channels, yuv);

    cv::Mat bgr;
    cv::cvtColor(yuv, bgr, cv::COLOR_YUV2BGR);
    cv::imwrite("bgr.jpg", bgr);

    return 0;
}

Скомпилировано и протестировано с помощью следующей команды:

g ++ -o yuv2rgb -std = c ++ 11 yuv2rgb.cpp -L / usr / local / lib -lopencv_core -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc

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

YUV To BGR Output

0 голосов
/ 08 мая 2018

Я думаю, что матрица OpenCV для вашего входного плоского изображения yuv420 должна иметь 1-канальный формат вместо 3-канального. Поместите там Y канал, затем U, затем V. Я нашел очень похожий вопрос ЗДЕСЬ Планарный YUV420 и NV12 - это то же самое

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