12 yuv420转换为rgb(opencv mat)

yuv格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式,而且自己造轮子工作量太大。因此通常都会将yuv转换为rgb,再用opencv等视觉库进行图像处理。

yuv转换为rgb有多种方法,比如公式法。但是推荐使用第三方库进行转换,比如ffmpeg,libyuv,opencv。其中ffmpeg是专门的视频音频处理软件,libyuv是谷歌开发的专门用于yuv基本图像处理(如旋转,缩放,格式转换)的视频库,libyuv主要用于android端。

ffmpeg,libyuv,opencv都是开源的。可以在网上查找资料。

本文简单介绍ffmpeg和libyuv的安装,opencv的安装教程很多就不介绍了。具体见文章:

https://blog.csdn.net/weixin_39393712/article/details/79583274

ffmpeg和libyuv 的安装:

下载最新的ffmpeg的dev版和share版,ffmpeg严格区分x64和x86。下载网站为:

http://ffmpeg.zeranoe.com/builds/

Libyuv需要编译源文件,源文件地址:

https://chromium.googlesource.com/libyuv/libyuv/

https://github.com/seungrye/libyuv

编译步骤见:

https://blog.csdn.net/aabcd123456/article/details/78982528

获得源文件后先建立vs工程,然后将ffmpegdev版本文件夹中的include和lib整个目录复制到vs工程目录下。如图所示:

对于libyuv的libyuv文件和lib文件,将其分别复制到vs工程目录下的include目录和lib目录。如图所示:

通常include中包含的是所调用库头文件,lib包含的是静态链接库,当然ffmpeg需要将其动态链接库复制到vs工程目录下,即将ffmpeg,share版本文件夹中bin目录下对应的所有dll复制到项目路径下如图所示::

Dll和lib是windows系统下的动态链接库和静态链接库,linux系统下的静态链接库以.a结尾,linux系统下的动态链接库以.so或.so.y结尾。具体可以见文章:

https://www.cnblogs.com/general001/articles/3567446.html

对于ffmpeg,libyuv在linux系统下的编译使用,通过编译下载相关源代码,通过cmake或者make命令进行项目构建。推荐使用cmake软件,cmake非常有用,应用十分广泛。入门教程见:

http://www.cnblogs.com/52php/p/5681745.html

在windows平台下,通过vs就能够减少大量工作。vs平台链接ffmpeg和libyuv的头文件和lib文件,先在项目工程属性>C/C++>常规>附加包含目录,添加include目录,但是ffmpeg有许多错误,vs通常会开启SDL检查后,某些警告会成为错误。所以将sdl检查置为否。如下图所示:

接着在在项目工程属性>链接器>常规>附加库目录下,添加lib文件夹,如下图所示:

最后如果使用ffmpeg和libyuv库,需要添加头文件完成整个工作的配置。代码如下:

extern "C"

{

#include "include\libavcodec\avcodec.h"

#include "include\libavformat\avformat.h"

#include "include\libavutil\channel_layout.h"

#include "include\libavutil\common.h"

#include "include\libavutil\imgutils.h"

#include "include\libswscale\swscale.h"

#include "include\libavutil\imgutils.h"

#include "include\libavutil\opt.h"

#include "include\libavutil\mathematics.h"

#include "include\libavutil\samplefmt.h"

//libyuv

#include "include\libyuv\libyuv.h"

};

#pragma comment(lib, "avcodec.lib")

#pragma comment(lib, "avformat.lib")

#pragma comment(lib, "avdevice.lib")

#pragma comment(lib, "avfilter.lib")

#pragma comment(lib, "avutil.lib")

#pragma comment(lib, "postproc.lib")

#pragma comment(lib, "swresample.lib")

#pragma comment(lib, "swscale.lib")

//libyuv

#pragma comment(lib, "yuv.lib")

yuv420转rgb

接下来通过ffmpeg,libyuv,opencv实现yuv420转rgb,并进行性能分析。函数的代码如下所示:

