1 分离YUV420中YUV分量

本程序中的函数主要是将YUV420P视频数据流的第一帧图像中的Y、U、V三个分量分离开并保存成三个文件。函数的代码如下所示:

/**
* @file 1 yuv_split.cpp
* @author luohen
* @brief split 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 url location of input yuv420p file
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @return int
*/
int yuv420_split(const char *url, int w, int h)
{
//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 *outputY_fp = fopen("video_result/output_420_y.y", "wb+");
FILE *outputU_fp = fopen("video_result/output_420_u.y", "wb+");
FILE *outputV_fp = fopen("video_result/output_420_v.y", "wb+"); unsigned char *pic = new unsigned char[w * h * 3 / 2]; //读数据,每次读取的字节数为sizeof(unsigned char)=1,共读取w*h*3/2次
//reading data
fread(pic, sizeof(unsigned char), w * h * 3 / 2, input_fp);
//writing data
//Y
fwrite(pic, sizeof(unsigned char), w * h, outputY_fp);
//U
fwrite(pic + w * h, sizeof(unsigned char), w * h / 4, outputU_fp);
//V
fwrite(pic + w * h * 5 / 4, sizeof(unsigned char), w * h / 4, outputV_fp); //memory release and files closing
delete[] pic;
fclose(input_fp);
fclose(outputY_fp);
fclose(outputU_fp);
fclose(outputV_fp); return 0;
} /**
* @brief main
*
* @return int
*/
int main()
{
//Setting YUV information
int state = yuv420_split("video/akiyo.yuv", 352, 288);
return 0;
}

调用函数为:

int yuv420_split(const char *url, int w, int h);

从代码可以看出,程序先是读入一段视频数据流。通过fread函数读取wh3/2个unsigned char长度的数据实现第一帧图像的读取,unsigned

char占一个字节(通过sizeof(unsigned char)可以查看到),也就是说fread函数读取wh3/2字节的数据就可以实现一帧图像的读取。

其中这段代码的fread函数是指每次读取1个字节的数据,一共读取wh(y的长度)+(w/2h/2)(u的长度)+

(w/2h/2)(v的长度)=wh*3/2次。

fread(pic, sizeof(unsigned char), w * h * 3 / 2, input_fp);

写成下列形式也是一样的。

fread(pic, w * h * 3 / 2*sizeof(unsigned char), 1, input_fp);

fwrite函数也是一样的用法。先存Y,再存UV。对于Y,U,Y分离后存储的格式可以是yuv格式也可以是单独的y格式。分离后的Y分量(352,288),U分量(176,144),V分量(176,144)。结果如下图所示:


2 YUV420灰度化

本程序中的函数主要是将YUV420P视频数据流的第一帧图像变为灰度图像。函数的代码如下所示:

/**
* @file 2 yuv_gray.cpp
* @author luohen
* @brief gray scale 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 url location of input yuv420p file
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @return int
*/
int yuv420_gray(const char *url, int w, int h)
{
//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 *outputGray_fp = fopen("video_result/output_gray.yuv", "wb+"); unsigned char *pic = new unsigned char[w * h * 3 / 2]; fread(pic, sizeof(unsigned char), w * h * 3 / 2, input_fp);
//Gray
//把pic+w*h开始所有的数据置为128,色度分量取值范围是-128至127,量化后范围为0至255
//uv=128,实现灰度化
memset(pic + w * h, 128, w * h / 2);
fwrite(pic, sizeof(unsigned char), w * h * 3 / 2, outputGray_fp); delete[] pic;
fclose(input_fp);
fclose(outputGray_fp);
return 0;
} /**
* @brief main函数
*
* @return int
*/
int main()
{
int state = yuv420_gray("video/akiyo.yuv", 352, 288);
return 0;
}

调用函数为:

int yuv420_gray(const char *url, int w, int h);

这段函数主要是将U、V分量置为128,从而得到灰度图像。将U、V置为128而不是0,主要原因是U、V本来的取值范围大概是-127到128(可能更大),因为YUV的数据流是无符号的,所以将其量化为0到255。UV的最初取值范围可以通过RGB与YUV的转换公式理解。具体见文章:

