【西西学FPGA】Lesson15 sobel

来源:互联网 发布:翼华科技 知乎 编辑:程序博客网 时间:2024/05/03 05:39
------------------------------------遇到的问题:
 数据读出时,一直在向上跑(解决)
 数据读出时,数据在向斜上方跑 (解决) 原因,q输出的参数设置问题
 图像显示阈值的设置在10-15左右(解决)sobel算法的问题
 流水线和数据操作的方法(需要掌握)
 多次写入的时候数据会发生偏移。(未解决)

------------------------------------sobel解释
计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。
------------------------------------灰度图像
我们可以通过下面几种方法,将其转换为灰度:
1.浮点算法:Gray=R*0.3+G*0.59+B*0.11
2.整数方法:Gray=(R*30+G*59+B*11)/100
3.移位方法:Gray =(R*76+G*151+B*28)>>8;
4.平均值法:Gray=(R+G+B)/3;
5.仅取绿色:Gray=G;
通过上述任一种方法求得Gray后,将原来的RGB(R,G,B)中的R,G,B统一用Gray替换,形成新的颜色RGB(Gray,Gray,Gray),用它替换原来的RGB(R,G,B)就是灰度图了。

------------------------------------sobel术语的定义:
(1)边缘:灰度或结构等信息的突变处,边缘是一个区域的结束,也是另一个区域的开始,利用该特征可以分割图像。
(2)边缘点:图像中具有坐标[x,y],且处在强度显著变化的位置上的点。
(3)边缘段:对应于边缘点坐标[x,y]及其方位 ,边缘的方位可能是梯度角。
------------------------------------核心公式
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经纵向及横向边缘检测的图像,其公式如下:
Gx Gy
Gx Gy

图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。
G= (Gx * Gx + Gy * Gy)开平方
用以下公式计算梯度方向。
arctan(Gy/Gx)
如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。

------------------------------------至芯教的方法
1 原始图像像素200*200的图片aaa.jpg 转化成200*200的8位宽的数组a,
2 计算:利用fifo,使数据每三行连续三个(a的高三位,只取R的3bit,扩展为6bit),然后与Gx,Gy做运算分别得到六位的sobel_x(有符号),和六位的sobel_y(有符号),然后将sobel_x和sobel_y的绝对值相加,得到六位的sobel_xy,为198*198 位宽为6位的数组b。
3 计算的条件:第三列传入才能开始做计算,所以本行最后一个数传入做计算以后,要等3个flag才能开始下一行的计算
4 有符号数,正数不变(最高位为0),负数取反加1(最高位为1),
5 边界扫描只有两个输出,就是00或者ff;阈值的设定关系到图片的精细度,5-20左右
6 fifo要注意清零

------------------------------------代码
----------工程架构
        rx_module//(用于接收UART发送的信号,生成数据,送给fifo)
        fifo //将收到的数据,整理,转化成3行数据的输出,并给出有效flag
        compute//对收到的数据进行sobel计算
        ram//8x198x198 用于存储计算完成的sobel_xy,
        vga//
----------信号关系(待整理)
----------------------------------------------------------------------核心代码----------------------------------------
module compute(
        input wire sclk,
        input wire s_rst_n,
        
        input wire [7:0] q_0_i,//from fifo
        input wire [7:0] q_1_i,
        input wire [7:0] q_2_i,
        input wire q_flag_i,
        input wire [7:0] num_cnt,
        input wire [7:0] all_cnt,
        
        output reg [7:0] compute_data_o, //只有两种选择,ff或者00;
        output reg compute_flag_o
        );
        
        reg [7:0] a00;
        reg [7:0] a01;
        reg [7:0] a02;
        //第0行
        reg [7:0] a10;
        reg [7:0] a11;
        reg [7:0] a12;
        //第1行
        reg [7:0] a20;
        reg [7:0] a21;
        reg [7:0] a22;
        //第2行
        
        reg [7:0] compute_cnt;
        reg [5:0] compute_data_x;
        reg [5:0] compute_data_y;
        reg compute_flag;
        reg compute_flag_tmp;
        
        wire [5:0] sobel_xy;
        reg [5:0] sobel_x;
        reg [5:0] sobel_y;
        reg q_flag_i_tmp;
        
        
