基于EBAZ4205矿板的图像处理:12图像二值化(阈值可调)

基于EBAZ4205矿板的图像处理:12图像二值化(阈值可调)

我的项目是基于EBAZ4205矿板的阈值可调的图像阈值二值化处理,可以通过按键调整二值化的阈值,key1为阈值加1,key4为阈值减1,key2为阈值加10,key5为阈值减10,key54为阈值重置为128。

先看效果

拿我的pynq当模特

可以清晰的看到xilinx的商标被划分了出来

阈值过大和过小就不行了,这也是全局阈值二值化的缺点,接下来我会完成基于卷积的局部阈值二值化,它能得到更好的效果,尽请期待。

项目解读

我的blockdesign,你不按照我的接,按照正点原子的开源代码接也是可以的,只是我有强迫症,能接的我都接了。

就是在标准的ov5640->VDMA->DDR->VDMA->DVI_Driver->HDMI的流程(可以点击这个超链接看我说的标准流程)的第一个箭头哪里加了三个模块,一个负责将图像从RGB格式转化为灰度图像,一个负责对灰度图像进行二值化处理,最后一个为PS提供了访问PL端reg的AXILite端口,以便实时调整阈值。

下面的代码里我都添加了(* X_INTERFACE_IGNORE = "true" *) ,是禁用vivado的interface自动推断,可以不加

rgb2gray模块

该模块负责将图像从RGB格式转化为灰度图像

公式:

Y = 0.299R +0.587G + 0.114B

Y = (77 R + 150G + 29 *B)>>8

c 复制代码
`timescale 1ns / 1ps
//作者:抢公主的大魔王
//功能:将来自ov5640视频流从RGB格式转化为灰度图像
//日期:24.5.5
//版本:1v0
//联系方式:2376635586@qq.com
module rgb2gray(
    
(* X_INTERFACE_IGNORE = "true" *)  input           cmos_frame_vsync,
(* X_INTERFACE_IGNORE = "true" *)  input [23:0]    cmos_frame_data,
(* X_INTERFACE_IGNORE = "true" *)  input           cmos_frame_href,

(* X_INTERFACE_IGNORE = "true" *)  input           cmos_frame_clk,
(* X_INTERFACE_IGNORE = "true" *)  input           cmos_rstn,//同步复位
(* X_INTERFACE_IGNORE = "true" *)  input           cmos_frame_ce,

(* X_INTERFACE_IGNORE = "true" *)  output          dataout_frame_vsync,
(* X_INTERFACE_IGNORE = "true" *)  output [23:0]   dataout_frame_data,
(* X_INTERFACE_IGNORE = "true" *)  output          dataout_frame_href,
(* X_INTERFACE_IGNORE = "true" *)  output          dataout_frame_ce
    );
    // Y = 0.299R +0.587G + 0.114B
    // Y = (77 *R + 150*G + 29 *B)>>8
    reg [15:0] r_gray1;
    reg [15:0] g_gray1;
    reg [15:0] b_gray1;
    reg [15:0] y1;
    reg [7:0] y2;
    reg [2:0] dataout_frame_vsync_r;
    reg [2:0] dataout_frame_href_r;
    reg [2:0] dataout_frame_ce_r;


    always@(posedge cmos_frame_clk)begin
        if(!cmos_rstn)begin
            r_gray1 <= 8'h00;
            g_gray1 <= 8'h00;
            b_gray1 <= 8'h00;
        end
        else begin
            r_gray1 <= cmos_frame_data[23:16]  * 8'd77 ;
            g_gray1 <= cmos_frame_data[15:8]   * 8'd150;
            b_gray1 <= cmos_frame_data[7:0]    * 8'd29 ;
        end
    end

    always@(posedge cmos_frame_clk)begin
        if(!cmos_rstn)begin
            y1 <= 16'h0000;
        end
        else begin
            y1 <= r_gray1 + g_gray1 + b_gray1;
        end
    end

    always@(posedge cmos_frame_clk)begin
        if(!cmos_rstn)begin
            y2 <= 8'h0000;
        end
        else begin
            y2 <= y1[15:8];
        end
    end

    

    always@(posedge cmos_frame_clk)begin
        if(!cmos_rstn)begin
            dataout_frame_ce_r      <= 3'b000;
            dataout_frame_vsync_r   <= 3'b000;
            dataout_frame_href_r    <= 3'b000;
        end
        else begin
            dataout_frame_ce_r      <= {dataout_frame_ce_r[1:0]     ,cmos_frame_ce};
            dataout_frame_vsync_r   <= {dataout_frame_vsync_r[1:0]  ,cmos_frame_vsync};
            dataout_frame_href_r    <= {dataout_frame_href_r[1:0]   ,cmos_frame_href};
        end
    end
    assign dataout_frame_data = {y2,y2,y2};
    assign dataout_frame_ce = dataout_frame_ce_r[2];
    assign dataout_frame_vsync = dataout_frame_vsync_r[2];
    assign dataout_frame_href = dataout_frame_href_r[2];


endmodule

global_binary模块

负责根据阈值对灰度图像进行二值化处理

c 复制代码
`timescale 1ns / 1ps
//作者:抢公主的大魔王
//功能:根据阈值对灰度图像进行二值化处理
//日期:24.5.5
//版本:1v0
//联系方式:2376635586@qq.com
module global_binary(
(* X_INTERFACE_IGNORE = "true" *)  input           datain_vsync,
(* X_INTERFACE_IGNORE = "true" *)  input [23:0]    datain,
(* X_INTERFACE_IGNORE = "true" *)  input           datain_href,

(* X_INTERFACE_IGNORE = "true" *)  input           datain_clk,
(* X_INTERFACE_IGNORE = "true" *)  input           datain_rstn,//同步复位
(* X_INTERFACE_IGNORE = "true" *)  input           datain_frame_ce,

(* X_INTERFACE_IGNORE = "true" *)  input      [7:0]threshold,

(* X_INTERFACE_IGNORE = "true" *)  output          dataout_vsync,
(* X_INTERFACE_IGNORE = "true" *)  output reg [23:0]   dataout,
(* X_INTERFACE_IGNORE = "true" *)  output          dataout_vaild,

(* X_INTERFACE_IGNORE = "true" *)  output          dataout_frame_ce
    );

