42人参与 • 2024-08-06 • fpga开发
基于图像实时采集系统实现图像处理
算法:采用精度为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
/**************************************功能介绍***********************************
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
/**************************************功能介绍***********************************
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
采用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
/**************************************功能介绍***********************************
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
/**************************************功能介绍***********************************
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
可以通过参数定义修改二值化和边缘检测阈值,以及控制是否进行图像处理和图像处理类型选择。
/**************************************功能介绍***********************************
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图像
高斯滤波效果不明显不做演示。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论