YUV2RGB Opencv
来源:互联网 发布:java香港空间 编辑:程序博客网 时间:2024/06/04 18:15
YUV2RGB OpenCV(C/C++/Python)
参考:
百度百科:YUV
维基百科:YUV
YUV Colorspace:http://softpixel.com/~cwright/programming/colorspace/yuv/
YUV420P格式分析:https://my.oschina.net/u/589963/blog/167766
YUV
是一种颜色编码方法
Y
分量表示颜色的亮度(luminance
),单取出 Y
分量就是图像的灰度图;U
、V
分量表示颜色色度或者浓度(Chrominance
)
YUV
图像有两种编码格式:
- 紧缩格式(
packed formats
):Y
、U
、V
三通道像素值依次排列,即Y0 U0 V0 Y1 U1 V1 ...
- 平面格式(
planar formats
):先排列Y
分量的所有像素值,再排列U
分量的,最后排列V
分量的
Note:平面模式适合采样(subsample
)
由于人眼对于亮度的敏感度远大于色度,所以减少 U
、V
分量并不会过多损害图像的质量,从而减少了数据量,达到压缩的目的
YUV444
表示图像完全采样,没有压缩,紧缩格式YUV420p
表示图像2:1
的水平取样,垂直2:1
采样,即每4
个Y
分量对应一个U
、V
分量,平面模式
Note:YUV420p
(有时简称为 YUV420
) 是常见的图像格式,接下来进行的 YUV
和 RGB
的转换操作都是针对 420p
格式的
YUV
和 RGB
之间的转换公式如下:
R = Y + 1.4075 * (V - 128)G = Y - 0.3455 * (U - 128) - (0.7169 * (V - 128))B = Y + 1.7790 * (U - 128)Y = R * .299000 + G * .587000 + B * .114000U = R * -.168736 + G * -.331264 + B * .500000 + 128V = R * .500000 + G * -.418688 + B * -.081312 + 128
Note:假定各分量之间的取值范围均为 [0, 255]
主要内容
C++
:YUV420p
转RGB
C++
:关键函数介绍Python
:YUV420p
转RGB
方法一Python
:关键函数介绍Python
:YUV420p
转RGB
方法二Python
:关键函数介绍C
:YUV420p
转RGB
C
:关键函数介绍YUV
图片资源
C++
:YUV420p
转 RGB
C++
:YUV420p
转 RGB
首先读取
YUV
格式图片,是二进制文件;打开图像文件,按字节读取,并赋值到新建的图像中,其中,Y
分量图像大小和结果图像大小一致,U
、V
分量图像大小比结果图像小一倍;按顺序读取Y
分量,再读取U
、V
分量vector<Mat> readYUV(char* image_path, int width, int height) { ifstream fin; fin.open(image_path, ios::binary); if (!fin.is_open()) { cout << "open failed" << endl; exit(0); } Mat img_Y = Mat::zeros(height, width, CV_8UC1); char ch; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { fin.read(&ch, sizeof(ch)); img_Y.at<uchar>(i, j) = (uchar)ch; } } Mat img_U = Mat::zeros(height / 2, width / 2, CV_8UC1); for (int i = 0; i < height / 2; i++) { for (int j = 0; j < width / 2; j++) { fin.read(&ch, sizeof(ch)); img_U.at<uchar>(i, j) = (uchar)ch; } } Mat img_V = Mat::zeros(height / 2, width / 2, CV_8UC1); for (int i = 0; i < height / 2; i++) { for (int j = 0; j < width / 2; j++) { fin.read(&ch, sizeof(ch)); img_V.at<uchar>(i, j) = (uchar)ch; } } fin.close(); vector<Mat> yuv; yuv.push_back(img_Y); yuv.push_back(img_U); yuv.push_back(img_V); return yuv;}
得到从文件解析出来的各分量后,放大
U
、V
分量和Y
分量同样大小:Mat enlarge(Mat src) { Mat enlarge = Mat::zeros(src.rows*2, src.cols*2, CV_8UC1); resize(src, enlarge, Size(), 2, 2, INTER_CUBIC); return enlarge;}
合并
3
个通道分量:Mat merge(vector<Mat> channels) { int width = channels.at(0).cols; int height = channels.at(0).rows; Mat yuv = Mat::zeros(height, width, CV_8UC3); merge(channels, yuv); return yuv;}
将
YUV
图像转换为RGB
图像(OpenCV
中格式为BGR
):Mat cvtYUV2BGR(Mat yuv) { int width = yuv.cols; int height = yuv.rows; Mat bgr = Mat::zeros(height, width, CV_8UC3); cvtColor(yuv, bgr, COLOR_YUV2BGR); return bgr;}
完整代码如下所示:
#include <iostream>#include <fstream>#include <opencv2\opencv.hpp>using namespace std;using namespace cv;vector<Mat> readYUV(char* image_path, int width, int height) { ifstream fin; fin.open(image_path, ios::binary); if (!fin.is_open()) { cout << "open failed" << endl; exit(0); } Mat img_Y = Mat::zeros(height, width, CV_8UC1); char ch; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { fin.read(&ch, sizeof(ch)); img_Y.at<uchar>(i, j) = (uchar)ch; } } Mat img_U = Mat::zeros(height / 2, width / 2, CV_8UC1); for (int i = 0; i < height / 2; i++) { for (int j = 0; j < width / 2; j++) { fin.read(&ch, sizeof(ch)); img_U.at<uchar>(i, j) = (uchar)ch; } } Mat img_V = Mat::zeros(height / 2, width / 2, CV_8UC1); for (int i = 0; i < height / 2; i++) { for (int j = 0; j < width / 2; j++) { fin.read(&ch, sizeof(ch)); img_V.at<uchar>(i, j) = (uchar)ch; } } fin.close(); vector<Mat> yuv; yuv.push_back(img_Y); yuv.push_back(img_U); yuv.push_back(img_V); return yuv;}Mat enlarge(Mat src) { Mat enlarge = Mat::zeros(src.rows*2, src.cols*2, CV_8UC1); resize(src, enlarge, Size(), 2, 2, INTER_CUBIC); return enlarge;}Mat merge(vector<Mat> channels) { int width = channels.at(0).cols; int height = channels.at(0).rows; Mat yuv = Mat::zeros(height, width, CV_8UC3); merge(channels, yuv); return yuv;}Mat cvtYUV2BGR(Mat yuv) { int width = yuv.cols; int height = yuv.rows; Mat bgr = Mat::zeros(height, width, CV_8UC3); cvtColor(yuv, bgr, COLOR_YUV2BGR); return bgr;}int main(int argc, char* argv[]) { int width = 640; int height = 480; //char* image_path = "c:\\yuv\\img_yuv"; char* image_path = "c:\\yuv\\jpgimage1_image_640_480.yuv"; vector<Mat> temp = readYUV(image_path, width, height); vector<Mat> channels; channels.push_back(temp.at(0)); channels.push_back(enlarge(temp.at(1))); channels.push_back(enlarge(temp.at(2))); Mat yuv = merge(channels); Mat bgr = cvtYUV2BGR(yuv); //Mat yuv = Mat::zeros(height, width, CV_8UC3); //merge(channels, yuv); //Mat bgr = Mat::zeros(height, width, CV_8UC3); //cvtColor(yuv, bgr, COLOR_YUV2BGR); imshow("img", bgr); waitKey(0); return 0;}
C++
:关键函数介绍
C++
:关键函数介绍fin.open(image_path, ios::binary);
参考:std::ifstream::open
原型:
void open (const char* filename, ios_base::openmode mode = ios_base::in);
参数介绍:
image_path
- filename
,指定打开的文件名
ios::binary
- mode
,操作文件的方式,ios::binary
表明已二进制模式操作而不是文本模式(Operations are performed in binary mode rather than text.
)
Mat img_Y = Mat::zeros(height, width, CV_8UC1);
参考:Mat::zeros
原型:
static MatExpr Mat::zeros(int rows, int cols, int type)
参数介绍:
height
- rows
,行数,即图像高
width
- cols
,列数,即图像宽
CV_8UC1
- type
,图像类型,此处为单通道无符号 8
位整数
fin.read(&ch, sizeof(ch));
参考:std::istream::read
原型:
istream& read (char* s, streamsize n);
参数介绍:
&ch
- s
,字符指针,保存提取的数据
sizeof(ch)
- n
,提取的字节数
img_Y.at<uchar>(i, j) = (uchar)ch;
参考:Mat::at
原型:
template<typename T> T& Mat::at(int i, int j)
函数功能:返回指定数组元素的索引
Python
:YUV420p
转 RGB
Python
:YUV420p
转 RGB
在网上找到一个参考:
Python读取YUV
能够运行(import Image
改成 from PIL import Image
),不过他使用的是 PIL
模块,目前最常用的图像处理库是 OpenCV
在知乎上的一个讨论,给了我灵感:
Python如何正确读取YUV二进制文件(为数字)?
读取二进制图像文件并解析为
Y
,U
,V
单通道图像:def read_YUV420(image_path, rows, cols): """ 读取YUV文件,解析为Y, U, V图像 :param image_path: YUV图像路径 :param rows: 给定高 :param cols: 给定宽 :return: 列表,[Y, U, V] """ # create Y gray = np.zeros((rows, cols), np.uint8) print type(gray) print gray.shape # create U,V img_U = np.zeros((rows / 2, cols / 2), np.uint8) print type(img_U) print img_U.shape img_V = np.zeros((rows / 2, cols / 2), np.uint8) print type(img_V) print img_V.shape with open(image_path, 'rb') as reader: for i in xrange(rows): for j in xrange(cols): gray[i, j] = ord(reader.read(1)) for i in xrange(rows / 2): for j in xrange(cols / 2): img_U[i, j] = ord(reader.read(1)) for i in xrange(rows / 2): for j in xrange(cols / 2): img_V[i, j] = ord(reader.read(1)) return [gray, img_U, img_V]
合并单通道图像并转换为
RGB
图像:def merge_YUV2RGB_v1(Y, U, V): """ 转换YUV图像为RGB格式(放大U、V) :param Y: Y分量图像 :param U: U分量图像 :param V: V分量图像 :return: RGB格式图像 """ # Y分量图像比U、V分量图像大一倍,想要合并3个分量,需要先放大U、V分量和Y分量一样大小 enlarge_U = cv2.resize(U, (0, 0), fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC) enlarge_V = cv2.resize(V, (0, 0), fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC) # 合并YUV3通道 img_YUV = cv2.merge([Y, enlarge_U, enlarge_V]) dst = cv2.cvtColor(img_YUV, cv2.COLOR_YUV2BGR) return dst
还有另一种方法
def merge_YUV2RGB_v2(Y, U, V): """ 转换YUV图像为RGB格式(缩小Y) :param Y: Y分量图像 :param U: U分量图像 :param V: V分量图像 :return: RGB格式图像 """ rows, cols = Y.shape[:2] # 先缩小Y分量,合并3通道,转换为RGB格式图像后,再放大至原来大小 shrink_Y = cv2.resize(Y, (cols / 2, rows / 2), interpolation=cv2.INTER_AREA) # 合并YUV3通道 img_YUV = cv2.merge([shrink_Y, U, V]) dst = cv2.cvtColor(img_YUV, cv2.COLOR_YUV2BGR) cv2.COLOR_YUV2BGR_I420 # 放大 enlarge_dst = cv2.resize(dst, (0, 0), fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC) return enlarge_dst
完整代码如下:
# -*- coding: utf-8 -*-import cv2import numpy as npdef read_YUV420(image_path, rows, cols): """ 读取YUV文件,解析为Y, U, V图像 :param image_path: YUV图像路径 :param rows: 给定高 :param cols: 给定宽 :return: 列表,[Y, U, V] """ # create Y gray = np.zeros((rows, cols), np.uint8) print type(gray) print gray.shape # create U,V img_U = np.zeros((rows / 2, cols / 2), np.uint8) print type(img_U) print img_U.shape img_V = np.zeros((rows / 2, cols / 2), np.uint8) print type(img_V) print img_V.shape with open(image_path, 'rb') as reader: for i in xrange(rows): for j in xrange(cols): gray[i, j] = ord(reader.read(1)) for i in xrange(rows / 2): for j in xrange(cols / 2): img_U[i, j] = ord(reader.read(1)) for i in xrange(rows / 2): for j in xrange(cols / 2): img_V[i, j] = ord(reader.read(1)) return [gray, img_U, img_V]def merge_YUV2RGB_v1(Y, U, V): """ 转换YUV图像为RGB格式(放大U、V) :param Y: Y分量图像 :param U: U分量图像 :param V: V分量图像 :return: RGB格式图像 """ # Y分量图像比U、V分量图像大一倍,想要合并3个分量,需要先放大U、V分量和Y分量一样大小 enlarge_U = cv2.resize(U, (0, 0), fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC) enlarge_V = cv2.resize(V, (0, 0), fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC) # 合并YUV3通道 img_YUV = cv2.merge([Y, enlarge_U, enlarge_V]) dst = cv2.cvtColor(img_YUV, cv2.COLOR_YUV2BGR) return dstdef merge_YUV2RGB_v2(Y, U, V): """ 转换YUV图像为RGB格式(缩小Y) :param Y: Y分量图像 :param U: U分量图像 :param V: V分量图像 :return: RGB格式图像 """ rows, cols = Y.shape[:2] # 先缩小Y分量,合并3通道,转换为RGB格式图像后,再放大至原来大小 shrink_Y = cv2.resize(Y, (cols / 2, rows / 2), interpolation=cv2.INTER_AREA) # 合并YUV3通道 img_YUV = cv2.merge([shrink_Y, U, V]) dst = cv2.cvtColor(img_YUV, cv2.COLOR_YUV2BGR) cv2.COLOR_YUV2BGR_I420 # 放大 enlarge_dst = cv2.resize(dst, (0, 0), fx=2.0, fy=2.0, interpolation=cv2.INTER_CUBIC) return enlarge_dstif __name__ == '__main__': rows = 480 cols = 640 image_path = 'C:\\yuv\\jpgimage1_image_640_480.yuv' Y, U, V = read_YUV420(image_path, rows, cols) dst = merge_YUV2RGB_v1(Y, U, V) cv2.imshow("dst", dst) cv2.waitKey(0)
Python
:关键函数介绍
Python
:关键函数介绍gray = np.zeros((rows, cols), np.uint8)
参考:numpy.zeros
原型:
numpy.zeros(shape, dtype=float, order='C')
(rows, cols)
- shape
,数组形状
np.uint8
- dtype
,默认是 float
,当前设置为 8
位无符号整数
with open(image_path, 'rb') as reader:
参考:[open(name[, mode[, buffering]])](https://docs.python.org/2.7/library/functions.html?highlight=open#open)
gray[i, j] = ord(reader.read(1))
参考:ord(c)
原型:ord(c)
函数功能:返回单个字符字符串的整数值
Python
:YUV420p
转 RGB
方法二
Python
:YUV420p
转 RGB
方法二之前的学习,让我又有了另一种更简单的方法
树莓派(Raspberry Pi)中PiCamera+OpenCV的使用
直接上程序:
# -*- coding: utf-8 -*-import cv2import numpy as npif __name__ == '__main__': rows = 240 cols = 320 with open("c:\\zhujian\\yuv\\img2_yuv", 'rb') as reader: bin_y = reader.read(rows * cols) print type(bin_y) print len(bin_y) num_y = np.fromstring(bin_y, np.uint8) print type(num_y) print num_y.shape img_y = np.reshape(num_y, (rows, cols)) print type(img_y) print img_y.shape cv2.imshow("img", img_y) cv2.waitKey(0) bin_u = reader.read(rows * cols / 4) num_u = np.fromstring(bin_u, np.uint8) img_u = np.reshape(num_u, (rows / 2, cols / 2)) bin_v = reader.read(rows * cols / 4) num_v = np.fromstring(bin_v, np.uint8) img_v = np.reshape(num_v, (rows / 2, cols / 2)) enlarge_u = cv2.resize(img_u, dsize=(cols, rows), interpolation=cv2.INTER_CUBIC) print enlarge_u.shape enlarge_v = cv2.resize(img_v, dsize=(cols, rows), interpolation=cv2.INTER_CUBIC) dst = cv2.merge([img_y, enlarge_u, enlarge_v]) bgr = cv2.cvtColor(dst, cv2.COLOR_YUV2BGR) cv2.imshow("dst", bgr) cv2.waitKey(0)
Python
:关键函数介绍
Python
:关键函数介绍num_y = np.fromstring(bin_y, np.uint8)
参考:numpy.fromstring
原型:
numpy.fromstring(string, dtype=float, count=-1, sep='')
函数功能:转换一维包含二进制数据或者文本数据的数组(A new 1-D array initialized from raw binary or text data in a string.
)
img_y = np.reshape(num_y, (rows, cols))
参考:numpy.reshape
原型:
numpy.reshape(a, newshape, order='C')[source]
函数功能:转换数组形状大小,更改后数据变换参考链接(Gives a new shape to an array without changing its data.
)
C
:YUV420p
转 RGB
C
:YUV420p
转 RGB
使用 C
语言进行 YUV
图像的操作,和 C++
类似
- 首先就是对图像文件进行读取,新建空白的
Y
、U
、V
分量,读取二进制图像文件,写入图像中; - 在对
U
、V
分量进行放大,合并3
个分量为一个3
通道 - 转换
YUV
图像为RGB
图像
代码如下:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <cv.h>#include <highgui.h>int main(int argc, char* argv[]) { int width = 640; int height = 480; IplImage* img_Y = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); IplImage* img_U = cvCreateImage(cvSize(width / 2, height / 2), IPL_DEPTH_8U, 1); IplImage* img_V = cvCreateImage(cvSize(width / 2, height / 2), IPL_DEPTH_8U, 1); IplImage* enlarge_U = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); IplImage* enlarge_V = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); IplImage* YUV = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); IplImage* RGB = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); // 打开二进制图像文件 FILE* fp = NULL; if ((fp = fopen("c:\\zhujian\\yuv\\jpgimage1_image_640_480.yuv", "rb")) == NULL) { printf("Error: open file failed\n"); exit(0); } // 读取Y分量 for (int i = 0; i < height; i++) { uchar* ptr = (uchar*)(img_Y->imageData + i*img_Y->widthStep); for (int j = 0; j < width; j++) { ptr[j] = (uchar)fgetc(fp); } } // 读取U分量 for (int i = 0; i < height / 2; i++) { uchar* ptr = (uchar*)(img_U->imageData + i*img_U->widthStep); for (int j = 0; j < width / 2; j++) { ptr[j] = (uchar)fgetc(fp); } } // 读取V分量 for (int i = 0; i < height / 2; i++) { uchar* ptr = (uchar*)(img_V->imageData + i*img_V->widthStep); for (int j = 0; j < width / 2; j++) { ptr[j] = (uchar)fgetc(fp); } } // 读取文件结束后,关闭文件指针 fclose(fp); // 放大U、V分量 cvResize(img_U, enlarge_U, CV_INTER_CUBIC); cvResize(img_V, enlarge_V, CV_INTER_CUBIC); // 合并Y、U、V分量为一个3通道YUV图像 cvMerge(img_Y, enlarge_U, enlarge_V, NULL, YUV); // 转换YUV图像为RGB图像 cvCvtColor(YUV, RGB, CV_YUV2BGR); // 显示图像 cvNamedWindow("img", CV_WINDOW_NORMAL); cvShowImage("img", RGB); cvWaitKey(0); cvDestroyWindow("img"); cvReleaseImage(&RGB); cvReleaseImage(&YUV); cvReleaseImage(&enlarge_V); cvReleaseImage(&enlarge_U); cvReleaseImage(&img_V); cvReleaseImage(&img_U); cvReleaseImage(&img_Y); return 0;}
当前运行环境是 Win7+VS2013+OpenCV2.4.13
,C
版本的 OpenCV
需要在程序结束前消除掉 IplImage
结构体,明显感觉在这个部分速度慢了很多
C
:关键函数介绍
C
:关键函数介绍if ((fp = fopen("c:\\zhujian\\yuv\\jpgimage1_image_640_480.yuv", "rb")) == NULL) {
参考:fopen
原型:
FILE * fopen ( const char * filename, const char * mode );
ptr[j] = (uchar)fgetc(fp);
参考:fgetc
原型:
int fgetc ( FILE * stream );
函数功能:从流中读取一个字符(Get character from stream
)
YUV
图片资源
YUV
图片资源YUV420格式图片 和 视频 测试用
2张yuv格式图像
- YUV2RGB Opencv
- YUV2RGB
- yuv2rgb
- YUV2RGB
- YUV2RGB
- yuv2rgb
- yuv2rgb.c
- YUV2RGB总结
- yuv2rgb 优化
- 【数据压缩】yuv2rgb
- RGB2YUV/YUV2RGB
- formula YUV2RGB RGB2YUV
- android yuv2rgb方案
- YUV2RGB实验报告
- 【数据压缩】RGB2YUV/YUV2RGB实验报告
- 关于YUV2RGB的2篇文章(ZZ)
- 实验一:彩色空间转换(YUV2RGB)
- 《数据压缩》实验报告一·YUV2RGB实验
- 购物车(Java集合框架)
- Firefox显示禁用
- weex使用日记之列表-详情页
- Python集成开发环境Anaconda2及Pytorch与Tensorflow的安装
- redis 持久化技术 之 aof
- YUV2RGB Opencv
- java反射笔记2
- zookeeper系列(一)——简介和原理
- DIV里面的图片水平与垂直居中的方法
- klocwork-11问题汇总
- TCP的状态迁移
- solr入门之edismax权重排序使用之Java代码实现自定义权重
- Spring与WebSocket
- Android客户端与服务器端交互数据之json解析