15

OpenCVでYUVファイルからフレームを読み取る方法は?

4

6 に答える 6

3

更新ここにコードの新しいバージョンがあります: https://github.com/chelyaev/opencv-yuv

単一のYUV 4:2:0 平面イメージ ファイルを読み取るコードを投稿しています。これをほとんどの YUV ファイルに直接適用できます (同じFILEオブジェクトから読み続けるだけです)。これに対する例外は、ヘッダーを持つ YUV ファイルを扱う場合です(通常、*.y4m拡張子があります)。このようなファイルを処理する場合は、次の 2 つのオプションがあります。

  1. FILE以下のコードを使用する前に、オブジェクトからヘッダー データを使用する独自の関数を記述します。
  2. *.y4m イメージからヘッダーを取り除きます (ffmpegまたは同様のツールを使用)。これは、最も単純なため、私が好むオプションです。

また、他の形式の YUV 形式 (非平面、異なるクロマ デシメーション) では機能しません。@Stephane が指摘したように、そのような形式は多数あります (そして、それらのほとんどには識別ヘッダーがありません)。これがおそらく、OpenCV がそのままではそれらをサポートしていない理由です。

しかし、それらを使用するのは非常に簡単です。

  • 画像とその寸法から始めます (これは YUV ファイルを読み取るときに必要です)
  • 輝度と彩度を 3 つの個別の画像に読み込む
  • 彩度デシメーションを補正するために、彩度イメージを 2 倍に拡大します。 彩度のデシメーションを補正するには、実際にはいくつかの方法があることに注意してください。アップサンプリングは最も単純な方法です
  • YUV 画像に結合します。RGBが必要な場合は、を使用できますcvCvtColor

最後に、コード:

IplImage * 
cvLoadImageYUV(FILE *fin, int w, int h)
{
    assert(fin);

    IplImage *py      = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 1);
    IplImage *pu      = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1);
    IplImage *pv      = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1);
    IplImage *pu_big  = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 1);
    IplImage *pv_big  = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 1);
    IplImage *image   = cvCreateImage(cvSize(w,    h), IPL_DEPTH_8U, 3);
    IplImage *result  = NULL;

    assert(py);
    assert(pu);
    assert(pv);
    assert(pu_big);
    assert(pv_big);
    assert(image);

    for (int i = 0; i < w*h; ++i)
    {
        int j = fgetc(fin);
        if (j < 0)
            goto cleanup;
        py->imageData[i] = (unsigned char) j;
    }

    for (int i = 0; i < w*h/4; ++i)
    {
        int j = fgetc(fin);
        if (j < 0)
            goto cleanup;
        pu->imageData[i] = (unsigned char) j;
    }

    for (int i = 0; i < w*h/4; ++i)
    {
        int j = fgetc(fin);
        if (j < 0)
            goto cleanup;
        pv->imageData[i] = (unsigned char) j;
    }

    cvResize(pu, pu_big, CV_INTER_NN);
    cvResize(pv, pv_big, CV_INTER_NN);
    cvMerge(py, pu_big, pv_big, NULL, image);

    result = image;

cleanup:
    cvReleaseImage(&pu);
    cvReleaseImage(&pv);

    cvReleaseImage(&py);
    cvReleaseImage(&pu_big);
    cvReleaseImage(&pv_big);

    if (result == NULL)
        cvReleaseImage(&image);

    return result;
}
于 2011-02-02T15:31:46.933 に答える
1

少なくとも現在のバージョンでは、それは不可能だと思います。もちろん、それほど難しいことではありませんが、次のような興味深い機能ではありません。

  • OpenCV は通常、RGB 形式の Web カメラ ストリーム、または表示目的で RGB に直接デコードされるコード化されたファイルで動作します。
  • OpenCV はコンピューター ビジョンに特化しており、YUV は、たとえばコーディング コミュニティほど一般的ではない形式です。
  • 多くの異なる YUV 形式があり、それらを実装するには多くの作業が必要になります。

ただし、 を使用して変換を行うことは可能cvCvtColor()です。

于 2011-02-02T14:37:58.107 に答える
0

同じ問題が発生しました。私の解決策は 1. 1 つの yuv フレーム (I420 など) を文字列オブジェクト "yuv" に読み取ります。2. yuv フレームを BGR24 形式に変換します。libyuv を使用してそれを行います。libyuv 関数の python ラッパーを書くのは簡単です。これで、BGR24 形式の別の文字列オブジェクト "bgr" を取得できます。3. numpy.fromstring を使用して、「bgr」文字列オブジェクトから画像オブジェクトを取得します。画像オブジェクトの形状を変更する必要があります。

以下は、参照用の単純な yuv ビューアーです。

import cv2
# below is the extension wrapper for libyuv
import yuvtorgb
import numpy as np

f = open('i420_cif.yuv', 'rb')

w = 352
h = 288
size = 352*288*3/2

while True:
    try:
        yuv = f.read(size)
    except:
        break
    if len(yuv) != size:
        f.seek(0, 0)
        continue

    bgr = yuvtorgb.i420_to_bgr24(yuv, w, h)

    img = np.fromstring(bgr, dtype=np.uint8)
    img.shape = h,w,3

    cv2.imshow('img', img)

    if cv2.waitKey(50) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
于 2015-01-29T09:16:46.143 に答える