如何从OpenCV中的YUV文件中读取帧?
答案 0 :(得分:6)
我写了一个非常简单的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
答案 1 :(得分:4)
如上所述,有很多种YUV格式:
在OpenCV中从YUV格式转换为RGB非常简单:
以下是 YV12 格式的YUV缓冲区示例:
Mat mYUV(height + height/2, width, CV_8UC1, (void*) frameData);
Mat mRGB(height, width, CV_8UC3);
cvtColor(mYUV, mRGB, CV_YUV2RGB_YV12, 3);
关键技巧是在转换之前定义RGB Mat 的尺寸。
答案 2 :(得分:3)
更新这里有更新版本的代码:https://github.com/chelyaev/opencv-yuv
我发布的一些代码会读取单个 YUV 4:2:0平面图像文件。您可以直接将其应用于大多数YUV文件(只需继续读取同一个FILE
对象)。 例外是处理YUV files that have a header时(通常,他们有*.y4m
扩展名)。如果您想处理这些文件,您有两种选择:
FILE
对象中的标题数据
ffmpeg
或类似工具)。这是我喜欢的选项,因为它是最简单的。它也不适用于任何其他形式的YUV格式(非平面,不同的色度抽取)。正如@Stephane指出的那样,有许多这样的格式(并且大多数都没有任何标识头),这可能是OpenCV不支持开箱即用的原因。
但与他们合作非常简单:
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;
}
答案 3 :(得分:0)
我认为不可能,至少在目前的版本中。当然,这并不难,但它不是一个有趣的特征,如:
但仍然可以使用cvCvtColor()
进行转化,这意味着无论如何都会引起一些兴趣。
答案 4 :(得分:0)
我遇到了同样的问题。我的解决方案是 1.将一个yuv帧(例如I420)读取到字符串对象&#34; yuv&#34;。 2.将yuv帧转换为BGR24格式。我用libyuv来做。为libyuv函数编写python包装器很容易。现在你得到另一个字符串对象&#34; bgr&#34;使用BGR24格式。 3.使用numpy.fromstring从&#34; bgr&#34;中获取图像对象。字符串对象。你需要改变图像对象的形状。
以下是一个简单的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()
答案 5 :(得分:0)
供以后参考:我已将@xianyanlin's brilliant answer转换为Python3。以下代码适用于从Raspberry Pi相机拍摄的视频,并且似乎输出正确的颜色和纵横比。
警告:它使用numpy格式指定高度*宽度的分辨率,例如1080 * 1920、480 * 640。
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_I420, 3)
return ret, bgr