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. java多线程的两种创建方式

    方式一:继承Thread类 1.创建一个继承于Thread类的子类 2.重写Thread类的run()方法---> 将此线程执行的操作声明在run()中 3.创建Thread类的子类的对象 4. ...

  2. 6.MongoDB系列之特殊索引和集合类型

    1. 地理空间索引及全文搜索 与Elasitcsearch一样,MongoDB同样支持地理空间索引及全文搜索,由于选型常用ES而非MongoDB此处略过 2. TTL索引 首先先了解下固定集合,其类似 ...

  3. scrapy操作mysql/批量下载图片

    1.操作mysql items.py meiju.py 3.piplines.py 4.settings.py -------------------------------------------- ...

  4. JUC(11)各种锁的理解(公平锁、可重入锁、自旋锁、死锁)

    文章目录 1.公平锁.非公平锁 2.可重入锁 3.自旋锁 4.死锁 1.公平锁.非公平锁 公平锁:非常公平.不能插队.必须先来后到 非公平锁:非常不公平.可以插队.(默认非公平) 可以修改为公平锁 2 ...

  5. python求列表均值,方差,标准差

    import numpy as np a = [1,2,3,4,5,6] #求均值 a_mean = np.mean(a) #求方差 a_var = np.var(a) #求标准差 a_std = n ...

  6. ES6 学习笔记(九)Set的基本用法

    1 基本用法 set类似于数组,它的成员是唯一的,当有多个相同的值,只会保留一份. 1.1 创建方法 Set本身是一个构造函数,用来生成Set实例,如: const s = new Set() let ...

  7. MLP(SGD or Adam) Perceptron Neural Network Working by Pytorch(including data preprocessing)

    通过MLP多层感知机神经网络训练模型,使之能够根据sonar的六十个特征成功预测物体是金属还是石头.由于是简单的linearr线性仿射层,所以网络模型的匹配度并不高. 这是我的第一篇随笔,就拿这个来练 ...

  8. C#自定义控件开发(1)

    自定义控件可以用组件或者用户控件来开发,如果是基于基础控件,进行一些扩展,那么可以使用组件,其它的情况可以使用用户控件. 首先新建一个类库项目,然后添加一个组件,取名为ButtonExtend,再添加 ...

  9. Nginx如何配置隐藏index.php文件

    server { listen 80; #listen [::]:80 default_server ipv6only=on; server_name jiqing.dexin.com; index ...

  10. 详解Native Memory Tracking之追踪区域分析

    摘要:本篇图文将介绍追踪区域的内存类型以及 NMT 无法追踪的内存. 本文分享自华为云社区<[技术剖析]17. Native Memory Tracking 详解(3)追踪区域分析(二)> ...