1、框图
①:整体框图
基于图像实时采集系统实现图像处理
②:图像处理模块框图
2、灰度转换模块
算法:采用精度为7的心理学公式:Gray = R0.299 + G0.587 + B0.114, Gray = R38 + G75 + B15 >> 7
/**************************************功能介绍***********************************
Copyright:
Date :
Author :厉长川
Version :2022.10.12 v1
Description:灰度转换模块
心理学公式:Gray = R*0.299 + G*0.587 + B*0.114, Gray = R*38 + G*75 + B*15 >> 7
*********************************************************************************/
module rgb2gray(
input clk ,//pclk
input rst_n ,//复位信号
input rgb_valid ,//rgb数据有效标志
input [15:0] rgb_din ,//rgb数据输入
output [7:0] gray_dout ,//灰度转换输出
output gray_valid //灰度转换数据有效标志
);
//中间信号定义
wire [7:0] r ;//rgb888
wire [7:0] g ;//rgb888
wire [7:0] b ;//rgb888
reg [2:0] valid_r ;//rgb数据有效标志打拍
reg [14:0] r_u ;//灰度转换运算寄存
reg [14:0] g_u ;//灰度转换运算寄存
reg [14:0] b_u ;//灰度转换运算寄存
reg [14:0] u_out ;//运算和寄存
//RGB565转RGB888:采用量化补偿的方式
assign r = {rgb_din[15:11], rgb_din[13:11]};
assign g = {rgb_din[10:5], rgb_din[6:5]};
assign b = {rgb_din[4:0], rgb_din[2:0]};
//valid_r:rgb数据有效标志打拍
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
valid_r <= 2'b0;
end
else begin
valid_r <= {valid_r[1:0], rgb_valid};
end
end
//7位精度的灰度转换运算
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
r_u <= 15'b0;
g_u <= 15'b0;
b_u <= 15'b0;
end
else if(valid_r[0])begin
r_u <= r*7'd38;
g_u <= g*7'd75;
b_u <= b*7'd15;
end
end
//u_out:运算和
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
u_out <= 15'b0;
end
else if(valid_r[1])begin
u_out <= r_u + g_u + b_u;
end
end
//gray_dout:灰度转换结果
assign gray_dout = u_out[7 +:8];
//gray_valid:灰度转换完成标志
assign gray_valid = valid_r[2];
endmodule
3、高斯滤波模块
/**************************************功能介绍***********************************
Copyright:
Date :
Author :厉长川
Version :2022.10.13 v1
Description:高斯滤波模块
1 2 1
w = 1/16 * 2 4 2
1 2 1
*********************************************************************************/
module gus_filter(
input clk ,
input rst_n ,
input [7:0] gray_din ,
input gray_valid,
output reg [7:0] gus_dout ,
output gus_valid
);
//中间信号定义
wire [7:0] taps0 ;//shift输出数据
wire [7:0] taps1 ;//shift输出数据
wire [7:0] taps2 ;//shift输出数据
reg [7:0] taps0_1 ;//第一拍数据
reg [7:0] taps1_1 ;//第一拍数据
reg [7:0] taps2_1 ;//第一拍数据
reg [7:0] taps0_2 ;//第二拍数据
reg [7:0] taps1_2 ;//第二拍数据
reg [7:0] taps2_2 ;//第二拍数据
reg [10:0] sum_1 ;//第一行加权和
reg [11:0] sum_2 ;//第二行加权和
reg [10:0] sum_3 ;//第三行加权和
reg [3:0] valid_r ;//输入数据有效标志打四拍
//valid_r:输入数据有效标志打四拍
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
valid_r <= 4'b0;
end
else begin
valid_r <= {valid_r[2:0], gray_valid};
end
end
//shift输出数据打拍
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
taps0_1 <= 8'b0;
taps1_1 <= 8'b0;
taps2_1 <= 8'b0;
taps0_2 <= 8'b0;
taps1_2 <= 8'b0;
taps2_2 <= 8'b0;
end
else begin
taps0_1 <= taps0;
taps1_1 <= taps1;
taps2_1 <= taps2;
taps0_2 <= taps0_1;
taps1_2 <= taps1_1;
taps2_2 <= taps2_1;
end
end
//三行数据加权和计算
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sum_1 <= 11'b0;
sum_2 <= 12'b0;
sum_3 <= 11'b0;
end
else if(valid_r[1])begin
sum_1 <= taps0 + {taps0_1,1'b1} + taps0_2;
sum_2 <= {taps1,1'b1} + {taps1_1,2'b11} + {taps1_2,1'b1};
sum_3 <= taps2 + {taps2_1,1'b1} + taps2_2;
end
end
//最后结果输出
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
gus_dout <= 8'b0;
end
else if(valid_r[2])begin
gus_dout <= (sum_1 + sum_2 + sum_3) >> 3'd4;
end
end
//高斯滤波数据有效标志
assign gus_valid = valid_r[3];
shift_gus shift_gus_inst (
.clken (gray_valid),
.clock (clk ),
.shiftin (gray_din ),
.shiftout ( ),
.taps0x (taps0 ),
.taps1x (taps1 ),
.taps2x (taps2 )
);
endmodule
4、二值化模块
/**************************************功能介绍***********************************
Copyright:
Date :
Author :厉长川
Version :2022.10.14 v2 简化算法
2022.10.13 v1
Description:二值化模块
*********************************************************************************/
`include "param.v"
module bin(
input clk ,//pclk
input rst_n ,//复位信号
input [7:0] gus_din ,//高斯滤波输入
input gus_valid ,//高斯滤波输入有效标志
output bin_dout ,//二值化输出
output bin_valid //二值化输出有效标志
);
//bin_dout:二值化输出
assign bin_dout = (gus_din > `BIN)?1'b1:1'b0;
//bin_valid:二值化输出有效标志
assign bin_valid = gus_valid;
endmodule
5、边缘检测模块
采用sobel算子进行边缘检测。
/**************************************功能介绍***********************************
Copyright:
Date :
Author :厉长川
Version :2022.10.13 v1
Description:边缘检测模块
-1 0 +1 +1 +2 +1
Gx = -2 0 +2 Gy = 0 0 0
-1 0 +1 -1 -2 -1
G = |Gx| + |Gy|;
*********************************************************************************/
`include "param.v"
module sobel(
input clk ,//pclk
input rst_n ,//复位信号
input bin_din ,//二值化输入
input bin_valid ,//二值化输入有效标志
output sobel_dout ,//边缘检测输出
output sobel_valid //边缘检测输出有效标志
);
//中间信号定义
wire taps0 ;//shift输出数据
wire taps1 ;//shift输出数据
wire taps2 ;//shift输出数据
reg taps0_1 ;//第一拍数据
reg taps1_1 ;//第一拍数据
reg taps2_1 ;//第一拍数据
reg taps0_2 ;//第二拍数据
reg taps1_2 ;//第二拍数据
reg taps2_2 ;//第二拍数据
reg [2:0] sumx_1 ;//x方向第一列
reg [2:0] sumx_3 ;//x方向第三列
reg [2:0] sumy_1 ;//y方向第一行
reg [2:0] sumy_3 ;//y方向第三行
reg [2:0] g_x ;//x方向梯度
reg [2:0] g_y ;//y方向梯度
reg [3:0] g ;//总梯度和
reg [4:0] valid_r ;//输入数据有效标志打四拍
//valid_r:输入数据有效标志打四拍
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
valid_r <= 5'b0;
end
else begin
valid_r <= {valid_r[3:0], bin_valid};
end
end
//shift输出数据打拍
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
taps0_1 <= 1'b0;
taps1_1 <= 1'b0;
taps2_1 <= 1'b0;
taps0_2 <= 1'b0;
taps1_2 <= 1'b0;
taps2_2 <= 1'b0;
end
else begin
taps0_1 <= taps0 ;
taps1_1 <= taps1 ;
taps2_1 <= taps2 ;
taps0_2 <= taps0_1;
taps1_2 <= taps1_1;
taps2_2 <= taps2_1;
end
end
//加权和
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sumx_1 <= 3'b0;
sumx_3 <= 3'b0;
sumy_1 <= 3'b0;
sumy_3 <= 3'b0;
end
else if(valid_r[1])begin
sumx_1 <= taps0 + {taps1 ,1'b1} + taps2;
sumx_3 <= taps0_2 + {taps1_2,1'b1} + taps2_2;
sumy_1 <= taps0 + {taps0_1,1'b1} + taps0_2;
sumy_3 <= taps2 + {taps2_1,1'b1} + taps2_2;
end
end
//x和y方向梯度
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
g_x <= 3'b0;
g_y <= 3'b0;
end
else if(valid_r[2])begin
g_x <= (sumx_1 > sumx_3)?sumx_1 - sumx_3:sumx_3 - sumx_1;
g_y <= (sumy_1 > sumy_3)?sumy_1 - sumy_3:sumy_3 - sumy_1;
end
end
//g:总梯度和
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
g <= 4'b0;
end
else if(valid_r[3])begin
g <= g_x + g_y;
end
end
//边缘检测结果
assign sobel_dout = (g > `SOBEL)?1'b1:1'b0;
//边缘检测数据有效标志
assign sobel_valid = valid_r[4];
shift_sobel shift_sobel_inst (
.clken ( bin_valid ),
.clock ( clk ),
.shiftin ( bin_din ),
.shiftout ( ),
.taps0x ( taps0 ),
.taps1x ( taps1 ),
.taps2x ( taps2 )
);
endmodule
6、图像处理模块
/**************************************功能介绍***********************************
Copyright:
Date :
Author :厉长川
Version :2022.10.13 v1
Description:图像数据处理模块
*********************************************************************************/
`include "param.v"
module process(
input clk ,//pclk
input rst_n ,//复位信号
input [15:0] rgb_din ,//rgb数据输入
input rgb_valid ,//rgb数据有效标志
output [15:0] pro_dout ,//处理完成输出
output pro_valid //处理完成输出有效标志
);
//中间信号定义
wire [7:0] gray_dout ;//灰度转换输出
wire gray_valid ;//灰度转换输出有效标志
wire [7:0] gus_dout ;//高斯滤波输出
wire gus_valid ;//高斯滤波输出有效标志
wire bin_dout ;//二值化输出
wire bin_valid ;//二值化输出有效标志
wire sobel_dout ;//边缘检测输出
wire sobel_valid;//边缘检测输出有效标志
//灰度转换模块
rgb2gray u_rgb2gray(
.clk (clk ),
.rst_n (rst_n ),
.rgb_valid (rgb_valid ),
.rgb_din (rgb_din ),
.gray_dout (gray_dout ),
.gray_valid (gray_valid )
);
//高斯滤波模块
gus_filter u_gus_filter(
.clk (clk ),
.rst_n (rst_n ),
.gray_din (gray_dout ),
.gray_valid (gray_valid ),
.gus_dout (gus_dout ),
.gus_valid (gus_valid )
);
//二值化模块
bin u_bin(
.clk (clk ),
.rst_n (rst_n ),
.gus_din (gus_dout ),
.gus_valid (gus_valid ),
.bin_dout (bin_dout ),
.bin_valid (bin_valid )
);
//边缘检测模块
sobel u_sobel(
.clk (clk ),
.rst_n (rst_n ),
.bin_din (bin_dout ),
.bin_valid (bin_valid ),
.sobel_dout (sobel_dout ),
.sobel_valid (sobel_valid )
);
//输出控制
`ifdef GRAY_OUT //输出灰度化图像
assign pro_dout = {gray_dout[7:3], gray_dout[7:2], gray_dout[7:3]};//灰度输出
assign pro_valid = gray_valid;//灰度输出有效标志
`endif
`ifdef GUS_OUT //输出高斯滤波图像
assign pro_dout = {gus_dout[7:3], gus_dout[7:2], gus_dout[7:3]};//高斯滤波输出
assign pro_valid = gus_valid;//高斯滤波输出有效标志
`endif
`ifdef BIN_OUT //输出二值化图像
assign pro_dout = {16{bin_dout}};//二值化输出
assign pro_valid = bin_valid;//二值化输出有效标志
`endif
`ifdef SOBEL_OUT//输出边缘检测图像
assign pro_dout = {16{sobel_dout}};//边缘检测输出
assign pro_valid = sobel_valid;//边缘检测输出有效标志
`endif
`ifdef NO_PRO //输出rgb图像
assign pro_dout = rgb_din;//rgb输出
assign pro_valid = rgb_valid;//rgb输出有效标志
`endif
endmodule
7、顶层模块
/**************************************功能介绍***********************************
Copyright:
Date :
Author :厉长川
Version :2022.10.10 v1
Description:顶层模块
*********************************************************************************/
module img_pro(
input clk ,//系统时钟50Mhz
input rst_n ,//复位信号,低电平有效
input [7:0] cmos_db ,//摄像头采集数据
input cmos_pclk ,//摄像头pclk时钟48MHz
input cmos_vsync ,//摄像头场同步信号
input cmos_href ,//摄像头行有效信号
output cmos_rst_n ,//摄像头复位信号
output cmos_xclk ,//摄像头xclk时钟24Mhz
output cmos_pwdn ,//摄像头掉电使能信号
output cmos_scl ,//摄像头配置时钟信号
inout cmos_sda ,//摄像头配置数据信号
output sdram_clk ,//sdram工作时钟
output sdram_cke ,//sdram使能
output [12:0] sdram_addr ,//sdram地址总线
output [1:0] sdram_ba ,//sdram bank地址
inout [15:0] sdram_dq ,//sdram数据总线
output [1:0] sdram_dqm ,//数据掩码
output [3:0] cmd ,//sdram操作命令
output vga_out_hs ,//vga行同步信号
output vga_out_vs ,//vga场同步信号
output [15:0] vga_dout //vga输出的RGB数据
);
//中间信号定义
wire vga_clk ;//vga时钟
wire clk_100MHz ;//100MHz工作时钟
wire done ;//摄像头配置完成标志
wire [15:0] pixel_dout ;//采集的像素数据
wire dout_valid ;//采集数据有效标志
wire [15:0] w_data ;//sdram写入数据
wire [15:0] r_data ;//sdram读出数据
wire [15:0] vga_din ;//vga输入数据
wire data_req ;//vga数据请求
wire [23:0] w_addr ;//sdram写地址
wire [23:0] r_addr ;//sdram读地址
wire sdram_rdreq ;//sdram数据接收fifo,读请求
wire sdram_wrreq ;//sdram数据发送fifo,写请求
wire r_ack ;//读响应
wire wr_ack ;//写响应
wire locked_1 ;//pll_1输出稳定标志
wire locked_2 ;//pll_2输出稳定标志
wire reset ;//sccb、data_cache、sdram和vga模块复位信号
wire init_done ;//sdram初始化结束
wire pixel_rst ;//pixel_sampling模块复位信号
wire w_done ;//写完成标志
wire r_done ;//读完成标志
wire pro_valid ;//灰度转换数据有效标志
wire [15:0] pro_dout ;//灰度转换输出
wire pclk ;//增强后的cmos_pclk
//sdram_cke:sdram使能
assign sdram_cke = 1'b1;
//sdram_dqm:数据掩码
assign sdram_dqm = 2'b00;
//reset:sccb、data_cache、sdram和vga模块复位信号
assign reset = locked_1 & locked_2 & rst_n;
//pixel_rst:pixel_sampling模块复位信号
assign pixel_rst = done & init_done & reset;
//时钟增强模块例化
iobuf iobuf_inst (
.datain ( cmos_pclk ),
.dataout ( pclk )
);
//摄像头配置模块例化
sccb u_sccb(
.clk (clk ),
.rst_n (reset ),
.done (done ),
.cmos_rst_n (cmos_rst_n ),
.cmos_pwdn (cmos_pwdn ),
.cmos_scl (cmos_scl ),
.cmos_sda (cmos_sda )
);
//摄像头数据拼接模块例化
pixel_sampling u_pixel_sampling(
.clk (pclk ),//摄像头pclk时钟48MHz
.rst_n (pixel_rst ),//pixel_sampling模块复位信号
.din (cmos_db ),//摄像头采集数据
.vsync (cmos_vsync ),//摄像头场同步信号
.href (cmos_href ),//摄像头行有效信号
.dout_valid (dout_valid ),//输出数据有效标志
.dout (pixel_dout ) //输出拼接完成的像素
);
//图像数据处理模块例化
process u_process(
.clk (pclk ),
.rst_n (pixel_rst ),
.rgb_din (pixel_dout ),
.rgb_valid (dout_valid ),
.pro_dout (pro_dout ),
.pro_valid (pro_valid )
);
//数据缓存模块例化
data_cache u_data_cache(
.clk (clk_100MHz ),
.rst_n (reset ),
.w_done (w_done ),
.r_done (r_done ),
.init_done (init_done ),
.r_data (pro_dout ),
.r_wrclk (pclk ),
.r_wrreq (pro_valid ),
.t_data (r_data ),
.t_rdclk (vga_clk ),
.t_rdreq (data_req ),
.w_ack (wr_ack ),
.r_ack (r_ack ),
.r_q (w_data ),
.w_addr (w_addr ),
.r_addr (r_addr ),
.t_q (vga_din ),
.sdram_rdreq (sdram_rdreq ),//sdram数据接收fifo,读请求
.sdram_wrreq (sdram_wrreq ) //sdram数据发送fifo,写请求
);
//sdram操作模块例化
sdram u_sdram(
.clk (clk_100MHz ),
.rst_n (reset ),
.w_req (sdram_wrreq ),
.r_req (sdram_rdreq ),
.w_addr (w_addr ),
.r_addr (r_addr ),
.w_data (w_data ),
.r_data (r_data ),
.sdram_addr (sdram_addr ),
.sdram_ba (sdram_ba ),
.sdram_dq (sdram_dq ),
.cmd (cmd ),
.init_done (init_done ),
.r_ack (r_ack ),
.wr_ack (wr_ack ),
.w_done (w_done ),//写操作完成标志
.r_done (r_done ) //读操作完成标志
);
//vga驱动模块例化
vga u_vga(
.clk (vga_clk ),
.rst_n (reset ),
.din (vga_din ),
.vga_out_hs (vga_out_hs ),
.vga_out_vs (vga_out_vs ),
.vga_dout (vga_dout ),
.data_req (data_req )
);
//时钟模块1例化
pll_1 pll_1_inst (
.areset (~rst_n ),
.inclk0 (clk ),//50MHz
.c0 (vga_clk ),//65MHz
.c1 (clk_100MHz ),//100MHz
.c2 (sdram_clk ),//100MHz,-75deg
.locked (locked_1 )
);
//时钟模块2例化
pll_2 pll_2_inst (
.areset (~rst_n ),
.inclk0 (clk ),//50MHz系统时钟
.c0 (cmos_xclk ),//24Mhz
.locked (locked_2 )
);
endmodule
8、参数定义
可以通过参数定义修改二值化和边缘检测阈值,以及控制是否进行图像处理和图像处理类型选择。
/**************************************功能介绍***********************************
Copyright:
Date :
Author :厉长川
Version :2022.10.10 v1
Description:参数定义
*********************************************************************************/
//sccb参数定义
`define CNT_1M 6'd50 //1M时钟计数
`define CNT_MS 21'd1315000 //26.3ms时间计数
`define PWDN 18'd255000 //5.1ms计时
`define RST_CMOS 19'd310000 //1.1ms复位等待时间
`define NUM_CFG 8'd248 //寄存器配置个数
//pixel_sampling参数定义
`define PIXEL 4'd10 //舍弃帧数
//vga接口参数
// 1024*768 65Mhz
`define H_ACTIVE 11'd1024 //行有效
`define H_FP 11'd24 //行前沿
`define H_SYNC 11'd136 //行同步
`define H_BP 11'd160 //行后沿
`define H_TO 11'd1344 //行周期
`define V_ACTIVE 11'd768 //场有效
`define V_FP 11'd3 //场前沿
`define V_SYNC 11'd6 //场同步
`define V_BP 11'd29 //场后沿
`define V_TO 11'd806 //场周期
//sdram模块参数
`define CMD_NOOP 4'b0111 //空指令
`define CMD_ACT 4'b0011 //行激活指令
`define CMD_RD 4'b0101 //读指令
`define CMD_WR 4'b0100 //写指令
`define CMD_BR 4'b0110 //突发终止指令
`define CMD_PRE 4'b0010 //预充电指令
`define CMD_AREF 4'b0001 //自动刷新指令
`define CMD_MOD 4'b0000 //模式寄存器配置命令
`define INIT_TIME 14'd10000 //上电等待时间,10000个时钟周期(100us)
`define AREF_TIME 10'd700 //自动刷新间隔时间,700个时钟周期(7us)
`define BURST_LEN 10'd512 //读写突发长度
`define ADDR_END `H_ACTIVE * `V_ACTIVE - `BURST_LEN //读写地址末地址
//阈值参数
`define BIN 7'd127 //二值化阈值
`define SOBEL 2'd3 //边缘检测阈值
//图像处理控制参数
// `define GRAY_OUT //输出灰度化图像
// `define GUS_OUT //输出高斯滤波图像
// `define BIN_OUT //输出二值化图像
// `define SOBEL_OUT //输出边缘检测图像
`define NO_PRO //输出rgb图像
9、最终效果
高斯滤波效果不明显不做演示。
①:灰度转换
②:二值化
文章来源:https://www.toymoban.com/news/detail-509863.html
③:边缘检测
文章来源地址https://www.toymoban.com/news/detail-509863.html
到了这里,关于二、FPGA实时图像处理(灰度转换、高斯滤波、二值化和边缘检测)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!