发布时间:2022-08-18 18:35
在上一篇文章里,已经实现了基于OV5640的摄像头监控,在此基础上,我们加入一些图像处理的内容,即可实现简单的一些图像处理效果,这次做到的就是最基础的人脸识别功能。
因为RGB全彩图像对于图像处理很困难,所以大部分采用的都是将图像信息二值化,也就是我们所理解的黑白图像。所以我们第一个需要的就是将图像信息从RGB转成ycbcr格式。
RGB转换YCBCR格式的公式如下:
Y = 0.299R +0.587G + 0.114B
Cb = 0.568(B-Y) + 128
CR = 0.713(R-Y) + 128
经过上面公式我们就可以将RGB转换成YCBCR格式
得到了YCBCR格式的图像数据之后,我们就可以通过设定阈值的范围来获得我们所需要的图像信息了,处理之后的效果就是人脸部分显示白色,其余部分显示黑色。
比如我们这里要得到的人脸的肤色,根据查询,人脸的阈值如下:
77 < Cb < 127
133 < Cr < 173
由于我们实现的是最基本的图像处理效果,所以此次的介绍没有加入滤波的方法。但可以介绍一下滤波的原因和方法,具体内容后期随缘介绍哈哈。
滤波的原因:
在我们的摄像头采集图像信息的过程中,由于硬件本来存在的问题,会有一些飘动的白点进行调动,这就是我们所说的图像噪点。(小时候的电视机的雪花就是这样滴)
滤波的方法:
就我所知的图像处理方法比较有限且基础,有中值滤波,均值滤波,服饰和膨胀算法等等,还有一些其他比如帧差发来检测快速运动物体,光流法等。
为了更加直观的看到处理的结果,我们用红框来框选住我们所处理之后的图像信息。但是我们不能无缘无故就可以准确的框选我们所要的内容,所以我们需要进行识别有效的区域,即得到有效图像的最小和最大的X,Y的坐标,来进行框选。
具体思路就是:用X,Y分别扫描图像信息,第一个得到的1.和第一个从1反转到0的坐标进行寄存,然后经过运算之后就可以准确的得到这四个值:
X min,X max,Y min,Y max.
当然,没有进行滤波的图像会产生很多的噪点,导致框选的内容有问题,这里只是提供一个思路。可以用开运算进行去除噪点。
将上一模块传来的X min,X max,Y min,Y max值分别赋予红色之后,就可以框选出我们想要框选的内容。
具体代码体现:
if(vga_y== y_min && vga_x>= x_min && vga_x<= x_max)
rgb <= RED;
else if(vga_y== y_max && vga_x>= x_min && vga_x<= x_max)
rgb <= RED;
else if(vga_x== x_min && vga_y>= y_min && vga_y<= y_max)
rgb <= RED;
else if(vga_x== x_max && vga_y>= y_min && vga_y<= y_max)
rgb <= RED
//step1 计算括号内的各乘法项
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rgb_r_m0 <= 16'd0;
rgb_r_m1 <= 16'd0;
rgb_r_m2 <= 16'd0;
rgb_g_m0 <= 16'd0;
rgb_g_m1 <= 16'd0;
rgb_g_m2 <= 16'd0;
rgb_b_m0 <= 16'd0;
rgb_b_m1 <= 16'd0;
rgb_b_m2 <= 16'd0;
end
else begin
rgb_r_m0 <= rgb888_r * 8'd77 ;
rgb_r_m1 <= rgb888_r * 8'd43 ;
rgb_r_m2 <= rgb888_r * 8'd128;
rgb_g_m0 <= rgb888_g * 8'd150;
rgb_g_m1 <= rgb888_g * 8'd85 ;
rgb_g_m2 <= rgb888_g * 8'd107;
rgb_b_m0 <= rgb888_b * 8'd29 ;
rgb_b_m1 <= rgb888_b * 8'd128;
rgb_b_m2 <= rgb888_b * 8'd21 ;
end
end
//step2 括号内各项相加
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
img_y0 <= 16'd0;
img_cb0 <= 16'd0;
img_cr0 <= 16'd0;
end
else begin
img_y0 <= rgb_r_m0 + rgb_g_m0 + rgb_b_m0;
img_cb0 <= rgb_b_m1 - rgb_r_m1 - rgb_g_m1 + 16'd32768;
img_cr0 <= rgb_r_m2 - rgb_g_m2 - rgb_b_m2 + 16'd32768;
end
end
//step3 括号内计算的数据右移8位
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
img_y1 <= 8'd0;
img_cb1 <= 8'd0;
img_cr1 <= 8'd0;
end
else begin
img_y1 <= img_y0 [15:8];
img_cb1 <= img_cb0[15:8];
img_cr1 <= img_cr0[15:8];
end
end
//x_min lag 2clk
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
x_min <= ROW_CNT;
end
else if(flag)
x_min <= ROW_CNT;
else if(per_frame_clken && per_img_Bit == 1 && x_min > cnt_x)
x_min <= cnt_x;
else
x_min <= x_min;
end
//x_max
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
x_max <= 0;
end
else if(flag)
x_max <= 0;
else if(per_frame_clken && per_img_Bit == 1 && x_max < cnt_x)
x_max <= cnt_x;
else
x_max <= x_max;
end
//y_min
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
y_min <= COL_CNT;
end
else if(flag)
y_min <= COL_CNT;
else if(per_frame_clken && per_img_Bit == 1 && y_min > cnt_y)
y_min <= cnt_y;
else
y_min <= y_min;
end
//y_max
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
y_max <= 0;
end
else if(flag)
y_max <= 0;
else if(per_frame_clken && per_img_Bit == 1 && y_max < cnt_y)
y_max <= cnt_y;
else
y_max <= y_max;
end
初学入门,分享学习笔记和心得,如有指教,感激不尽!
由于最近板子做在了课设上,所以暂时没有上板的效果,等课赛开始之后,将即时上传上板的效果图片。