2016-06-14 2 views
1

Я хочу преобразовать изображение из RGBA в формат YUV422. Ниже приведен мой код:Преобразование RGBA в формат YUV422 с использованием C++ - не получается правильный вывод

#include "opencv2/highgui/highgui.hpp" 
#include "opencv2/imgproc/imgproc.hpp" 
#include <iostream> 
#include <stdio.h> 
#include <stdlib.h> 

using namespace cv; 
using namespace std; 

#define CLIP(X) ((X) > 255 ? 255 : (X) < 0 ? 0 : X) 
#define RGB2Y(R, G, B) CLIP((( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16) 
#define RGB2U(R, G, B) CLIP(((-38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128) 
#define RGB2V(R, G, B) CLIP(((112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128) 

int main(int argc, char *argv[]) 
{ 

    Mat in_img, in_RGB, out_yuv; 
    in_img = imread(argv[1],1); 
    if(!in_img.data) 
    { 
     printf("Failed to load the image ... %s\n!", argv[1]); 
     return -1; 
    } 
    short imgwidth = in_img.cols; 
    short imgheight = in_img.rows; 

    cvtColor(in_img, in_RGB, CV_BGR2RGB); 
    out_yuv.create(imgheight, imgwidth, CV_16U); 

    imwrite("RGB.jpg",in_RGB); 

    for(int i = 0; i< imgheight; i++) 
     for(int j = 0; j< imgwidth; j = j+2) { 
      unsigned int val = in_RGB.at<unsigned int>(i,j); 

/*********** for 1st pixel ***********/ 
      unsigned int tmp = val; 
      unsigned char B = (unsigned char)(((tmp<<16) >> 24) | 0x000000ff); //Extracting B channel data 

      tmp = val; 
      unsigned char G = (unsigned char)(((tmp<<8) >> 24) | 0x000000ff); //Extracting G channel data 

      tmp = val; 
      unsigned char R = (unsigned char)((tmp >> 24) | 0x000000ff); //Extracting R channel data 

      unsigned char Y1 = RGB2Y(R, G, B); 
      unsigned char U = RGB2U(R, G, B); 
      unsigned char V = RGB2V(R, G, B); 

/*********** for 2nd pixel ***********/ 
      unsigned int val1 = in_RGB.at<unsigned int>(i,j+1); 
      unsigned int tmp1 = val1; 
      unsigned char B1 = (unsigned char)(((tmp1<<16) >> 24) | 0x000000ff); 

      tmp1 = val1; 
      unsigned char G1 = (unsigned char)(((tmp1<<8) >> 24) | 0x000000ff); 

      tmp1 = val1; 
      unsigned char R1 = (unsigned char)((tmp1 >> 24) | 0x000000ff); 

      unsigned char Y2 = RGB2Y(R, G, B); 

/********** writing into out image in U-Y1-V-Y2 format *********************/ 

     unsigned short p1 = ((U << 8) | Y1) ; 
     unsigned short p2 = ((V << 8) | Y2) ; 
     out_yuv.at<unsigned short>(i,j) = p1; 
     out_yuv.at<unsigned short>(i,j+1) = p2; 

    } 
     imwrite("YUV422.png",out_yuv); 
return 0; 
} 

Но я не получаю надлежащего выходного изображения. Я также попытался записать его в формате Y1-U-Y2-V, все тот же вывод. Что может быть неправильным с приведенным выше кодом или это формат выходного изображения (.png/.jpg), который создает пробку? (Резюме :: imwrite не позволяет сохранять в формате .yuv)

+0

если изображение RGBA я не вижу, где вы обработки/пропуская альфа-канал – EdChum

+0

'imwrite («YUV422.png», out_yuv);' Что вы используете для просмотра полученного изображения? – UmNyobe

+0

@EdChum: Я игнорирую альфа-канал (LSB 8 бит) и извлекаю каналы 'R', 'G', 'B' (MSB 24 бит). – Goutham

ответ

1
out_yuv.create(imgheight, imgwidth, CV_16U); 
... 
imwrite("YUV422.png",out_yuv); 

Несколько вопросов здесь:

  • imwrite считает CV_16Uto be mono channel.
  • Вы не можете писать yuv внутри png. Вы должны сбросить данные raw и использовать специальный просмотрщик yuv, такой как raw yuvplayer, чтобы убедиться, что ваши данные верны.

Edit:
Обратите внимание, что исходные пиксели аббревиатуры своего рода большой порядок байт, то есть крайнее левое значение является наименее значащий байт в памяти (большую часть времени, видео люди любят путаницы)

  • RGBA означает R = RGB[0], G = RGB[1], B = RGB[2], A = RGB[3]
  • YUYV означает в буфере p означает p[0] является Y0, p[1] является U, p[2] является Y1, p[3] является V

Вы делаете прямо противоположное со своими сдвигами :)

Edit 2: Если изображение все еще омлет, вы, кажется, готовы написать следующий формат планарного (YUV422 P aka YV16). Плоский формат означает, что каждый канал находится на отдельной, смежной плоскости. Яснее использовать простой старый буфер для целевых данных (unsigned char*, или std::vector<unsigned char>).

unsigned char* out_yuv_ptr = new unsigned char[imgwidth*imgheight*2]; 
unsigned char* y_ptr = out_yuv_ptr; 
unsigned char* u_ptr = y_ptr + imgwidth*imgheight; 
unsigned char* v_ptr = u_ptr + imgwidth*imgheight/2; 
... 
*y_ptr = Y1; 
++y_ptr 
*y_ptr = Y2; 
++y_ptr 
*u_ptr = U; 
++u_ptr; 
*v_ptr = V; 
++v_ptr; 
+0

Благодарим вас за предложение, это было действительно полезно. Я сбросил данные в '.yuv ', используя команду fwrite(). При проверке с помощью [raw yuvplayer] (https://sourceforge.net/projects/raw-yuvplayer/) он отображает вид скремблированного вывода (с правильным размером изображения и цветовой кодировкой (YUV422), установленными в проигрывателе). Если я изменил опцию «цвет» в проигрывателе на YUYV/UYVY, я получаю выходное изображение, как ожидалось, за исключением разных цветов, чем оригинал. Теперь я начинаю сомневаться в правильности используемой методологии преобразования в коде. Есть ли способ узнать это? – Goutham

+0

@quintello смотреть редактирование. – UmNyobe

+0

Я скорректировал тип endian, и теперь результат кажется идеальным в формате ** YUYV **, но мое первоначальное намерение состояло в том, чтобы преобразовать его в формат YUV422 (который все еще скремблирован). Куда я пошел по пути от YUV422 до YUYV? – Goutham

Смежные вопросы