FPGA-HDMI-图片Sobel滤波显示实验(ZYBO Z7)

在这里插入图片描述

目录

  • 前言
  • 1. 算法构建
  • 2. 编程实现
    • 2.1 灰度转换
    • 2.2 状态设定
    • 2.3 基于sobel的边缘滤波运算
    • 2.4 计算结果输出
  • 3. 波形仿真
  • 4. 板级验证

前言

前文已经介绍了如何将静态图片进行二值化或者灰度化显示,本节是在此前实验的基础上,对图像进行soble滤波处理,关于数字图像的滤波算法,可参考博客MATLAB-梯度Roberts算子、拉普拉斯算子、Sobel算子、Prewitt算子对图像进行锐化。该文章主要讲述算法构建,编程实现,时序仿真和板级验证四个环节。

1. 算法构建

首先需要构建一个3×3的soble算子,具体如图1所示。本文以垂直为例,进行实验的开展。主要思想参考了视频soble边缘检测。我们首先需要将彩色图片转化为灰度,这一部分FPGA-HDMI-静态图片(灰度化)显示实验(ZYBO Z7一样的。可以在此基础上进行扩展。
FPGA-HDMI-图片Sobel滤波显示实验(ZYBO Z7)_第1张图片

图1 soble算子

从图1可以发现,在进行sobel滤波时,中间一行并没有参与运算,所以可以采用状态机的方式进行算法的实现,我们可以构建两个状态,即0状态和1状态。其中偶数行表示0状态,奇数行表示1状态。同时我们定义两个缓存列表,用于暂存上两行的数据,分别定义为line_buff0(偶数行)和line_buff1(奇数行)。假设当前行为T,则指示为0状态时,参与运算的是当前行的值和缓存于line_buff0的数据,图2对这一过程进行了直观的说说明。最后将得到的数据进项重新赋值即可

FPGA-HDMI-图片Sobel滤波显示实验(ZYBO Z7)_第2张图片

图2 算法运算流程

2. 编程实现

2.1 灰度转换

对图片的灰度处理,仍采用了最简单的实现方法,即以RGB三通道的平均值,作为灰度值,代码实现如下:

//----------------------灰度转换--------------

wire [7:0] R_pixel;
wire [7:0] G_pixel;
wire [7:0] B_pixel;

//通道切分
assign R_pixel = pixel_data[23:16];
assign G_pixel = pixel_data[15:8];
assign B_pixel = pixel_data[7:0];

//灰度转换
wire [7:0] gray;
wire [9:0] mean_data_rgb; 

assign mean_data_rgb = (R_pixel+ G_pixel + B_pixel)/3;
assign gray = data_valid ? mean_data_rgb[7:0]:'d0;

2.2 状态设定

考虑到该实验的状态只有两种,即0状态和1状态,所以可以采用时钟边沿触发的方式来实现,假定第一行为0状态,每当检测到图片一行的第一个像素点时,设定为高电平,其他状态为低电平,这样就产生了一个触发沿,我们在以该时钟的上升沿的触发方式进行电平的反转,这样就实现了奇数行为1状态,偶数行为0状态,具体代码的实现如下:

reg line_clk;
always @(posedge pixel_clk) begin
    if(pixel_ypos>'d0 && pixel_ypos <= 225)    begin
        if (pixel_xpos == 'd0) begin
            line_clk <= 1'd1;  
        end
        else begin
            line_clk <= 1'd0;
        end
    end
end


reg state;
always @(posedge line_clk) begin
    if (pixel_ypos == 'd1) begin  
        state <= 0;            
    end else begin
        state <= ~state;         
    end
end

2.3 基于sobel的边缘滤波运算

具体的实现思路在第一小节已进行分析,程序和核心就是暂存前前两行的数据line_buff0line_buff1和当前行的3个像素值p2p1p0,代码实如下:

reg                    [   7:0]         p0                         ;
reg                    [   7:0]         p1                         ;
reg                    [   7:0]         p2                         ;
reg                    [   7:0]         line_buff0[299:0]          ;
reg                    [   7:0]         line_buff1[299:0]          ;
reg                    [   7:0]         conv_out                   ;

always @(posedge pixel_clk) begin
    if(data_valid) begin
        case (state)
            'b0:begin 
                line_buff0[pixel_xpos] <= gray;                    
                line_buff1[pixel_xpos] <= line_buff1[pixel_xpos];   
                p2 <= gray;
                p1 <= p2;
                p0 <= p1;
                if(pixel_xpos > 'd2 && pixel_ypos >'d2)  begin 
                    if((p0+2*p1+p2)>(line_buff0[pixel_xpos-2]+2*line_buff0[pixel_xpos-1]+line_buff0[pixel_xpos])) begin
                        conv_out <= (p0+2*p1+p2)-(line_buff0[pixel_xpos-2]+2*line_buff0[pixel_xpos-1]+line_buff0[pixel_xpos]);
                    end
                    else begin
                        conv_out <= (line_buff0[pixel_xpos-2]+2*line_buff0[pixel_xpos-1]+line_buff0[pixel_xpos])-(p0+2*p1+p2);
                    end
                end
            end
            'b1:begin 
                line_buff1[pixel_xpos] <= gray;                   
                line_buff0[pixel_xpos] <= line_buff0[pixel_xpos]; 
                p2 <= gray;
                p1 <= p2;
                p0 <= p1;
                if(pixel_xpos > 'd2 && pixel_ypos >'d2)  begin 
                    if((p0+2*p1+p2)>(line_buff1[pixel_xpos-2]+2*line_buff1[pixel_xpos-1]+line_buff1[pixel_xpos])) begin
                        conv_out <= (p0+2*p1+p2)-(line_buff1[pixel_xpos-2]+2*line_buff1[pixel_xpos-1]+line_buff1[pixel_xpos]);
                    end
                    else begin 
                        conv_out <= (line_buff1[pixel_xpos-2]+2*line_buff1[pixel_xpos-1]+line_buff1[pixel_xpos])-(p0+2*p1+p2);
                    end        
                end
            end
            default:begin  
                line_buff0[pixel_xpos] <= line_buff0[pixel_xpos];
                line_buff1[pixel_xpos] <= line_buff1[pixel_xpos];
                conv_out <= conv_out;
            end
        endcase
    end
end

2.4 计算结果输出

这一块非常简单,不在赘述,代码如下:

always @(*) begin
    if (data_valid) begin
        soble_out <= {conv_out,conv_out,conv_out};
    end 
    else begin
        soble_out <= pixel_data;
    end
end

3. 波形仿真

在仿真的过程中,我遇到了各种各样的问题,比如计算后的输出竟然是不定态,我对着波形花费了大量的时间去手动计算,分析问题所在,可惜最后也不知道原因所在,最后我又重新实验,将图片显示的位置放置在左上角后,波形奇迹般的正常了,波形如下:

FPGA-HDMI-图片Sobel滤波显示实验(ZYBO Z7)_第3张图片

图3 仿真结果

4. 板级验证

FPGA-HDMI-图片Sobel滤波显示实验(ZYBO Z7)_第4张图片
在这里插入图片描述
代码工程私聊即可

参考
https://www.bilibili.com/video/BV1vg411T7kn/?spm_id_from=333.999.0.0&vd_source=e3e56f2c8b99f0309ca6937cefb13991

你可能感兴趣的:(FPGA,#,Verilog学习,fpga开发,matlab,开发语言)