5 yuv420格式的灰阶测试图

本程序中的函数主要是为YUV420P视频数据流的第一帧图像添加边框。函数的代码如下所示:

/**
* @file 5 yuv_graybar.cpp
* @author luohen
* @brief gray scale bar of yuv
* @date 2018-12-07
*
*/ #include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream> using namespace std; /**
* @brief
*
* @param width width of input yuv420p file
* @param height height of input yuv420p file
* @param ymin minimum value of y
* @param ymax maximum value of y
* @param barnum Number of bars
* @param url location of input yuv420p file
* @return int
*/
int yuv420_graybar(int width, int height, int ymin, int ymax, int barnum, const char *url)
{
//每个灰度条的宽度
int barwidth;
//每个灰度阶次范围
float lum_inc;
//计算Y值
unsigned char lum_temp;
//uv分量宽高
int uv_width, uv_height;
//reading yuv image
FILE *input_fp;
if ((input_fp = fopen(url, "rb")) == NULL)
{
printf("%s open error!\n", url);
return -1;
}
else
{
printf("%s open.\n", url);
}
//writing yuv image
FILE *output_fp = fopen("video_result/gray_test.yuv", "wb+"); int t = 0, i = 0, j = 0; //每个灰度条的宽度
barwidth = width / barnum;
//每个灰度阶次范围
lum_inc = ((float)(ymax - ymin)) / ((float)(barnum - 1));
//uv分量宽高
uv_width = width / 2;
uv_height = height / 2; unsigned char *data_y = new unsigned char[width * height];
unsigned char *data_u = new unsigned char[uv_width * uv_height];
unsigned char *data_v = new unsigned char[uv_width * uv_height]; //Output Info
//输出信息
printf("Y, U, V value from picture's left to right:\n");
for (t = 0; t < (width / barwidth); t++)
{
//计算Y值
lum_temp = ymin + (char)(t * lum_inc);
printf("%3d, 128, 128\n", lum_temp);
}
//保存数据
for (j = 0; j < height; j++)
{
for (i = 0; i < width; i++)
{
t = i / barwidth;
lum_temp = ymin + (char)(t * lum_inc);
data_y[j * width + i] = lum_temp;
}
}
for (j = 0; j < uv_height; j++)
{
for (i = 0; i < uv_width; i++)
{
data_u[j * uv_width + i] = 128;
}
}
for (j = 0; j < uv_height; j++)
{
for (i = 0; i < uv_width; i++)
{
data_v[j * uv_width + i] = 128;
}
} fwrite(data_y, width * height, sizeof(unsigned char), output_fp);
fwrite(data_u, uv_width * uv_height, sizeof(unsigned char), output_fp);
fwrite(data_v, uv_width * uv_height, sizeof(unsigned char), output_fp);
fclose(input_fp);
fclose(output_fp); delete[] data_y;
delete[] data_u;
delete[] data_v;
return 0;
} /**
* @brief main
*
* @return int
*/
int main()
{
int state = yuv420_graybar(640, 360, 0, 255, 10, "video/graybar.yuv");
return 0;
}

调用函数为:

int yuv420_graybar(int width, int height, int ymin, int ymax, int barnum, const char *url);

实际上这部分代码和前面代码差不多,先取得YUV数据流,类似一个一维数组,读第一帧图像,然后依次读到y,u,v三个分量起始位置,再对y,u,v的像素值分别进行处理。

结果如图所示:


6 两张yuv420p图像的峰值信噪比(psnr)计算

本程序中的函数主要是比较两张yuv420p图像的峰值信噪。函数的代码如下所示:

