9 yuv420图像截取

本程序中的函数主要是对YUV420P视频数据流的第一帧图像进行截取。类似opencv中的rect函数,函数的代码如下所示:

/**
* @file 9 yuv_clip.cpp
* @author luohen
* @brief yuv image clip
* @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 w width of input yuv420p file
* @param h height of input yuv420p file
* @param sx clipped initial position x of origin y image
* @param sy clipped initial position y of origin y image
* @param sw wdith of clipped image
* @param sh height of clipped image
* @param url location of input yuv420p file
* @return int
*/
int yuv420_clip(int w, int h, int sx, int sy, int sw, int sh, const char *url)
{
//reading yuv file
FILE *input_fp;
//writing yuv file
FILE *output_fp = fopen("video_result/output_clip.yuv", "wb+"); if ((input_fp = fopen(url, "rb")) == NULL)
{
printf("%s open error!\n", url);
return -1;
}
else
{
printf("%s open.\n", url);
} //origin image
unsigned char *pic = new unsigned char[w * h * 3 / 2];
//clipped image
unsigned char *pic_clip = new unsigned char[sw * sh * 3 / 2]; // y length of origin image
int size_y = w * h;
// yu length of origin image
int size_yu = w * h + w * h / 4;
// y length of clipped image
int size_sy = sw * sh;
// yu length of clipped image
int size_syu = sw * sh + sw * sh / 4; fread(pic, sizeof(unsigned char), w * h * 3 / 2, input_fp); //y clip
for (int j = 0; j < sh; j++)
{
for (int k = 0; k < sw; k++)
{
pic_clip[j * sw + k] = pic[(sx + j) * w + (sy + k)];
}
} //sw_uv,sh_uv
int sw_uv = sw / 2;
int sh_uv = sh / 2; //u clip
for (int j = 0; j < sh_uv; j++)
{
for (int k = 0; k < sw_uv; k++)
{
pic_clip[size_sy + j * sw_uv + k] = pic[size_y + (sx / 2 + j) * w / 2 + (sy / 2 + k)];
}
} //v clip
for (int j = 0; j < sh_uv; j++)
{
for (int k = 0; k < sw_uv; k++)
{
pic_clip[size_syu + j * sw_uv + k] = pic[size_yu + (sx / 2 + j) * w / 2 + (sy / 2 + k)];
}
} fwrite(pic_clip, 1, sw * sh * 3 / 2, output_fp); delete[] pic;
delete[] pic_clip;
fclose(input_fp);
fclose(output_fp);
return 0;
} /**
* @brief main
*
* @return int
*/
int main()
{
int state = yuv420_clip(352, 288, 60, 50, 176, 144, "video/akiyo.yuv");
return 0;
}

调用函数为:

int yuv420_clip(int w, int h, int sx, int sy, int sw, int sh, const char *url);

这段代码指的是对于宽高为w,h的yuv图像,相对于y分量来说截取宽为sw,高为sh的部分,截取部分左上角顶点坐标为(sx,sy);对于uv分量来截取宽高分别为sw/2,sh/2,截取部分左上角顶点坐标为(sx/2,sy/2)。然后分别对y,u,v分量截图。

这段程序sx=60,sy=50,sw=176,sh=144。最终的结果如下图:


10 yuv420图像帧差法运动检测

本程序中的函数主要是截取YUV420P视频数据流的第1帧图像和第200图像,通过帧差法对两幅图像的y分量进行对比实现运动检测。类似opencv中的absdiff函数,函数的代码如下所示:

