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. jsp页面重定向后地址栏controller名重复而导致报404错误

    今天做ssm项目时遇到了这种错误 看看代码: 无关代码省略... 22 <body> 23 <div id="container"> 24 <ifra ...

  2. [leetcode]95.不同的二叉搜索树

    Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 95. 不同的二叉搜索树 II 给你 ...

  3. 一天十道Java面试题----第一天(面向对象-------》ArrayList和LinkedList)

    这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 1.面向对象 2.JDK.JRE.JVM区别和联系 3.==和equals 4.final 5.String .Strin ...

  4. 齐博x2向上滚动特效

    要实现图中圈起来的向上滚动特效,大家可以参考下面的代码 <!--滚动开始--> <style type="text/css"> .auto-roll{ he ...

  5. 2.签名&初始化&提交

      Git设置签名 签名的作用是区分不同操作者的身份,用户的签名信息在每一个版本的提交信息中能够看到, 以此确认本次提交是谁做的,git首次安装必须设置用户签名,否则无法提交代码 这里设置的用户签名和 ...

  6. 2022HNCTF--WEB

    @ 目录 [Week1]Interesting_http 分析 payload [Week1]2048 分析 payload [Week1]easy_html 分析 paylaod [Week1]In ...

  7. JIRA操作之 基本说明

    官方说明:https://docs.atlassian.com/software/jira/docs/api/7.6.1/ 项目(Project) Project是一组问题单(Issue)的集合,每个 ...

  8. Uniapp And Taro一些小测评

    前情 最近公司准备新开发一个小程序项目,对于使用哪一款小程序框架有一些犹豫,我有过2年左右的uniapp项目开发经验,Taro在刚刚出来的时候有尝试过,经常莫名报错需要重启,在内心是有些偏向uniap ...

  9. 「浙江理工大学ACM入队200题系列」问题 E: 零基础学C/C++78——求奇数的乘积

    本题是浙江理工大学ACM入队200题第八套中的E题 我们先来看一下这题的题面. 题面 输入 输入数据包含多个测试实例,每个测试实例占一行,每行的第一个数为n,表示本组数据一共有n个,接着是n个整数,你 ...

  10. .Net 7里的函数.Ctor和.CCtor是干啥用的呢?你知道吗

    楔子 有小伙伴被面试官问到这个问题,本篇彻底解析下这个问题. 为了彻底点,注意本篇是最底层的.Net 7 RC CLR运行模型(汇编)为基础进行全局剖析,局部业务分析. 如有疏漏,请斧正. 目的非手段 ...