https://www.cnblogs.com/armlinux/archive/2012/02/15/2396763.html

最终得到的YUV灰度图像,UV分量都存在只是为128而已。事实上只提取出Y分量效果也是一样的。结果如下图所示:


3 YUV420亮度减半

本程序中的函数主要是将YUV420P视频数据流的第一帧图像亮度减半。函数的代码如下所示:

/**
* @file 3 yuv_halfy.cpp
* @author luohen
* @brief Half of Y value
* @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 url location of input yuv420p file
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @return int
*/
int yuv420_half(const char *url, int w, int h)
{
//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/output_half.yuv", "wb+"); unsigned char *pic = new unsigned char[w * h * 3 / 2]; fread(pic, sizeof(unsigned char), w * h * 3 / 2, input_fp);
//half of Y
for (int j = 0; j < w * h; j++)
{
unsigned char temp = pic[j] / 2;
//printf("%d,\n",temp);
pic[j] = temp;
}
fwrite(pic, 1, w * h * 3 / 2, output_fp); delete[] pic;
fclose(input_fp);
fclose(output_fp);
return 0;
} /**
* @brief main函数
*
* @return int
*/
int main()
{
int state = yuv420_half("video/akiyo.yuv", 352, 288);
return 0;
}

调用函数为:

int yuv420_half(const char *url, int w, int h);

这段函数主要是将Y分量减半,从而得到灰度图像。而其他UV分量不需要调整。实际上YUV图像处理套路就是将YUV三个分量分别看成三张灰度图像,分别进行图像处理。除了YUV分量大小不一,其他与RGB像素处理一样。结果如下图所示:


4 YUV420添加边框

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

/**
* @file 4 yuv_border.cpp
* @author luohen
* @brief add a border to 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 url location of input yuv420p file
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @return int
*/
int yuv420_border(const char *url, int w, int h)
{
//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/output_border.yuv", "wb+"); //border width
int border = 30;
unsigned char *pic = new unsigned char[w * h * 3 / 2]; //reading y
fread(pic, 1, w * h * 3 / 2, input_fp);
//y
for (int j = 0; j < h; j++)
{
for (int k = 0; k < w; k++)
{
if (k < border || k >(w - border) || j < border || j >(h - border))
{
//0最暗,255最亮
pic[j * w + k] = 0;
//pic[j*w+k]=255;
}
}
} fwrite(pic, 1, w * h * 3 / 2, output_fp);
delete[] pic;
fclose(input_fp);
fclose(output_fp);
return 0;
} /**
* @brief main函数
*
* @return int
*/
int main()
{
int state = yuv420_border("video/akiyo.yuv", 352, 288);
return 0;
}

调用函数为:

int yuv420_border(const char *url, int w, int h);

这段函数主要是调整图像边缘的Y分量数值,从而为图像添加边框。其中Y的初始值就是0-255,和灰度图一样,y为0时图像最暗,为255图像最暗。但是这段程序并没有实现严格意义上的添加图像边框,应该使得uv分量相同位置处的值为128(因为copy雷神代码。就懒得自己写了)。

结果如下图所示:

但是想了下,还是不能全copy雷神的代码。uv分量相同位置处的值为128,代码如下:

/**
* @file 4 yuv_border.cpp
* @author luohen
* @brief add a border to 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 url location of input yuv420p file
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @return int
*/
int yuv420_border(const char *url, int w, int h)
{
//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/output_border.yuv", "wb+"); //border width
int border = 30;
unsigned char *pic = new unsigned char[w * h * 3 / 2]; //reading y
fread(pic, 1, w * h * 3 / 2, input_fp);
//y
for (int j = 0; j < h; j++)
{
for (int k = 0; k < w; k++)
{
if (k < border || k >(w - border) || j < border || j >(h - border))
{
//0最暗,255最亮
pic[j * w + k] = 0;
//pic[j*w+k]=255;
}
}
}
//u
for (int j = 0; j < h / 2; j++)
{
for (int k = 0; k < w / 2; k++)
{
if (k < border / 2 || k >(w / 2 - border / 2) || j < border / 2 || j >(h / 2 - border / 2))
{
pic[w*h + j * w / 2 + k] = 128;
//pic[j*w+k]=255;
}
}
}
//v
for (int j = 0; j < h / 2; j++)
{
for (int k = 0; k < w / 2; k++)
{
if (k < border / 2 || k >(w / 2 - border / 2) || j < border / 2 || j >(h / 2 - border / 2))
{
pic[w*h + w / 2 * h / 2 + j * w / 2 + k] = 128;
//pic[j*w+k]=255;
}
}
} fwrite(pic, 1, w * h * 3 / 2, output_fp);
delete[] pic;
fclose(input_fp);
fclose(output_fp);
return 0;
} /**
* @brief main函数
*
* @return int
*/
int main()
{
int state = yuv420_border("video/akiyo.yuv", 352, 288);
return 0;
}

