2010-02-09 86 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