2010-02-09 84 views

回答

0

我不認爲這是可能的,至少在目前的版本。當然,這樣做並不難,但它不是那麼有趣的功能,因爲:

  • OpenCV通常適用於RGB格式的網絡攝像頭流或編碼文件,它們是直接解碼爲RGB以用於顯示目的;
  • OpenCV致力於計算機視覺,其中YUV是一種比在編碼社區中不太常見的格式;
  • 有很多不同的YUV格式,這意味着很多工作來實現它們。

儘管使用cvCvtColor(),轉換仍然是可能的,這意味着它仍然有一些利益。

3

UPDATE這裏有代碼的一個新版本:https://github.com/chelyaev/opencv-yuv

我張貼一些代碼,會讀一個單一 YUV 4:2:0平面圖像文件。您可以直接將其應用於大多數YUV文件(只需繼續讀取相同的FILE對象)。 例外這是當處理YUV files that have a header(通常,他們有一個*.y4m擴展名)。如果要對付這樣的文件,你有兩個選擇:

  1. 寫自己的函數使用下面的代碼
  2. 剝去* .y4m圖像頭之前消耗從FILE對象的報頭數據(使用ffmpeg或類似的工具)。這是我喜歡的選項,因爲它是最簡單的。

它也不適用於任何其他形式的YUV格式(非平面,不同的色度抽取)。正如@Stephane指出的,有很多這樣的格式(其中大多數沒有任何標識頭),這可能是OpenCV不支持它們的原因。

但與他們的合作是相當簡單:

  • 開始用圖像和它的尺寸
  • 讀取亮度和色度分爲3個獨立的圖像
  • 高檔(該讀YUV文件時需要)色度圖像減少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; 
} 
+0

我現在有同樣的問題,我試圖打開並使用具有UYVY視頻工作(4:2:2)編解碼器,我想你的代碼,但它沒有工作,我知道,你在回答中提到過,但你能否說出原因?在此先感謝您的幫助 – Engine 2013-02-13 10:09:08

+1

我發佈的代碼處理YUV 4:2:0。由於您的視頻採用YUV 4:2:2格式,因此我的代碼無法直接在您的視頻上播放。您需要修改代碼來處理您的格式。有關更多詳細信息,請參閱:http://en.wikipedia.org/wiki/Chroma_subsampling#4:2:2 – misha 2013-02-14 04:21:46

0

我遇到同樣的問題。我的解決方案是 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() 
4

如前所述,有許多類型的YUV格式:

http://www.fourcc.org/yuv.php

要從OpenCV的YUV格式轉換爲RGB格式很簡單:

  1. 創建一個用於該幀數據的適當尺寸的三維OpenCV Mat
  2. 用所需的d爲RGB數據創建一個空Mat imension並用3個信道
  3. 最後使用cvtColor於兩個墊之間進行轉換,使用正確的轉換標誌枚舉

這裏是一個例子用於YUV緩衝在YV12格式:

Mat mYUV(height + height/2, width, CV_8UC1, (void*) frameData); 
Mat mRGB(height, width, CV_8UC3); 
cvtColor(mYUV, mRGB, CV_YUV2RGB_YV12, 3); 

關鍵技巧是在您轉換之前定義您的RGB墊的尺寸

+0

這是正確答案。 我正在處理YUV的NV12變化,這些幫助我瞭解了格式: https://wiki.videolan.org/YUV/#NV12,https://commons.wikimedia.org/wiki/File:Common_chroma_subsampling_ratios .SVG – rhardih 2016-10-11 13:05:05

2

我寫了一個非常簡單的python代碼來讀取二進制文件中的YUV NV21流。

import cv2 
import numpy as np 

class VideoCaptureYUV: 
    def __init__(self, filename, size): 
     self.height, self.width = size 
     self.frame_len = self.width * self.height * 3/2 
     self.f = open(filename, 'rb') 
     self.shape = (int(self.height*1.5), self.width) 

    def read_raw(self): 
     try: 
      raw = self.f.read(self.frame_len) 
      yuv = np.frombuffer(raw, dtype=np.uint8) 
      yuv = yuv.reshape(self.shape) 
     except Exception as e: 
      print str(e) 
      return False, None 
     return True, yuv 

    def read(self): 
     ret, yuv = self.read_raw() 
     if not ret: 
      return ret, yuv 
     bgr = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR_NV21) 
     return ret, bgr 


if __name__ == "__main__": 
    #filename = "data/20171214180916RGB.yuv" 
    filename = "data/20171214180916IR.yuv" 
    size = (480, 640) 
    cap = VideoCaptureYUV(filename, size) 

    while 1: 
     ret, frame = cap.read() 
     if ret: 
      cv2.imshow("frame", frame) 
      cv2.waitKey(30) 
     else: 
      break