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. virtualbox的Linux虚拟磁盘大小调整及注意事项

    virtualBox 调整磁盘分区 起因 起初安装centos6.3 时,没有修改默认的硬盘空间.只有8G,导致后面安装完zookeeper,jdk之后,在安装mysql发现磁盘空间不足 扩容步骤 1 ...

  2. AgileBoot - 手把手一步一步带你Run起全栈项目(SpringBoot+Vue3)

    AgileBoot是笔者在业余时间基于ruoyi改造优化的前后端全栈项目. 关于AgileBoot的详细介绍:https://www.cnblogs.com/valarchie/p/16777336. ...

  3. Morris 遍历实现二叉树的遍历

    Morris 遍历实现二叉树的遍历 作者:Grey 原文地址: 博客园:Morris 遍历实现二叉树的遍历 CSDN:Morris 遍历实现二叉树的遍历 说明 Morris 遍历可以实现二叉树的先,中 ...

  4. 某OA系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该请假条;如果员工请假天数大于等于3天,小于10天,经理可以审批;如果员工请假天数大于等于10天,小于30天,总经理可以审批

    某OA系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该请假条:如果员工请假天数大于等于3天,小于10天,经理可以审批:如果员工请假天数大于等于10天,小于30天,总经理可以审批 ...

  5. break ,continue,retrun的区别

    break ,continue,retrun的区别 1:break 在循环体内结束整个循环过程 for (var i = 1; i <= 5; i++) { if(i == 3){ break; ...

  6. 深入浅出redis缓存应用

    0.1.索引 https://blog.waterflow.link/articles/1663169309611 1.只读缓存 只读缓存的流程是这样的: 当查询请求过来时,先从redis中查询数据, ...

  7. Java多线程(5):CAS

    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 在JDK1.5之前,Java的多线程都是靠synchronized来保证同步的,这会引起很多性能问题,例如死锁.但随着Java的不断完善,JNI ...

  8. Java 编码那些事(二)

    建议先阅读:Java 编码那些事(一) 现在说说编码在Java中的实际运用.在使用tomcat的时候,绝大部分同学都会遇到乱码的问题,查查文档,google一下解决方案啥的,都是设置这里,设置那里,或 ...

  9. LoadRunner11脚本小技能之添加请求头+定义变量+响应内容乱码转换打印+事务拆分

    一.添加请求头 存在一些接口,发送请求时需要进行权限验证.登录验证(不加请求头时运行脚本,接口可能会报401等等),所以需要在脚本中给对应请求添加请求头.注意:请求头需在请求前添加,包含url类.su ...

  10. Java继承Frame画一个窗口显示图片

    将图片显示到窗口上. 在工程目录下准备好图片5.png 运行代码: import javax.imageio.ImageIO; import java.awt.*; import java.awt.e ...