基于EBAZ4205矿板的图像处理:09基于sobel边缘检测的图像锐化
项目全部文件
随后会上传项目全部文件
先看效果
锐化的有点过头了,不过我也懒得改了,想要改也很简单,无非就是给卷积运算后的结果加个系数,通过改系数调整加权的值。
算法简介
sobel边缘检测,实际上就是对g=f(x,y)这个函数求导,其中x和y是像素点的坐标,g是像素点的灰度值,求导嘛,就是找出像素随着位置变化的梯度,像素数值变化大的地方自然就是图像中的边缘、边界了。
sobel锐化就是将上述求导求出的梯度数值和卷积运算的滑动窗口的中心像素的灰度像素值加和,然后用加和结果替代中心像素的灰度像素值,当然这一加和的过程中,可以加上一个系数。这样我们就可以动态调整图像的锐化效果。
算法的FPGA部署
先是卷积乘法,然后把乘法的结果加在一起。再开方。开方的结果直接加在该卷积滑动窗口的中心像素点上。
项目代码
我会上传项目全部文件,这里就只粘贴部分关键代码了
图像锐化模块
`timescale 1ns / 1ps
module sobel_sharpper
((* X_INTERFACE_IGNORE = "true" *) input wire clk ,(* X_INTERFACE_IGNORE = "true" *) input wire rst_n ,(* X_INTERFACE_IGNORE = "true" *) input wire matrix_img_vsync,(* X_INTERFACE_IGNORE = "true" *) input wire matrix_img_href,//(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] sobel_thresh ,//8'd96(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p11,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p12,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p13,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p21,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p22,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p23,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p31,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p32,(* X_INTERFACE_IGNORE = "true" *) input wire [7:0] matrix_p33,(* X_INTERFACE_IGNORE = "true" *) input wire matrix_frame_ce,(* X_INTERFACE_IGNORE = "true" *) output wire dataout_vsync , // processed Image data vsync valid signal(* X_INTERFACE_IGNORE = "true" *) output wire dataout_href , // processed Image data href vaild signal(* X_INTERFACE_IGNORE = "true" *) output wire [23:0] dataout_gray , // processed Image brightness output(* X_INTERFACE_IGNORE = "true" *) output wire dataout_frame_ce
);//----------------------------------------------------------------------
// [p11,p12,p13] [-1,0,1]
// Gx_data = [p21,p22,p23] * [-2,0,2] = (p13+2*p23+p33) - (p11+2*p21+p31)
// [p31,p32,p33] [-1,0,1]
//
// [p11,p12,p13] [-1,-2,-1]
// Gy_data = [p21,p22,p23] * [ 0, 0, 0] = (p31+2*p32+p33) - (p11+2*p12+p13)
// [p31,p32,p33] [ 1, 2, 1]
//
// G_data = sqrt(Gx_data^2 + Gy_data^2)
reg [ 9:0] Gx_data_tmp1;
reg [ 9:0] Gx_data_tmp2;
reg [ 9:0] Gy_data_tmp1;
reg [ 9:0] Gy_data_tmp2;
reg signed [10:0] Gx_data;
reg signed [10:0] Gy_data;
reg signed [21:0] Gx_square_data;
reg signed [21:0] Gy_square_data;
reg [20:0] G_square_data;
wire [10:0] G_data;always @(posedge clk)
beginGx_data_tmp1 <= matrix_p13 + {matrix_p23,1'b0} + matrix_p33;Gx_data_tmp2 <= matrix_p11 + {matrix_p21,1'b0} + matrix_p31;Gy_data_tmp1 <= matrix_p31 + {matrix_p32,1'b0} + matrix_p33;Gy_data_tmp2 <= matrix_p11 + {matrix_p12,1'b0} + matrix_p13;Gx_data <= $signed({1'b0,Gx_data_tmp1}) - $signed({1'b0,Gx_data_tmp2});Gy_data <= $signed({1'b0,Gy_data_tmp1}) - $signed({1'b0,Gy_data_tmp2});Gx_square_data <= $signed(Gx_data) * $signed(Gx_data);Gy_square_data <= $signed(Gy_data) * $signed(Gy_data);G_square_data <= Gx_square_data[20:0] + Gy_square_data[20:0];
endsqrt u_sqrt
(.sys_clk (clk ),.sys_rst (~rst_n ),.din (G_square_data ),.din_valid (1'b1 ),.dout (G_data ),.dout_valid ( )
);//----------------------------------------------------------------------
// lag 16 clocks signal sync
reg [15:0] matrix_img_vsync_r1;
reg [15:0] matrix_img_href_r1;
reg [15:0] matrix_frame_ce_r1;always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginmatrix_img_vsync_r1 <= 16'b0;matrix_img_href_r1 <= 16'b0;matrix_frame_ce_r1 <= 16'b0;endelsebeginmatrix_img_vsync_r1 <= {matrix_img_vsync_r1[14:0],matrix_img_vsync};matrix_img_href_r1 <= {matrix_img_href_r1[14:0],matrix_img_href};matrix_frame_ce_r1 <= {matrix_frame_ce_r1[14:0],matrix_frame_ce};end
endreg [7:0] matrix_p22_r1 [0:15];always @(posedge clk)
beginmatrix_p22_r1[ 0] <= matrix_p22;matrix_p22_r1[ 1] <= matrix_p22_r1[ 0];matrix_p22_r1[ 2] <= matrix_p22_r1[ 1];matrix_p22_r1[ 3] <= matrix_p22_r1[ 2];matrix_p22_r1[ 4] <= matrix_p22_r1[ 3];matrix_p22_r1[ 5] <= matrix_p22_r1[ 4];matrix_p22_r1[ 6] <= matrix_p22_r1[ 5];matrix_p22_r1[ 7] <= matrix_p22_r1[ 6];matrix_p22_r1[ 8] <= matrix_p22_r1[ 7];matrix_p22_r1[ 9] <= matrix_p22_r1[ 8];matrix_p22_r1[10] <= matrix_p22_r1[ 9];matrix_p22_r1[11] <= matrix_p22_r1[10];matrix_p22_r1[12] <= matrix_p22_r1[11];matrix_p22_r1[13] <= matrix_p22_r1[12];matrix_p22_r1[14] <= matrix_p22_r1[13];matrix_p22_r1[15] <= matrix_p22_r1[14];
end//----------------------------------------------------------------------
reg [11:0] pixel_data1;always @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_data1 <= matrix_p22_r1[15];elsepixel_data1 <= matrix_p22_r1[15] + G_data;
endreg [7:0] pixel_data2;always @(posedge clk)
beginif(pixel_data1 > 12'd255)pixel_data2 <= 8'd255;elsepixel_data2 <= pixel_data1[7:0];
end//----------------------------------------------------------------------
// lag 2 clocks signal sync
reg [1:0] matrix_img_vsync_r2;
reg [1:0] matrix_img_href_r2;
reg [1:0] matrix_frame_ce_r2;always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginmatrix_img_vsync_r2 <= 2'b0;matrix_img_href_r2 <= 2'b0;matrix_frame_ce_r2 <= 2'b0;endelsebeginmatrix_img_vsync_r2 <= {matrix_img_vsync_r2[0],matrix_img_vsync_r1[15]};matrix_img_href_r2 <= {matrix_img_href_r2[0],matrix_img_href_r1[15]};matrix_frame_ce_r2 <= {matrix_frame_ce_r2[0],matrix_frame_ce_r1[15]};end
end//----------------------------------------------------------------------
// result output
assign dataout_gray = {3{pixel_data2}};
assign dataout_vsync = matrix_img_vsync_r2[1];
assign dataout_href = matrix_img_href_r2[1];
assign dataout_frame_ce = matrix_frame_ce_r2[1];endmodule
vitis代码
//作者:抢公主的大魔王
//功能:图像sobel锐化
//日期:24.5.24
//版本:1v0
//联系方式:2376635586@qq.com
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xil_types.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xplatform_info.h"
#include "xaxivdma.h"
#include "xaxivdma_i.h"
#include "display_ctrl_hdmi/display_ctrl.h"
#include "vdma_api/vdma_api.h"
#include "emio_sccb_cfg/emio_sccb_cfg.h"
#include "ov5640/ov5640_init.h"
#include "sleep.h"
#include "xuartps.h"
#include "string.h"//宏定义
#define DYNCLK_BASEADDR XPAR_AXI_DYNCLK_0_BASEADDR //动态时钟基地址
#define VDMA_ID XPAR_AXIVDMA_0_DEVICE_ID //VDMA器件ID
#define DISP_VTC_ID XPAR_VTC_0_DEVICE_ID //VTC器件ID
#define UART_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID //串口设备ID
#define UART_INT_IRQ_ID XPAR_XUARTPS_0_INTR //串口中断ID
//#define THRESHOLD_BASEADDR XPAR_AXICTRLTHRESHOLD_0_S00_AXI_BASEADDR#define EMIO_SCL_NUM 54
#define EMIO_SDA_NUM 55
#define KEY1 56 //T19
#define KEY2 57 //P19
#define KEY3 58 //U20
#define KEY4 59 //U19
#define KEY5 60 //V20
#define LED1 61 //H18
#define LED2 62 //K17
#define LED3 63 //E19#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
XGpioPs Gpio;
#define GPIO_BANK XGPIOPS_BANK0 /* Bank 0 of the GPIO Device */
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define GPIO_INTERRUPT_ID XPAR_XGPIOPS_0_INTR//全局变量
//frame buffer的起始地址
unsigned int const frame_buffer_addr = (XPAR_PS7_DDR_0_S_AXI_BASEADDR+ 0x1000000);
//u8 binary_threshold = 128;
//u8 sobel_threshold = 153;XAxiVdma vdma;
DisplayCtrl dispCtrl;
VideoMode vd_mode;void Gpio_Init(void){XGpioPs_Config *ConfigPtr;ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);XGpioPs_SetDirectionPin(&Gpio, LED1, 1);XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1);XGpioPs_WritePin(&Gpio, LED1, 0);}int main(void)
{u32 status;u16 cmos_h_pixel; //ov5640 DVP 输出水平像素点数u16 cmos_v_pixel; //ov5640 DVP 输出垂直像素点数u16 total_h_pixel; //ov5640 水平总像素大小u16 total_v_pixel; //ov5640 垂直总像素大小cmos_h_pixel = 1280;cmos_v_pixel = 720;total_h_pixel = 2570;total_v_pixel = 980;emio_init();//控制hdmi的emio初始化//xil_printf("Uart and Key is init successful! \r\n");//xil_printf("ov5640 is initing! \r\n");status = ov5640_init( cmos_h_pixel, //初始化ov5640cmos_v_pixel,total_h_pixel,total_v_pixel);//设置OV5640输出分辨率为1280*720 PCLK = 72Mhzif(status == 0);//xil_printf("OV5640 init successful!\r\n");elsexil_printf("OV5640 detected failed!\r\n");xil_printf("Uart and OV5640 is init successful! \r\n\r\n");sleep(1);vd_mode = VMODE_1280x720;//配置VDMArun_vdma_frame_buffer(&vdma, VDMA_ID, vd_mode.width, vd_mode.height,frame_buffer_addr,0,0,BOTH);//初始化Display controllerDisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);//设置VideoModeDisplaySetMode(&dispCtrl, &vd_mode);DisplayStart(&dispCtrl);Gpio_Init();//按键和led的初始化//Xil_Out32(THRESHOLD_BASEADDR, binary_threshold);//Xil_Out32(THRESHOLD_BASEADDR+4, sobel_threshold);while(1){XGpioPs_WritePin(&Gpio, LED1, !XGpioPs_ReadPin(&Gpio, LED3));sleep(1);}return 0;
}