/**
* @file 12 yuv_transform.cpp
* @author luohen
* @brief YUV image transform to opencv rgb image
* @date 2018-12-11
*
*/ #include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <time.h> extern "C"
{
#include "include\libavcodec\avcodec.h"
#include "include\libavformat\avformat.h"
#include "include\libavutil\channel_layout.h"
#include "include\libavutil\common.h"
#include "include\libavutil\imgutils.h"
#include "include\libswscale\swscale.h"
#include "include\libavutil\imgutils.h"
#include "include\libavutil\opt.h"
#include "include\libavutil\mathematics.h"
#include "include\libavutil\samplefmt.h"
//libyuv
#include "include\libyuv\libyuv.h"
};
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")
//libyuv
#pragma comment(lib, "yuv.lib") using namespace std;
using namespace cv; /**
* @brief
*
* @param pYUV input yuv420 image
* @param pBGR24 output bgr24 image
* @param width width of input yuv420p image
* @param height height of input yuv420p image
* @return
*/
bool ffmpeg_yuv2bgr(unsigned char *pYUV, unsigned char *pBGR24, int width, int height)
{
AVPicture pFrameYUV, pFrameBGR; avpicture_fill(&pFrameYUV, pYUV, AV_PIX_FMT_YUV420P, width, height);
avpicture_fill(&pFrameBGR, pBGR24, AV_PIX_FMT_BGR24, width, height); struct SwsContext *imgCtx = NULL;
//初始化函数
//原图高,宽,图像类型;输出图高,宽,图像类型;算法种类;其他
imgCtx = sws_getContext(width, height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_BGR24, SWS_BILINEAR, 0, 0, 0); if (imgCtx != NULL)
{
//执行函数
//函数返回值;输入图像指针数组,图像颜色通道数组;扫描起点;扫描行数;输出图像指针数组,图像颜色通道数组;
sws_scale(imgCtx, pFrameYUV.data, pFrameYUV.linesize, 0, height, pFrameBGR.data, pFrameBGR.linesize);
//end
if (imgCtx)
{
sws_freeContext(imgCtx);
imgCtx = NULL;
}
return true;
}
else
{
sws_freeContext(imgCtx);
imgCtx = NULL;
return false;
}
} /**
* @brief transform function of ffmpeg
*
* @param w width of input yuv420p image
* @param h height of input yuv420p image
* @param pic input yuv image
* @return Mat output rgb image(opencv mat)
*/
Mat yuv420_ffmpeg(int w, int h, unsigned char *pic)
{
Mat bgrImg(h, w, CV_8UC3);
unsigned char *pBGR24 = new unsigned char[w * h * 3];
ffmpeg_yuv2bgr(pic, bgrImg.data, w, h); return bgrImg;
} /**
* @brief transform function of libyuv
*
* @param w width of input yuv420p image
* @param h height of input yuv420p image
* @param pic input yuv image
* @return Mat output rgb image(opencv mat)
*/
Mat yuv420_libyuv(int w, int h, unsigned char *pic)
{
int size_src = w * h * 3 / 2;
int size_dest = w * h * 4; //BGRA, A:Alpha(transparency,透明度)
Mat matI420 = cv::Mat(h, w, CV_8UC4); libyuv::I420ToARGB((const uint8 *)pic, w,
(const uint8 *)(pic + w * h), w / 2,
(const uint8 *)(pic + w * h * 5 / 4), w / 2,
matI420.data, w * 4, w, h);
//bgr
Mat bgrImg;
cvtColor(matI420, bgrImg, COLOR_BGRA2BGR);
return bgrImg;
} /**
* @brief
*
* @param w
* @param h
* @param pic
* @return Mat
*/
Mat yuv420_opencv(int w, int h, unsigned char *pic)
{
//创建YUV mat
cv::Mat yuvImg;
yuvImg.create(h * 3 / 2, w, CV_8UC1);
//数据保存为yuvImg.data
memcpy(yuvImg.data, pic, w * h * 3 / 2 * sizeof(unsigned char)); //转化为RGB图像
cv::Mat bgrImg;
cv::cvtColor(yuvImg, bgrImg, CV_YUV2BGR_I420); return bgrImg;
} /**
* @brief main
*
* @return int
*/
int main()
{
clock_t start, end;
double endtime;
//Frequency of reading image
int count_frame = 300;
//视频路径
char *url = (char *)"video/akiyo.yuv";
int w = 352, h = 288;
FILE *input_fp;
if ((input_fp = fopen(url, "rb")) == NULL)
{
printf("%s open error!\n", url);
return -1;
}
else
{
printf("%s open.\n", url);
} unsigned char *pYuvBuf = new unsigned char[w * h * 3 / 2]; fseek(input_fp, 0, SEEK_SET);
//Timing starts
start = clock();
Mat ffmpeg_mat;
for (int i = 0; i < count_frame; i++)
{
fread(pYuvBuf, sizeof(unsigned char), w * h * 3 / 2, input_fp);
ffmpeg_mat = yuv420_ffmpeg(w, h, pYuvBuf);
} //Timing end
end = clock();
endtime = (double)(end - start) / CLOCKS_PER_SEC;
cout << "ffmpeg Total time:" << endtime << "s" << endl;
cout << "ffmpeg Total time:" << endtime * 1000 << "ms" << endl; fseek(input_fp, 0, SEEK_SET);
start = clock();
Mat libyuv_mat;
for (int i = 0; i < count_frame; i++)
{
fread(pYuvBuf, sizeof(unsigned char), w * h * 3 / 2, input_fp);
libyuv_mat = yuv420_libyuv(w, h, pYuvBuf);
}
end = clock();
endtime = (double)(end - start) / CLOCKS_PER_SEC;
cout << "libyuv Total time:" << endtime << "s" << endl; //s为单位
cout << "libyuv Total time:" << endtime * 1000 << "ms" << endl; //ms为单位 fseek(input_fp, 0, SEEK_SET);
start = clock();
Mat opencv_mat;
for (int i = 0; i < count_frame; i++)
{
fread(pYuvBuf, sizeof(unsigned char), w * h * 3 / 2, input_fp);
opencv_mat = yuv420_opencv(w, h, pYuvBuf);
}
end = clock();
endtime = (double)(end - start) / CLOCKS_PER_SEC;
cout << "opencv Total time:" << endtime << "s" << endl;
cout << "opencv Total time:" << endtime * 1000 << "ms" << endl; system("pause");
return 0;
}