/**
* @file 10 yuv_framedifference.cpp
* @author luohen
* @brief Frame difference method of y
* @date 2018-12-10
*
*/ #include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <string.h>
#include <iostream> using namespace std; /**
* @brief
*
* @param pFrame1 the first frame
* @param pFrame2 the second frame
* @param pResult the result image
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @param yThreshold threshold value
*/
void yuv420_Framedifference(unsigned char *pFrame1, unsigned char *pFrame2, unsigned char *pResult, int w, int h, int yThreshold)
{
//the first frame
unsigned char *Y1 = new unsigned char[w * h];
//the second frame
unsigned char *Y2 = new unsigned char[w * h]; //copy y
memcpy(Y1, pFrame1, w * h);
memcpy(Y2, pFrame2, w * h);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int i = y * w + x;
//diff
int temp = abs((int)Y1[i] - (int)Y2[i]);
if (temp > yThreshold)
{
pResult[i] = 255;
}
else
{
pResult[i] = 0;
}
}
}
delete[] Y1;
delete[] Y2;
} /**
* @brief main function
*
* @return int
*/
int main()
{
//the yuv image size
int w = 352, h = 288; //reading yuv file
FILE *input_fp;
//writing yuv file
//the first yuv image
FILE *fp1 = fopen("video_result/akiyo1.yuv", "wb+");
//the second yuv image
FILE *fp2 = fopen("video_result/akiyo2.yuv", "wb+");
//the binary image of frame difference
FILE *fp3 = fopen("video_result/output_diff.y", "wb+"); const char * url = "video/akiyo.yuv";
if ((input_fp = fopen(url, "rb")) == NULL)
{
printf("%s open error!\n", url);
return 0;
}
else
{
printf("%s open.\n", url);
} //result
unsigned char *pResult = new unsigned char[w * h];
//the first image
unsigned char *pFrame1 = new unsigned char[w * h * 3 / 2];
//the second image
unsigned char *pFrame2 = new unsigned char[w * h * 3 / 2]; //used for read frames
unsigned char originalFrame[352 * 288 * 3 / 2];
//reading image for a loop
for (int i = 0; i < 200; i++)
{
//fread function automatically moves the pointer
//take the first frame
if (i == 0)
{
fread(pFrame1, w * h * 3 / 2, 1, input_fp);
}
//take the second frame
if (i == 199)
{
fread(pFrame2, w * h * 3 / 2, 1, input_fp);
}
//Skip intermediate frame
else
{
fread(originalFrame, w * h * 3 / 2, 1, input_fp);
}
} /* another way to read images
fread(pFrame1, w * h * 3 / 2, 1, input_fp);
int p = 199 * w*h * 3 / 2;
//move the pointer
fseek(input_fp, p, SEEK_SET);
fread(pFrame2, w * h * 3 / 2, 1, input_fp);
*/ //the threshold is 30
yuv420_Framedifference(pFrame1, pFrame2, pResult, w, h, 30); fwrite(pFrame1, 1, w * h * 3 / 2, fp1);
fwrite(pFrame2, 1, w * h * 3 / 2, fp2);
fwrite(pResult, 1, w * h, fp3); delete[] pResult;
delete[] pFrame1;
delete[] pFrame2; fclose(input_fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
}

调用函数为:

 void yuv420_Framedifference(unsigned char *pFrame1, unsigned char *pFrame2, unsigned char *pResult, int w, int h, int yThreshold);

这段代码中忽略了uv分量的影响。计算第一帧y分量与第二帧y分量的差。然后通过类似opencv中的threshold函数,对于帧差得到的图像中像素值大于给定阈值yThreshold的点,其像素值置为255,小于阈值的点像素值置为0。也就是说像素值为255的区域就是运动区域,为0的区域就是背景区域。这是最基本的运动检测算法,当然这段代码改进的地方有:通过uv分量的差综合得到背景区域;或者引入三帧差法。

对于主函数中,由于akiyo.yuv是一个视频流,通过fread函数每读完一张图像,fread中的文件指针会直接移动到当前文件读取位置,这样就可以用fread函数读完视频中所有的图像。

当然这种方式比较傻,可以直接通过下列代码,先读取第一帧图像,然后通过fseek函数,将fread的文件指针,从SEEK_SET(文件开始处)移动到第199帧图像的结尾处,再用fread函数读取第200帧图像。

fseek(input_fp, p, SEEK_SET);

fread(pFrame1, w * h * 3 / 2, 1, input_fp);

int p = 199 * w*h * 3 / 2;

fseek(input_fp, p, SEEK_SET);

fread(pFrame2, w * h * 3 / 2, 1, input_fp);

所提取的第1帧图像、第200帧图像以及帧差结果的二值图如图所示:

11 二值图像膨胀和腐蚀

本程序中的函数主要是对帧差法提取的运动区域二值图像进行膨胀和腐蚀操作,函数的代码如下所示:

/**
* @file 11 yuv_dilate_erode.cpp
* @author luohen
* @brief dilate and erode of yuv image
* @date 2018-12-10
*
*/ #include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <string.h>
#include <iostream> using namespace std; /**
* @brief erode
*
* @param pFrame the input binary image
* @param pdilateResult the output binary image
* @param kernel kernel of erode
* @param w width of image
* @param h height of image
*/
void yuv420_erode(unsigned char *pFrame, unsigned char *pErodeResult, int kernel, int w, int h)
{
//copy data
unsigned char *srcImg = new unsigned char[w * h];
memcpy((char *)srcImg, (char *)pFrame, w * h); //kernel除中心之外像素点个数
int nErodeThreshold = kernel * kernel - 1;
//对于中点要erode像素区域步长
int erodeDist = (kernel - 1) / 2;
//ignore edge point
for (int i = erodeDist; i < h - erodeDist; i++)
{
for (int j = erodeDist; j < w - erodeDist; j++)
{
// 如果值不为0才进行处理
if (srcImg[i * w + j] != 0)
{
int iPointCount = 0;
// 根据此点的邻域判断此点是否需要删除
for (int r = -erodeDist; r <= erodeDist; r++)
{
for (int c = -erodeDist; c <= erodeDist; c++)
{
//统计不为0的个数
if (srcImg[(i + r) * w + j + c] != 0)
{
iPointCount++;
}
}
}
// 如果邻域中不为0的个数小于阈值,则中心点像素值设置为0
if (iPointCount < nErodeThreshold)
{
pErodeResult[i * w + j] = 0;
}
else
{
pErodeResult[i * w + j] = 255;
}
}
else
{
pErodeResult[i * w + j] = 0;
}
}
}
delete[] srcImg;
return;
} /**
* @brief dilate
*
* @param pFrame the input binary image
* @param pdilateResult the output binary image
* @param kernel kernel of dilate
* @param w width of image
* @param h height of image
*/
void yuv420_dilate(unsigned char *pFrame, unsigned char *pdilateResult, int kernel, int w, int h)
{
//copy data
unsigned char *srcImg = new unsigned char[w * h];
memcpy((char *)srcImg, (char *)pFrame, w * h); //对于中点要erode像素区域步长
int erodeDist = (kernel - 1) / 2;
//ignore edge point
for (int i = erodeDist; i < h - erodeDist; i++)
{
for (int j = erodeDist; j < w - erodeDist; j++)
{
//对所有点进行判断
int iPointCount = 0;
// 根据此点的邻域判断此点是否需要删除
for (int r = -erodeDist; r <= erodeDist; r++)
{
for (int c = -erodeDist; c <= erodeDist; c++)
{
//统计不为0的个数
if (srcImg[(i + r) * w + j + c] != 0)
{
iPointCount++;
}
}
}
// 如果邻域中各像素点值都为0,则中心点像素值设置为0
if (iPointCount == 0)
{
pdilateResult[i * w + j] = 0;
}
else
{
pdilateResult[i * w + j] = 255;
}
}
}
delete[] srcImg;
return;
} /**
* @brief
*
* @param pFrame1 the first frame
* @param pFrame2 the second frame
* @param pResult the result image
* @param w width of input yuv420p file
* @param h height of input yuv420p file
* @param yThreshold threshold value
*/
void yuv420_Framedifference(unsigned char *pFrame1, unsigned char *pFrame2, unsigned char *pResult, int w, int h, int yThreshold)
{
//the first frame
unsigned char *Y1 = new unsigned char[w * h];
//the second frame
unsigned char *Y2 = new unsigned char[w * h];
;
//copy y
memcpy(Y1, pFrame1, w * h);
memcpy(Y2, pFrame2, w * h);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int i = y * w + x;
//diff
int temp = abs((int)Y1[i] - (int)Y2[i]);
if (temp > yThreshold)
{
pResult[i] = 255;
}
else
{
pResult[i] = 0;
}
}
}
delete[] Y1;
delete[] Y2;
} /**
* @brief main function
*
* @return int
*/
int main()
{
//the yuv image size
int w = 352, h = 288; //reading yuv file
FILE *input_fp;
//writing yuv file
//the first yuv image
FILE *fp1 = fopen("video_result/akiyo1.yuv", "wb+");
//the second yuv image
FILE *fp2 = fopen("video_result/akiyo2.yuv", "wb+");
//the binary image of frame difference
FILE *fp3 = fopen("video_result/akiyo_erode.y", "wb+"); const char *url = "video/akiyo.yuv";
if ((input_fp = fopen(url, "rb")) == NULL)
{
printf("%s open error!\n", url);
return 0;
}
else
{
printf("%s open.\n", url);
} //result
unsigned char *pResult = new unsigned char[w * h];
//the first image
unsigned char *pFrame1 = new unsigned char[w * h * 3 / 2];
//the second image
unsigned char *pFrame2 = new unsigned char[w * h * 3 / 2]; //used for read frames
unsigned char originalFrame[352 * 288 * 3 / 2];
//reading image for a loop
for (int i = 0; i < 200; i++)
{
//fread function automatically moves the pointer
//take the first frame
if (i == 0)
{
fread(pFrame1, w * h * 3 / 2, 1, input_fp);
}
//take the second frame
if (i == 199)
{
fread(pFrame2, w * h * 3 / 2, 1, input_fp);
}
//Skip intermediate frame
else
{
fread(originalFrame, w * h * 3 / 2, 1, input_fp);
}
} /* another way to read images
fread(pFrame1, w * h * 3 / 2, 1, input_fp);
int p = 199 * w*h * 3 / 2;
//move the pointer
fseek(input_fp, p, SEEK_SET);
fread(pFrame2, w * h * 3 / 2, 1, input_fp);
*/ //the threshold is 30
yuv420_Framedifference(pFrame1, pFrame2, pResult, w, h, 30); //kernel size is 3 X 3.
yuv420_erode(pResult, pResult, 3, w, h);
//yuv420_dilate(pResult, pResult, 3, w, h); fwrite(pFrame1, 1, w * h * 3 / 2, fp1);
fwrite(pFrame2, 1, w * h * 3 / 2, fp2);
fwrite(pResult, 1, w * h, fp3); delete[] pResult;
delete[] pFrame1;
delete[] pFrame2; fclose(input_fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
}

函数调用代码为:

void yuv420_dilate(unsigned char *pFrame, unsigned char *pdilateResult, int kernel, int w, int h);

void yuv420_erode(unsigned char *pFrame, unsigned char *pErodeResult, int kernel, int w, int h);

腐蚀膨胀的原理和作用见文章;

https://blog.csdn.net/qq_25847123/article/details/73744575

简单。这段代码是opencv中dilate和erode函数中的简化版。不同之处是,这段代码所用处理核只能是矩形的。此外对于边缘点,opencv中会用类似深度学习卷积神经网络中的padding操作,在周围填充点;这段代码就忽略边缘的点,直接处理中间的像素点。

代码很简单,通常对yuv图像处理就是读图,分离yuv分量,然后分别对像素点进行处理。

膨胀腐蚀的结果如图所示:

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

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

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

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

    1 分离YUV420中YUV分量 本程序中的函数主要是将YUV420P视频数据流的第一帧图像中的Y.U.V三个分量分离开并保存成三个文件.函数的代码如下所示: /** * @file 1 yuv_sp ...

  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. 学习ASP.NET Core Blazor编程系列六——初始化数据

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  2. 换工作?试试远程工作「GitHub 热点速览 v.22.40」

    近日,潜在某个技术交流群的我发现即将毕业的小伙伴在焦虑实习.校招,刚好本周 GitHub 热榜有个远程工作项目.不妨大家换个思路,"走"出去也许有更多的机会.当然,除了全球的远程工 ...

  3. oneplus8手机蓝牙连接tws耳机无法双击退出语音助手

    通过蓝牙协议栈我们知道,蓝牙耳机可以通过发送AT指令唤醒或者退出语音助手 唤醒语音助手: AT+BVRA=1 退出语音助手: AT+BVRA=0 但是实际操作中发现双击可以唤醒但再次双击却无法退出语音 ...

  4. 华为路由器vrrp(虚拟路由器冗余协议)基本配置命令

    vrrp(虚拟路由器冗余协议)基本配置 int g0/0/0 vrrp vrid 1 virtual-ip 172.16.1.254 创建VRRP备份组,备份组号为1,配置虚拟IP为172.16.1. ...

  5. 1.2.2 musl pwn

    1.2.2 musl pwn 几个结构 __malloc_context(与glibc中的main_arena类似) struct malloc_context { uint64_t secret; ...

  6. 驱动开发:内核枚举ShadowSSDT基址

    在笔者上一篇文章<驱动开发:Win10枚举完整SSDT地址表>实现了针对SSDT表的枚举功能,本章继续实现对SSSDT表的枚举,ShadowSSDT中文名影子系统服务描述表,SSSDT其主 ...

  7. 知识图谱顶刊综述 - (2021年4月) A Survey on Knowledge Graphs: Representation, Acquisition, and Applications

    知识图谱综述(2021.4) 论文地址:A Survey on Knowledge Graphs: Representation, Acquisition, and Applications 目录 知 ...

  8. Redis 常见问题-缓存穿透

    问题描述: * 针对 DB 中不存在的数据源,每次请求缓存和数据库都不存在 造成后果: * 应用服务器压力变大 * Redis 命中率大幅度降低 * `数据库压力巨增甚至 down 掉`* 该现象对于 ...

  9. 以开发之名 | bilibili会员购让IP在眼前动起来

    随着ACG文化(二次元文化)影响力的不断提升,哔哩哔哩平台上衍生品消费群体不断扩大,手办行业迅速崛起.2017年,B站推出ACG衍生品消费品牌bilibili会员购,涵盖二次元手办销售等多项业务,拓展 ...

  10. 解决 net core 3.x 跨域问题

    跨域:指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制. 以下几种情况是造成跨域的原因: 域名相同,端口不同 域名相同,协议不同(即,一个 ...