reg [1:0] dataout_vsync_r;
reg [1:0] dataout_valid_r;
reg [1:0] dataout_frame_ce_r;
always@(posedge datain_clk)begin
    if(!datain_rstn)
        dataout <= 24'hff_ff_ff;
    else if(datain[7:0]>=threshold)
        dataout <= 24'hff_ff_ff;
    else
        dataout  <= 24'h00_00_00;
end
always@(posedge datain_clk)begin
    if(!datain_rstn) begin
        dataout_vsync_r     <=  3'b000;
        dataout_valid_r     <=  3'b000;
        dataout_frame_ce_r  <=  3'b000;
    end
    else begin
        dataout_vsync_r     <=  {dataout_vsync_r[0]     , datain_vsync};
        dataout_valid_r     <=  {dataout_valid_r[0]     , datain_href};
        dataout_frame_ce_r  <=  {dataout_frame_ce_r[0]  , datain_frame_ce};
    end
end

assign dataout_vsync        = dataout_vsync_r[1];
assign dataout_vaild        = dataout_valid_r[1];
assign dataout_frame_ce     = dataout_frame_ce_r[1];

endmodule

AXICtrlThreshold模块

这个就是自己打包的标准的AXILite IP核,然后加了两句代码,一句是将threshold的0到7为连接到这个IP内部的第一个reg的低八位,另一句就是让这个reg复位是被复位为128,而不是0,因为我的图像阈值二值化算法的缺省阈值为128。

打包过程如下

下面要改名字和描述哦。

然后到了这个AXILite IP内部添加下面的代码

c 复制代码
assign threshold = slv_reg0[7:0];

然后更改复位值

c 复制代码
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      slv_reg0 <= 32'd128;
	      slv_reg1 <= 0;
	      slv_reg2 <= 0;
	      slv_reg3 <= 0;
	    end 

