• yuv420p转RGB


    yuv420是用4个byte存储4个Y的信息,用1个Byte存储U的信息,一个Byte存储V的信息,
    这4个Y共用这2个U和V ,也就是用6个Byte 存储4个像素信息,也就是一个像素需要12个Bits(6*8/4),也就是12bpp。
    注意yuv420p里面的p是指planar,也就是分层存储,先存全部Y的信息,然后是U的信息,最后是V的信息,
    或者这样说: 如果把一个图片按yuv420p的格式保存为二进制数据文件,那么把这个文件均分为6份,那么前面的4份是Y,第5份是U,第6份是V。

    以下程序的流程是:

    1 使用 ffmpeg 先将一张图片保存为 yuv420p的数据文件。
    2 使用下面的程序读取此文件,然后将yuv数据转为rgb,最后使用opencv保存为jpg格式的图片。
    3 主要是熟悉yuv420p的数据格式,以及熟悉yuv如何转为RGB。
    4 最后就是使用opencv将RGB数据保存为图片,注意opencv是需要BGR的数据.

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    using namespace cv;
    
    #define  IMAGE_W 1280
    #define  IMAGE_H 720
    
    #define  FILE_NAME "output420.yuv"
    
    int convert_yuv_to_rgb_pixel(int y, int u, int v) {
    	unsigned int pixel32 = 0;
    	unsigned char *pixel = (unsigned char*) &pixel32;
    	int r, g, b;
    	r = y + (1.370705 * (v - 128));
    	g = y - (0.698001 * (v - 128)) - (0.337633 * (u - 128));
    	b = y + (1.732446 * (u - 128));
    
    	if (r > 255)
    		r = 255;
    	if (g > 255)
    		g = 255;
    	if (b > 255)
    		b = 255;
    	if (r < 0)
    		r = 0;
    	if (g < 0)
    		g = 0;
    	if (b < 0)
    		b = 0;
       //注意opencv是需要BGR的数据
    	pixel[0] = b;  // blue
    	pixel[1] = g;  // green
    	pixel[2] = r;  //red
    	return pixel32;
    }
    
    int convert_yuv420p_to_rgb888_buffer(unsigned char *yuv, unsigned char *rgb,
    		unsigned int width, unsigned int height) {
    	unsigned int pixel32;
    	unsigned char *ptr = rgb;
    	int y0, y1, y2, y3, u, v;
    	int i = 0;
    	unsigned char *a = yuv + width * height * 0;
    	unsigned char *b = yuv + width * height * 1;
    	unsigned char *c = yuv + (int) (width * height * 1.25);
    
    	while (i < width * height) {
    		i += 4;
    		u = *(b++);
    		v = *(c++);
    		for (int j = 0; j < 4; j++) {
    			y0 = *(a++);
    			pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);
    			*(ptr++) = (pixel32 & 0x000000ff);
    			*(ptr++) = (pixel32 & 0x0000ff00) >> 8;
    			*(ptr++) = (pixel32 & 0x00ff0000) >> 16;
    		}
    
    	}
    	return 0;
    }
    
    /**
     * 	 yuyv420p to rgb to jpg.
     *   ffmpeg -i in.jpg -pix_fmt yuv420p output420.yuv -y
     *   ffmpeg  -pix_fmts
     *   yuyv420 use 12bits to store 1 pixes.
     *
     */
    int main() {
    	int ret;
    	int fd = open(FILE_NAME, O_RDWR);
    	if (ret == -1) {
    		perror("open");
    		return -1;
    	}
    	unsigned char yuv[IMAGE_W * IMAGE_H * 3 + 1000];
    
    	ret = read(fd, yuv, IMAGE_W * IMAGE_H * 3 + 1000);
    	if (ret == -1) {
    		perror("read");
    		return -1;
    	}
    
    	assert(ret == IMAGE_W * IMAGE_H * 12 / 8);
    	char rgb24[IMAGE_W * IMAGE_H * 3];
    	convert_yuv420p_to_rgb888_buffer((unsigned char*) yuv,
    			(unsigned char*) rgb24,
    			IMAGE_W, IMAGE_H);
    	Mat image(IMAGE_H, IMAGE_W, CV_8UC3, rgb24);
    	imwrite("output.jpg", image);
    	cout << "success" << endl;
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    如果有任何问题,欢迎评论。

  • 相关阅读:
    新电脑重装系统好吗?电脑重装系统的好坏
    【C++】set & multiset
    SHELL (bash)编程记录
    微服务的定义
    【Spring面试】Spring事务(图文详解)
    基于PyTorch使用LSTM实现新闻文本分类任务
    错误: 找不到或无法加载主类 IpAddressTest
    浅析GC-垃圾回收
    Java Thread.yield()方法具有什么功能呢?
    oracle---一表向另一表循环插入数据过程中、发现异常并抛进日志表、直至数据传输完成
  • 原文地址:https://blog.csdn.net/oHeHui1/article/details/127984399