/**
* @file 6 yuv420_psnr.cpp
* @author luohen
* @brief Compute the PSNR values of two yuv files
* @date 2018-12-08
*
*/ #include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream> using namespace std; /**
* @brief
*
* @param url1 location of input yuv420p file1
* @param url2 location of input yuv420p file2
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @return int
*/
int yuv420_psnr(const char *url1, const char *url2, int w, int h)
{
//reading yuv iamges
FILE *fp1 = fopen(url1, "rb+");
FILE *fp2 = fopen(url2, "rb+"); unsigned char *pic1 = new unsigned char[w * h];
unsigned char *pic2 = new unsigned char[w * h]; fread(pic1, 1, w * h, fp1);
fread(pic2, 1, w * h, fp2); double mse_sum = 0, mse = 0, psnr = 0;
//computing mse
for (int j = 0; j < w * h; j++)
{
mse_sum += pow((double)(pic1[j] - pic2[j]), 2);
}
mse = mse_sum / (w * h);
//computing psnr
psnr = 10 * log10(255.0 * 255.0 / mse);
printf("%5.3f\n", psnr); delete[] pic1;
delete[] pic2;
fclose(fp1);
fclose(fp2);
return 0;
} /**
* @brief main
*
* @return int
*/
int main()
{
int state = yuv420_psnr("video/akiyo.yuv", "video/distort_akiyo.yuv", 352, 288);
return 0;
}

调用函数为:

int yuv420_psnr(const char *url1, const char *url2, int w, int h);

这段代码主要是计算两张图像的接近程度,psnr值具体介绍可以见文章:

https://www.cnblogs.com/ranjiewen/p/6390846.html

本文所用的两张图像一张是akiyo视频流首帧图像,另外一张是前面为akiyo加上边框的图像。两张图像的psnr值为13.497。一般psnr值越大两张图像越接近。


7 yuv420图像顺时针旋转90度

本程序中的函数主要是将YUV420P视频数据流的第一帧图像顺时针旋转90度。函数的代码如下所示:

/**
* @file 7 yuv_Rotation90.cpp
* @author luohen
* @brief 90 degree rotation of yuv420 images
* @date 2018-12-08
*
*/ #include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream> using namespace std; /**
* @brief Pre-defined image size
*
*/
#define image_h 288
#define image_w 352 /**
* @brief
*
* @param url location of input yuv420p file
* @return int
*/
int yuv420_Rotation90(const char *url)
{
//reading yuv files
FILE *input_fp;
//writingyuv files
FILE *output_fp = fopen("video_result/output_rotation.yuv", "wb+"); //reading yuv datas
if ((input_fp = fopen(url, "rb")) == NULL)
{
printf("%s open error!\n", url);
return -1;
}
else
{
printf("%s open.\n", url);
} //Input image array definition
unsigned char input_Y[image_h][image_w];
unsigned char input_U[image_h / 2][image_w / 2];
unsigned char input_V[image_h / 2][image_w / 2]; //Output image array definition
unsigned char output_Y[image_w][image_h];
unsigned char output_U[image_w / 2][image_h / 2];
unsigned char output_V[image_w / 2][image_h / 2]; int w = image_w;
int h = image_h; fread(input_Y, sizeof(unsigned char), w * h, input_fp);
fread(input_U, sizeof(unsigned char), w / 2 * h / 2, input_fp);
fread(input_V, sizeof(unsigned char), w / 2 * h / 2, input_fp); //Y 90 degree rotation
for (int x = 0; x < h; x++)
{
for (int y = 0; y < w; y++)
{
//旋转之后,输出的x值等于输入的y坐标值
//y值等于输入列高-输入x坐标值-1
output_Y[y][h - x - 1] = input_Y[x][y];
}
} //u 90 degree rotation
for (int x = 0; x < h / 2; x++)
{
for (int y = 0; y < w / 2; y++)
{
//旋转之后,输出的x值等于输入的y坐标值
//y值等于输入列高-输入x坐标值-1
output_U[y][h / 2 - x - 1] = input_U[x][y];
}
} //v 90 degree rotation
for (int x = 0; x < h / 2; x++)
{
for (int y = 0; y < w / 2; y++)
{
//旋转之后,输出的x值等于输入的y坐标值
//y值等于输入列高-输入x坐标值-1
output_V[y][h / 2 - x - 1] = input_V[x][y];
}
} fwrite(output_Y, sizeof(unsigned char), w * h, output_fp);
fwrite(output_U, sizeof(unsigned char), w / 2 * h / 2, output_fp);
fwrite(output_V, sizeof(unsigned char), w / 2 * h / 2, output_fp); fclose(input_fp);
fclose(output_fp); return 0;
} /**
* @brief main
*
* @return int
*/
int main()
{
int state = yuv420_Rotation90("video/akiyo.yuv");
return 0;
}