最后把它output出去

c 复制代码
output wire [7:0] threshold

IP代码本身,和她的top层都要output

然后在这一栏,所有不是对号的要挨个点一遍,挨个更新一下,最后全是对号之后,就可以打包了。

vitis端代码

IntrHandler是中断回调函数,触发中断后会调用这个函数。

SetupInterruptSystem负责初始化中断,配置触发中断方式,使能中断。

Gpio_Init初始化GPIO,包括key1-5,led1-3和sccb总线(配置OV5640的)

binary_threshold就是我的图像阈值二值化的阈值啦,可以通过按键进行调整。

c 复制代码
//作者:抢公主的大魔王
//功能:阈值可调的图像二值化
//日期:24.5.5
//版本: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"

//宏定义
#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 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;
XAxiVdma     vdma;
DisplayCtrl  dispCtrl;
VideoMode    vd_mode;

static XScuGic Intc; /* The Instance of the Interrupt Controller Driver */


static void IntrHandler(void *CallBackRef, u32 Bank, u32 Status)
{
	XGpioPs *Gpio_cb = (XGpioPs *)CallBackRef;
	if (XGpioPs_IntrGetStatusPin(Gpio_cb, KEY1)){
		binary_threshold++;
		Xil_Out32(THRESHOLD_BASEADDR, binary_threshold);
		xil_printf("The threshold has been changed\n\rThe threshold now is %d\n\r",binary_threshold);
		XGpioPs_IntrClearPin(Gpio_cb, KEY1);
	}
	else if (XGpioPs_IntrGetStatusPin(Gpio_cb, KEY4)){
		binary_threshold--;
		Xil_Out32(THRESHOLD_BASEADDR, binary_threshold);
		xil_printf("The threshold has been changed\n\rThe threshold now is %d\n\r",binary_threshold);
		XGpioPs_IntrClearPin(Gpio_cb, KEY4);
	}
	else if (XGpioPs_IntrGetStatusPin(Gpio_cb, KEY2)){
		binary_threshold = binary_threshold+10;
		Xil_Out32(THRESHOLD_BASEADDR, binary_threshold);
		xil_printf("The threshold has been changed\n\rThe threshold now is %d\n\r",binary_threshold);
		XGpioPs_IntrClearPin(Gpio_cb, KEY2);
	}
	else if (XGpioPs_IntrGetStatusPin(Gpio_cb, KEY5)){
		binary_threshold = binary_threshold-10;
		Xil_Out32(THRESHOLD_BASEADDR, binary_threshold);
		xil_printf("The threshold has been changed\n\rThe threshold now is %d\n\r",binary_threshold);
		XGpioPs_IntrClearPin(Gpio_cb, KEY5);
	}
	else if (XGpioPs_IntrGetStatusPin(Gpio_cb, KEY3)){
		binary_threshold = 128;
		Xil_Out32(THRESHOLD_BASEADDR, binary_threshold);
		xil_printf("The threshold has been reset\n\rThe threshold now is %d\n\r",binary_threshold);
		XGpioPs_IntrClearPin(Gpio_cb, KEY3);
	}
	XGpioPs_WritePin(&Gpio, LED1, !XGpioPs_ReadPin(&Gpio, LED1));
}