其中对uv处理时border要除以2,因u、v只有y的四分之一大小。

对u,v赋值代码如下,因为yuv420是以数据流依次存储。所以u处理时数据u从pic[wh]开始,而处理v从pic[wh+w/2*h/2]开始。

pic[w*h + j * w / 2 + k] = 128;

pic[w*h + w / 2 * h / 2 + j * w / 2 + k] = 128;

结果如图所示:

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

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

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

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

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

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

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

  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. C#实现登录某web进而获取其token数据

    实习在学C#,记录一下学习过程! 首先是需求描述(基于C#的.net core MVC实现): User: Resource Owner Agent:Brower auth.brightspace.c ...

  2. 谣言检测(RDEA)《Rumor Detection on Social Media with Event Augmentations》

    论文信息 论文标题:Rumor Detection on Social Media with Event Augmentations论文作者:Zhenyu He, Ce Li, Fan Zhou, Y ...

  3. 如何使用 pyqt 读取串口传输的图像

    前言 这学期选修了嵌入式系统的课程,大作业选择的题目是人脸口罩检测.由于课程提供的开发板搭载的芯片是 STM32F103ZET6,跑不动神经网络,所以打算将 OV7725 拍摄到的图像通过串口传输给上 ...

  4. OpenJudge 1.6.7 有趣的跳跃

    07:有趣的跳跃 总时间限制: 1000ms 内存限制: 65536kB 描述 一个长度为n(n>0)的序列中存在"有趣的跳跃"当前仅当相邻元素的差的绝对值经过排序后正好是从 ...

  5. 驱动开发:内核枚举PspCidTable句柄表

    在上一篇文章<驱动开发:内核枚举DpcTimer定时器>中我们通过枚举特征码的方式找到了DPC定时器基址并输出了内核中存在的定时器列表,本章将学习如何通过特征码定位的方式寻找Windows ...

  6. 齐博x1如何取消某个标签的缓存时间

    标签默认会有缓存, 如果你要强制取消缓存时间的话, 可以加上下面的参数 time="-1"如下图所示 标签默认缓存时间是10分钟, 你也可以改成其它时间 比如 time=" ...

  7. NLP之基于Seq2Seq的单词翻译

    Seq2Seq 目录 Seq2Seq 1.理论 1.1 基本概念 1.2 模型结构 1.2.1 Encoder 1.2.2 Decoder 1.3 特殊字符 2.实验 2.1 实验步骤 2.2 算法模 ...

  8. Linux--多线程(二)

    线程的同步和互斥 基本概念 概述:现在操作系统基本都是多任务的操作系统,同时有大量可以调度的实体在运行.在多任务操作系统当中,同时运行的多个任务可能: 都需要访问/使用同一种资源 多个任务之间有依赖关 ...

  9. 基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2

    基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2 Video Capture&Display IP for V4L2 在主机端视频设备内核驱动V4L2 的控制和调度下,Vi ...

  10. Codeforces Round #811 (Div. 3)D. Color with Occurrences

    题目大意:给出一个文章t和n个字符串s1,s2...sn: 问能否用这n个字符串将整个文章覆盖: 思路:贪心(最小区间覆盖) 记录每个字符串能够覆盖的所有位置(起点,终点,编号) 排序后贪心的求出是否 ...