调用函数为:

int yuv420_Rotation90(const char *url);

这段代码主要是分别提取yuv分量,然后将y,u,v分量分别旋转90度。但是提取yuv分量和以前的代码有所不同。

首先是建立yuv三个分量输入的静态二维数组,相比使用动态数组,这种方式处理数据简单很多,但是需要实现确定输入图像的大小。

unsigned char input_Y[image_h][image_w];

unsigned char input_U[image_h / 2][image_w / 2];

unsigned char input_V[image_h / 2][image_w / 2];

然后建立旋转后的输出数组,输出数组定义是,由于是旋转90度,长宽进行了对调。

unsigned char output_Y[image_w][image_h];

unsigned char output_U[image_w / 2][image_h / 2];

unsigned char output_V[image_w / 2][image_h / 2];

其他旋转操作,就是图像赋值过程。旋转后akiyo图像尺寸变为(288,352)

结果如图所示:


8 yuv420图像大小重置

本程序中的函数主要是对YUV420P视频数据流的第一帧图像进行缩放或者放大。类似opencv中的resize函数,函数的代码如下所示:

/**
* @file 8 yuv_resize.cpp
* @author luohen
* @brief adjusting yuv image size
* @date 2018-12-08
*
*/ #include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <string.h>
#include <iostream> using namespace std; #define HEIGHT 288
#define WIDTH 352 /**
* @brief
*
* @param url location of input yuv420p file
* @param out_width output image width
* @param out_height output image height
* @return int
*/
int yuv420_resize(const char *url, int out_width, int out_height)
{
//input array
unsigned char yin[HEIGHT][WIDTH];
unsigned char uin[HEIGHT / 2][WIDTH / 2];
unsigned char vin[HEIGHT / 2][WIDTH / 2];
//output array
unsigned char *yout = new unsigned char[out_width * out_height];
unsigned char *uout = new unsigned char[out_width / 2 * out_height / 2];
unsigned char *vout = new unsigned char[out_width / 2 * out_height / 2];
///reading yuv file
FILE *input_fp;
//writing yuv file
FILE *output_fp = fopen("video_result/output_resize.yuv", "wb+"); if ((input_fp = fopen(url, "rb")) == NULL)
{
printf("%s open error!\n", url);
return -1;
}
else
{
printf("%s open.\n", url);
} fread(yin, sizeof(unsigned char), HEIGHT * WIDTH, input_fp);
fread(uin, sizeof(unsigned char), HEIGHT * WIDTH / 4, input_fp);
fread(vin, sizeof(unsigned char), HEIGHT * WIDTH / 4, input_fp); //Y
for (int i = 0; i < out_height; i++)
{
for (int j = 0; j < out_width; j++)
{
int i_in = round(i * HEIGHT / out_height);
int j_in = round(j * WIDTH / out_width);
yout[i * out_width + j] = yin[i_in][j_in];
}
} //U
for (int i = 0; i < out_height / 2; i++)
{
for (int j = 0; j < out_width / 2; j++)
{
int i_in = round(i * (HEIGHT / 2) / (out_height / 2));
int j_in = round(j * (WIDTH / 2) / (out_width / 2));
uout[i * out_width / 2 + j] = uin[i_in][j_in];
}
} //V
for (int i = 0; i < out_height / 2; i++)
{
for (int j = 0; j < out_width / 2; j++)
{
int i_in = round(i * (HEIGHT / 2) / (out_height / 2));
int j_in = round(j * (WIDTH / 2) / (out_width / 2));
vout[i * out_width / 2 + j] = vin[i_in][j_in];
}
} fwrite(yout, sizeof(unsigned char), out_width * out_height, output_fp);
fwrite(uout, sizeof(unsigned char), out_width * out_height / 4, output_fp);
fwrite(vout, sizeof(unsigned char), out_width * out_height / 4, output_fp); delete[] yout;
delete[] uout;
delete[] vout;
fclose(input_fp);
fclose(output_fp); return 0;
} /**
* @brief main
*
* @return int
*/
int main()
{
int state = yuv420_resize("video/akiyo.yuv", 288, 352);
return 0;
}