//输入的flag延迟一个周期
//q_flag_i_tmp
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                q_flag_i_tmp <= 8'd0;
        else
                q_flag_i_tmp <= q_flag_i;
//---------------------------3行3列寄存器-------------------------
//a00
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a00 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a00 <= q_0_i;
//a01
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a01 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a01 <= a00;
//a02
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a02 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a02 <= a01;
//a10
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a10 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a10 <= q_1_i;
//a11
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a11 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a11 <= a10;
//a12
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a12 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a12 <= a11;
//a20
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a20 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a20 <= q_2_i;
//a21
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a21 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a21 <= a20;
//a22
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                a22 <= 8'd0;
        else if(q_flag_i == 1'b1)
                a22 <= a21;
//--------------------------sobel计算实现部分--------------------------
//compute_cnt;
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                compute_cnt <= 8'd0;
        else if ((compute_cnt == 8'd200)&&(compute_flag_o == 1'b1))
                compute_cnt <= 8'd0;
        else if(q_flag_i == 1'b1)
                compute_cnt <= compute_cnt + 1'b1;

//compute_data_x,
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                compute_data_x <= 6'd0;
        else if((compute_flag == 1'b1)&&(compute_cnt >= 8'd3)&&(compute_cnt <= 8'd200 ))
                compute_data_x <= (~{3'b0,a00[7:5]}+1'b1)
                                + a02[7:5]
                                + (~{3'b0,a10[7:5]}+1'b1)*2
                                + a12[7:5]*2
                                + (~{3'b0,a20[7:5]}+1'b1)
                                + a22[7:5];
                
//compute_data_y,
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                compute_data_y <= 6'd0;
        else if((compute_flag == 1'b1)&&(compute_cnt >= 8'd3)&&(compute_cnt <= 8'd200 ))
                compute_data_y <= (~{3'b0,a00[7:5]}+1'b1)
                                + a20[7:5]
                                + (~{3'b0,a01[7:5]}+1'b1)*2
                                + a21[7:5]*2
                                + (~{3'b0,a02[7:5]}+1'b1)
                                + a22[7:5];
                                
//compute_flag; 输入数据同步的flag信号延迟两个周期,用于计算gx和gy
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                compute_flag <= 1'b0;
        else
                compute_flag <= q_flag_i_tmp;

//compute_flag_tmp compute_flag;延迟一个周期,用于计算sobel_xy
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                compute_flag_tmp <= 1'b0;
        else if((compute_flag == 1'b1)&&(compute_cnt >= 8'd3)&&(compute_cnt <= 8'd200 ))
                compute_flag_tmp <= 1'b1;
        else
                compute_flag_tmp <= 1'b0;

//sobel_x
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                sobel_x <= 6'd0;
        else if(compute_flag_tmp == 1'b1)
                if(compute_data_x[5] == 1'b1)
                        sobel_x <= ~compute_data_x+1'b1;
                else if(compute_data_x[5] != 1'b1)
                        sobel_x <= compute_data_x;
                        
//sobel_y
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                sobel_y <= 6'd0;
        else if(compute_flag_tmp == 1'b1)
                if(compute_data_y[5] == 1'b1)
                        sobel_y <= ~compute_data_y+1'b1;
                else if(compute_data_y[5] != 1'b1)
                        sobel_y <= compute_data_y;
//sobel_xy
assign sobel_xy = sobel_x + sobel_y;

//-----------------------------输出端口部分------------------------------
//compute_data_o,
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                compute_data_o <= 8'h0;
        else if((compute_flag_tmp == 1'b1)&&(sobel_xy >= 8'd9))
                compute_data_o <= 8'hff;
        else if((compute_flag_tmp == 1'b1)&&(sobel_xy <= 8'd9))
                compute_data_o <= 8'h00;
                
//compute_flag_o
always@(posedge sclk or negedge s_rst_n)
        if(!s_rst_n)
                compute_flag_o <= 1'b0;
        else if (compute_flag_tmp == 1'b1)
                compute_flag_o <= 1'b1;
        else
                compute_flag_o <= 1'b0;
                
endmodule
0 0
原创粉丝点击