调用函数为:

Mat yuv420_ffmpeg(int w, int h, unsigned char *pic);

Mat yuv420_libyuv(int w, int h, unsigned char *pic);

Mat yuv420_opencv(int w, int h, unsigned char *pic);

这段代码主要是分别用ffmpeg,libyuv,opencv实现yuv420转换为rgb,每种方法转换300张yuv420图像。对比三种方法转换所用时间,结果如下:

综合三种方法来说,ffmpeg速度最快,且ffmpeg最常用,因此推荐使用ffmpeg。如果仅仅对yuv图像进行处理或者android端,libyuv最为推荐。如果是安装ffmpeg或者libyuv较为麻烦,仅限于研究项目,建议使用opencv。

[图像处理] YUV图像处理入门5的更多相关文章

  1. [图像处理] YUV图像处理入门1

    目前数字图像处理技术已经应用生活各个方面,但是大部分教程都是利用第三方库(如opencv)对RGB图像格式进行处理.对于YUV图像格式的图像处理教程较少.于是博主搬运总结了多个大牛的文章,总结出来这个 ...

  2. [图像处理] YUV图像处理入门2

    1 分离YUV420中YUV分量 本程序中的函数主要是将YUV420P视频数据流的第一帧图像中的Y.U.V三个分量分离开并保存成三个文件.函数的代码如下所示: /** * @file 1 yuv_sp ...

  3. [图像处理] YUV图像处理入门4

    9 yuv420图像截取 本程序中的函数主要是对YUV420P视频数据流的第一帧图像进行截取.类似opencv中的rect函数,函数的代码如下所示: /** * @file 9 yuv_clip.cp ...

  4. [图像处理] YUV图像处理入门3

    5 yuv420格式的灰阶测试图 本程序中的函数主要是为YUV420P视频数据流的第一帧图像添加边框.函数的代码如下所示: /** * @file 5 yuv_graybar.cpp * @autho ...

  5. Python图像处理库Pillow入门

    http://python.jobbole.com/84956/ Pillow是Python里的图像处理库(PIL:Python Image Library),提供了了广泛的文件格式支持,强大的图像处 ...

  6. MATLAB图像处理_Bayer图像处理 & RGB Bayer Color分析

    Bayer图像处理   Bayer是相机内部的原始图片, 一般后缀名为.raw. 很多软件都可以查看, 比如PS. 我们相机拍照下来存储在存储卡上的.jpeg或其它格式的图片, 都是从.raw格式转化 ...

  7. 打基础丨Python图像处理入门知识详解

    摘要:本文讲解图像处理基础知识和OpenCV入门函数. 本文分享自华为云社区<[Python图像处理] 一.图像处理基础知识及OpenCV入门函数>,作者: eastmount. 一.图像 ...

  8. Atitit 图像处理知识点  知识体系 知识图谱v2

    Atitit 图像处理知识点  知识体系 知识图谱v2 霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法.主要用来从图像 ...

  9. Atitit 图像处理知识点  知识体系 知识图谱

    Atitit 图像处理知识点  知识体系 知识图谱 图像处理知识点 图像处理知识点体系 v2 qb24.xlsx 基本知识图像金字塔op膨胀叠加混合变暗识别与检测分类肤色检测other验证码生成 基本 ...

随机推荐

  1. Docker | 镜像浅析,以及制作自己的镜像

    分层下载,docker image 的核心: 联合文件系统 镜像是什么 镜像就是一个轻量的.独立的软件包.用来打包运行环境和基于运行环境开发的软件.它包含软件运行所需的所有内容(包括代码.运行时.库. ...

  2. FastJson序列化对象复杂时出错问题解决

    FastJson序列化对象复杂时出错问题解决 针对复杂的对象,如Map<String, List<Map<String, XxxObject<A, B, C>>&g ...

  3. python批量加密文件

    1.文件名的加密与解密 #coding:utf-8 from docx import Document import os,sys from docx.oxml.ns import qn def fi ...

  4. 分布式ID生成方案总结整理

    目录 1.为什么需要分布式ID? 2.业务系统对分布式ID有什么要求? 3.分布式ID生成方案 3.1 UUID 3.2.数据库自增 3.3.号段模式 3.4. Redis实现 3.4. 雪花算法(S ...

  5. vim常用快捷键总结一(光标移动命令)

    vim编辑器的工作模式分为3种即(命令模式,编辑模式和尾行模式),具体定义这里就不在赘述了,这里只简单介绍各工作模式下对应的操作和快捷方式. 通常来说三三种模式功能划分大致如下 命令模式:定位.翻页. ...

  6. fltp备份文件后统计验证

    上一篇(https://www.cnblogs.com/jying/p/16805821.html)记录了自己在centos使用lftp备份文件的过程,本篇记录自己对备份后的文件与源文件目录的对比统计 ...

  7. ES6高级编程(一)

    一.JavaScript概要 1.1.JavaScript组成 JavaScript主要由三部分构成,分别是ECMAScript.DOM与BOM ECMAScript定义了该语言的语法.类型.语句.关 ...

  8. CAN总线数据链路层(一)

    1.通信机制 发送报文. 1.首先检测Bus状态,空闲 则发送 报文且回读         2.线与机制,若有两个节点同时发报文          报文结构:          通过ID进行仲裁(规则 ...

  9. kubernetes_CoreDNS全解析

    一.前言 kubernetes CoreDNS 是 kube-system 命令空间里面的一个Pod,用于域名解析. kubernetes自带三个命名空间(用kubeadm安装的Kubernetes集 ...

  10. <四>理解空间配置器allocator, 优化STL 中的Vector

    .在上一节我们实现的 MyVector存在哪些问题? 问题1 现在有Student类 class Student{ public: Student(){cout<<"构造Stud ...