调用函数为:

int yuv420_resize(const char *url, int out_width, int out_height);

这段代码也是通过事先设定yuv输入输出的静态二维数组来进行处理的。其中out_width, out_height

是输出图像的宽高,这段代码中输出图像的宽高可以设定为任意值。所用图像resize方法是最简单的最邻近插值法。

插值方法见文章:

https://blog.csdn.net/caomin1hao/article/details/81092134

当设置调整后的图像宽高为288,352时,结果如下:

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

  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图像处理入门5

    12 yuv420转换为rgb(opencv mat) yuv格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式,而且自己造轮子工作量太大.因此通常都会将yuv转换为rgb, ...

  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. Java注解(4):一个真实的Elasticsearch案例

    昨天把拼了一半的注解+Elasticsearch积木放下了,因为东西太多了拼不好,还容易乱.休息了一晚上接着来. 接着昨天,创建elasticsearch文档注解(相当于数据表的注解): /** * ...

  2. 使用@Param标识参数

    可以通过@Param注解标识mapper接口中的方法参数 此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值: 以 param1,param2...为键,以参数为 ...

  3. C#中的装箱和拆箱

    什么是装箱和拆箱 装箱(boxing)和拆箱(unboxing)是C#类型系统的核心概念.是不同于C与C++的新概念!,通过装箱和拆箱操作,能够在值类型和引用类型中架起一做桥梁. 换言之,可以轻松的实 ...

  4. js 获取开始时间和结束时间相隔小时及分钟(时间戳操作)

    js 获取开始时间和结束时间相隔小时及分钟(时间戳操作) 场景描述:获取开始时间和结束时间相隔小时及分钟 实例: TimeOnConfirm(curDate) { if(this.pickernum ...

  5. 物理服务器做系统盘centos

    linux系统跟windows系统都是操作系统的一种,安装的方法也较多,一样可以通过制作u盘启动盘给linux系统安装.那么具体是如何安装linux?下面就给大家演示下u盘启动盘安装linux系统教程 ...

  6. MybatisPlus Lambda表达式 聚合查询 分组查询 COUNT SUM AVG MIN MAX GroupBy

    一.序言 众所周知,MybatisPlus在处理单表DAO操作时非常的方便.在处理多表连接连接查询也有优雅的解决方案.今天分享MybatisPlus基于Lambda表达式优雅实现聚合分组查询. 由于视 ...

  7. 第2-3-3章 文件处理策略-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 5.2 文件处理策略 5.2.1 FileStrategy 5.2.2 AbstractFileStrategy 5.2.3 LocalServiceImpl 5.2.4 FastDfsServ ...

  8. 超精准!AI 结合邮件内容与附件的意图理解与分类!⛵

    作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 TensorFlow 实战系列:https://www.showmeai ...

  9. 1759D(数位变0)

    题目链接 题目大意: 给你两个整数n, m.你需要求一个数,它满足如下条件: 是n的整数倍,且倍数小于m. 你应该使其末尾的0尽可能的多(如100后面有2个零,1020后面有一个零,我们应该输出100 ...

  10. ubuntu 下安装串口终端

    查看串口设备 # Ubuntu 22.04自动卸载CH341串口 sudo apt remove brltty ls -l /dev/ttyUSB0 # 查看串口设备添加信息 sudo dmesg | ...