web-dev-qa-db-ja.com

OpenCVでYUVをBGRまたはRGBに変換する

フィードがYUV形式で入っているTVキャプチャカードを持っています。私はこの質問に似た他の投稿を見て、述べられたすべての可能な方法を試そうとしましたが、どちらも明確な画像を提供しませんでした。現時点で、最良の結果はOpenCV cvCvtColor(scr, dst, CV_YUV2BGR)関数呼び出しでした。

私は現在、YUV形式を認識していません。正直に言うと、4チャネルを格納しているように見えますが、3つしかありません。空白を埋めるために使用できる可能性のあることを誰かが理解できるように、キャプチャカードの画像を含めました。

YUV to BGR converted image

フィードは、DeckLink Intensity Proカードを介して受信され、Windows 7環境でOpenCVを使用してC++アプリケーションでアクセスされます。

更新

この情報に関するウィキペディアの記事を見て、アプリケーションでこの式を使用しようとしました。以下は、コードブロックから受け取った出力です。アドバイスは大歓迎です。

BYTE* pData;

    videoFrame->GetBytes((void**)&pData);

    m_nFrames++;

    printf("Num Frames executed: %d\n", m_nFrames);

    for(int i = 0; i < 1280 * 720 * 3; i=i+3)
    {
        m_RGB->imageData[i] = pData[i] + pData[i+2]*((1 - 0.299)/0.615);
        m_RGB->imageData[i+1] = pData[i] - pData[i+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[i+2]*((0.299*(1 - 0.299))/(0.615*0.587));
        m_RGB->imageData[i+2] = pData[i] + pData[i+1]*((1 - 0.114)/0.436);
    }

Attempted RGB conversion

11
Seb

YUV422ストリームをYUV444としてデコードしているように見えます。指定したコードに次の変更を加えてみてください。

for(int i = 0, j=0; i < 1280 * 720 * 3; i+=6, j+=4)
{
    m_RGB->imageData[i] = pData[j] + pData[j+3]*((1 - 0.299)/0.615);
    m_RGB->imageData[i+1] = pData[j] - pData[j+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[j+3]*((0.299*(1 - 0.299))/(0.615*0.587));
    m_RGB->imageData[i+2] = pData[j] + pData[j+1]*((1 - 0.114)/0.436);
    m_RGB->imageData[i+3] = pData[j+2] + pData[j+3]*((1 - 0.299)/0.615);
    m_RGB->imageData[i+4] = pData[j+2] - pData[j+1]*((0.114*(1-0.114))/(0.436*0.587)) - pData[j+3]*((0.299*(1 - 0.299))/(0.615*0.587));
    m_RGB->imageData[i+5] = pData[j+2] + pData[j+1]*((1 - 0.114)/0.436);
}

定数が正しいかどうかはわかりませんが、最悪の場合、色が消えます-画像は認識できるはずです。

6
Mark Ransom

OPENCVの新しいバージョンでは、YUVからRGBへの変換に使用できる組み込み関数があります。

cvtColor(src,dst,CV_YUV2BGR_YUY2);

下線の後にYUV形式を指定します。このようにCV_YUYV2BGR_xxxx

9
kyencn

OpenCVを使用して次のC++コードを使用し、yuvデータ(YUV_NV21)をRGB画像(OpenCVのBGR)に変換します

int main()
{
  const int width  = 1280;
  const int height = 800;

  std::ifstream file_in;
  file_in.open("../image_yuv_nv21_1280_800_01.raw", std::ios::binary);
  std::filebuf *p_filebuf = file_in.rdbuf();
  size_t size = p_filebuf->pubseekoff(0, std::ios::end, std::ios::in);
  p_filebuf->pubseekpos(0, std::ios::in);

  char *buf_src = new char[size];
  p_filebuf->sgetn(buf_src, size);

  cv::Mat mat_src = cv::Mat(height*1.5, width, CV_8UC1, buf_src);
  cv::Mat mat_dst = cv::Mat(height, width, CV_8UC3);

  cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV21);
  cv::imwrite("yuv.png", mat_dst);

  file_in.close();
  delete []buf_src;

  return 0;
}

変換後の結果は画像 yuv.png のようになります。

あなたはテスト生画像ここ およびプロジェクト全体から見つけることができますfrom my Github Project

2
cggos

BlackMagic IntensityソフトウェアはbmdFormat8BitYUVでYUVY '形式を返すため、2つのソースピクセルが4バイトに圧縮されます-openCVのcvtColorでこれを処理できるとは思いません。

自分で行うか、IntensityソフトウェアのConvertFrame()関数を呼び出すだけです。

編集:Y U Vは通常次のように保存されます
enter image description here

各ピクセルにはY(明るさ)がありますが、行のすべての代替ピクセルにはUとV(色)しかありません。

したがって、データが上記のようにメモリの先頭を指す符号なしの文字である場合。

ピクセル1、Y =データ[0] U =データ[+1] V =データ[+3]
ピクセル2、Y =データ[+2] U =データ[+1] V =データ[+3]

次に、サンプルコードで使用したYUV-> RGB係数を使用します。

2
Martin Beckett

それは間違った道かもしれませんが、多くの人々(つまり、エンジニア)はYUVとYCbCrを混ぜています。

してみてください

cvCvtColor(src, dsc, CV_YCbCr2RGB) 

またはCV_YCrCb2RGBまたはおそらくよりエキゾチックなタイプ。

1
Sam

多分誰かはカラーモデルYCbCrとYUVで混乱しています。 OpencvはYCbCrを処理しません。代わりにYCrCbがあり、opencvでYUVと同じ方法で実装されていますです。

Opencvソースから https://github.com/Itseez/opencv/blob/2.4/modules/imgproc/src/color.cpp#L38

case CV_BGR2YCrCb: case CV_RGB2YCrCb:
case CV_BGR2YUV: case CV_RGB2YUV:
    // ...
    // 1 if it is BGR, 0 if it is RGB
    bidx = code == CV_BGR2YCrCb || code == CV_BGR2YUV ? 0 : 2; 
    //... converting to YUV with the only difference that brings 
    //    order of Blue and Red channels (variable bidx)

しかし、もう1つ言うべきことがあります。
現在バグ変換CV_BGR2YUVおよびCV_RGB2YUVOpenCVブランチ2.4。*で。

現在、この式は実装で使用されています。

Y = 0.299B + 0.587G + 0.114R
U = 0.492(R-Y)
V = 0.877(B-Y)

それがどうあるべきか( wikipedia によると):

Y = 0.299R + 0.587G + 0.114B
U = 0.492(B-Y)
V = 0.877(R-Y)

チャネルの赤と青は、実装された式では誤った位置にあります。

バグが修正されていないときにBGR-> YUVを変換するための考えられる回避策:

  cv::Mat source = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
  cv::Mat yuvSource;    
  cvtColor(source, yuvSource, cv::COLOR_BGR2RGB); // rearranges B and R in the appropriate order
  cvtColor(yuvSource, yuvSource, cv::COLOR_BGR2YUV);
  // yuvSource will contain here correct image in YUV color space
1
Temak