void SetupInterruptSystem(XScuGic *GicInstancePtr, XGpioPs *Gpio,
				u16 GpioIntrId){

	XScuGic_Config *IntcConfig;
	Xil_ExceptionInit();

	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);

	XScuGic_CfgInitialize(GicInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);

	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler)XScuGic_InterruptHandler,
				GicInstancePtr);
	XScuGic_Connect(GicInstancePtr, GpioIntrId,
				(Xil_ExceptionHandler)IntrHandler,
				(void *)Gpio);


	XScuGic_Enable(GicInstancePtr, GpioIntrId);

	XGpioPs_SetIntrTypePin(Gpio, KEY1,  XGPIOPS_IRQ_TYPE_EDGE_FALLING);
	XGpioPs_SetIntrTypePin(Gpio, KEY2,  XGPIOPS_IRQ_TYPE_EDGE_FALLING);
	XGpioPs_SetIntrTypePin(Gpio, KEY3,  XGPIOPS_IRQ_TYPE_EDGE_FALLING);
	XGpioPs_SetIntrTypePin(Gpio, KEY4,  XGPIOPS_IRQ_TYPE_EDGE_FALLING);
	XGpioPs_SetIntrTypePin(Gpio, KEY5,  XGPIOPS_IRQ_TYPE_EDGE_FALLING);

	XGpioPs_IntrEnablePin(Gpio, KEY1);
	XGpioPs_IntrEnablePin(Gpio, KEY2);
	XGpioPs_IntrEnablePin(Gpio, KEY3);
	XGpioPs_IntrEnablePin(Gpio, KEY4);
	XGpioPs_IntrEnablePin(Gpio, KEY5);

	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
}


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);

	XGpioPs_SetDirectionPin(&Gpio, LED2, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1);
	XGpioPs_WritePin(&Gpio, LED2, 0);

	XGpioPs_SetDirectionPin(&Gpio, LED3, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, LED3, 1);
	XGpioPs_WritePin(&Gpio, LED3, 0);

	XGpioPs_SetDirectionPin(&Gpio, KEY1, 0);
	XGpioPs_SetDirectionPin(&Gpio, KEY2, 0);
	XGpioPs_SetDirectionPin(&Gpio, KEY3, 0);
	XGpioPs_SetDirectionPin(&Gpio, KEY4, 0);
	XGpioPs_SetDirectionPin(&Gpio, KEY5, 0);

	SetupInterruptSystem(&Intc, &Gpio, GPIO_INTERRUPT_ID);

}


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();
	status = ov5640_init( cmos_h_pixel,  //初始化ov5640
						  cmos_v_pixel,
						 total_h_pixel,
						 total_v_pixel);//设置OV5640输出分辨率为1280*720  PCLK = 72Mhz
	if(status == 0)
		xil_printf("OV5640 detected successful!\r\n");
	else
		xil_printf("OV5640 detected failed!\r\n");

	vd_mode = VMODE_1280x720;

	//配置VDMA
	run_vdma_frame_buffer(&vdma, VDMA_ID, vd_mode.width, vd_mode.height,
							frame_buffer_addr,0,0,BOTH);
    //初始化Display controller
	DisplayInitialize(&dispCtrl, DISP_VTC_ID, DYNCLK_BASEADDR);
    //设置VideoMode
	DisplaySetMode(&dispCtrl, &vd_mode);
	DisplayStart(&dispCtrl);
	Gpio_Init();
	while(1){
		XGpioPs_WritePin(&Gpio, LED3, !XGpioPs_ReadPin(&Gpio, LED3));
		sleep(1);
	}
    return 0;
}
相关推荐
老艾的AI世界40 分钟前
新一代AI换脸更自然,DeepLiveCam下载介绍(可直播)
图像处理·人工智能·深度学习·神经网络·目标检测·机器学习·ai换脸·视频换脸·直播换脸·图片换脸
喵~来学编程啦3 小时前
【论文精读】LPT: Long-tailed prompt tuning for image classification
人工智能·深度学习·机器学习·计算机视觉·论文笔记
DS小龙哥4 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
凤枭香6 小时前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
蒙娜丽宁8 小时前
《Python OpenCV从菜鸟到高手》——零基础进阶,开启图像处理与计算机视觉的大门!
python·opencv·计算机视觉
好喜欢吃红柚子9 小时前
万字长文解读空间、通道注意力机制机制和超详细代码逐行分析(SE,CBAM,SGE,CA,ECA,TA)
人工智能·pytorch·python·计算机视觉·cnn
AI小杨9 小时前
【车道线检测】一、传统车道线检测:基于霍夫变换的车道线检测史诗级详细教程
人工智能·opencv·计算机视觉·霍夫变换·车道线检测
撞南墙者12 小时前
OpenCV自学系列(1)——简介和GUI特征操作
人工智能·opencv·计算机视觉
王哈哈^_^12 小时前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt