zoukankan      html  css  js  c++  java
  • FPGA实现钢笔画和浮雕效果

      经过前面的知识,我们知道了一个 8 bit 的灰度数据数值是 0~255,代表着从黑到白。而二值图像则是灰度图的特殊化,那我们开动脑筋想一想,是否可以设置一下阈值来制造二值图像,使之能呈现一些特殊的效果呢?

      答案是可以的,那本章博客就来整理一下FPGA实现钢笔画和浮雕画的实现。

    一、钢笔画

      钢笔画的实现比较简单,核心思想就是设置一个阈值,灰度图和阈值进行对比,从而输出全1或全0的图像。

    1、MATLAB实现

     1 %--------------------------------------------------------------------------
     2 %                         钢笔画
     3 %--------------------------------------------------------------------------
     4 clc;
     5 clear all;
     6 RGB = imread('Lenna.jpg'); %读取图像
     7 gray = rgb2gray(RGB);      %灰度图
     8 
     9 [ROW,COL,N] = size(gray);  %获得图像尺寸[高度,长度,维度]
    10 pen = zeros(ROW,COL);
    11 value = 80;
    12 
    13 for i = 1:ROW
    14     for j = 1:COL
    15         pen(i,j) = gray(i,j);
    16         if gray(i,j) > value
    17             pen(i,j) = 255;
    18         else
    19             pen(i,j) = 0;
    20         end
    21     end
    22 end
    23 
    24 subplot(2,1,1);imshow(gray);  title('灰度图');
    25 subplot(2,1,2);imshow(pen);title('钢笔画');

      这里我的阈值 value 设置为100,它的范围是 0-255,点击运行,我们得到如下结果:

      结果还是不错的,得到了钢笔画的效果,唉如果自己用笔能画得这么好看就好了 ^_^

    2、FPGA实现

      这个算法比较简单,Verilog写起来也是一气呵成,之前我们实现了 RGB565 转 YCbCr444,Y 分量代表灰度数据,把它提取出来做阈值比较处理即可,关键代码如下所示:

    assign pen_de    = Y_de;
    assign pen_hsync = Y_hsync;
    assign pen_vsync = Y_vsync;
    assign pen_data  = (Y_data > value) ? 16'hffff : 16'h0000; 

      为了方便查看不同阈值带来的效果,阈值 value 由外部引入,从两个按键获得,按键key[0]增加阈值,按键[1]减小阈值。按键获得阈值的代码如下所示:

     1 //**************************************************************************
     2 // *** 名称 : key_value.v
     3 // *** 作者 : xianyu_FPGA
     4 // *** 博客 : https://www.cnblogs.com/xianyufpga/
     5 // *** 日期 : 2019-08-10
     6 // *** 描述 : 按键获得阈值
     7 //**************************************************************************
     8 
     9 module key_value
    10 //========================< 端口 >==========================================
    11 (
    12 input   wire                clk                     ,
    13 input   wire                rst_n                   ,
    14 input   wire    [ 1:0]      key_vld                 ,
    15 output  reg     [ 7:0]      value                  
    16 );
    17 //==========================================================================
    18 //==    代码
    19 //==========================================================================
    20 always @(posedge clk or negedge rst_n) begin
    21     if(!rst_n) begin
    22         value <= 8'd0;
    23     end
    24     else if(key_vld[0]) begin
    25         value <= value + 8'd10;
    26     end
    27     else if(key_vld[1]) begin
    28         value <= value - 8'd10;
    29     end
    30     else if(value<10) begin         //255不是10的倍数,跳过1-10数值
    31         value <= 8'd0;
    32     end
    33     else if(value>245) begin        //跳过251-255数值
    34         value <= 8'd250;
    35     end
    36 end
    37 
    38 
    39 
    40 endmodule

      阈值的增减幅度设置为 10,阈值的范围是 0~255,但 255 不是10的整数倍,所以阈值为0又按下减阈值按键时,会出现246,236等数值,不好看,所以我设计时将阈值改为0-250。

      此外,这个阈值除了提供给图像处理外,我还传给了数码管模块,这样就能直接看到当前的阈值了。

    3、上板验证

      当阈值为80时,我们得到如下的图像:

      和MATLAB进行对比,除了因板卡坏了导致颜色失真外,效果是一样的,此次实验成功。

      完整实验的视频如下所示:(板子有问题,黑色显示成了红色)

      实现了钢笔画后,我们可以通过同样的方式,改变输出的灰度值来实现铅笔画,此外还有其他更特别的效果也可以采用多个阈值对不同颜色做输出处理。 

    二、浮雕效果

      浮雕是雕刻的一种,雕刻者在一块平板上将他要塑造的形象雕刻出来,使它脱离原来材料的平面。浮雕是雕塑与绘画结合的产物,用压缩的办法来处理对象,靠透视等因素来表现三维空间,并只供一面或两面观看。浮雕一般是附属在另一平面上的,因此在建筑上使用更多,用具器物上也经常可以看到。由于其压缩的特性,所占空间较小,所以适用于多种环境的装饰。近年来,它在城市美化环境中占了越来越重要的地位。浮雕在内容、形式和材质上与原调一样丰富多彩。浮雕的材料有石头、木头、象牙和金属等。

      本次设计同样是基于 YCbCr 的灰度数据Y分量来进行的,浮雕效果的算法公式为:NewPixel(i,j)= Pixel(i,j+1)- Pixel(i,j)+ value,其中 i 为图像高度,j 为图像宽度,pixel为像素点,value为阈值(0-255)。

    1、MATLAB实现

     1 %--------------------------------------------------------------------------
     2 %                         浮雕画
     3 %--------------------------------------------------------------------------
     4 clc;
     5 clear all;
     6 RGB = imread('sun.jpg');   %读取图像
     7 gray = rgb2gray(RGB);      %灰度图
     8 
     9 [ROW,COL,N] = size(gray);  %获得图像尺寸[高度,长度,维度]
    10 emboss = zeros(ROW,COL);
    11 value = 100;
    12 
    13 for i = 1:ROW
    14     for j=1:COL-1
    15         emboss(i,j) = gray(i,j+1) - gray(i,j) + value;
    16         if emboss(i,j) > 255
    17              emboss(i,j) = 255;
    18         elseif emboss(i,j) < 0
    19             emboss(i,j) = 0;
    20         else
    21             emboss(i,j) = emboss(i,j);
    22         end
    23     end
    24 end
    25 emboss = uint8(emboss);
    26 
    27 subplot(2,1,1);imshow(gray);  title('灰度图');
    28 subplot(2,1,2);imshow(emboss);title('浮雕画');

      原图如下所示:

      阈值范围是 0-255,这里我设置为80,点击运行MATLAB,我们得到如下结果:

      浮雕效果出来了,

    2、FPGA实现

      首先考虑一个问题,如何实现公式 NewPixel(i,j)= Pixel(i,j+1)- Pixel(i,j)+ value ,尤其是 j+1 怎么处理?答案是打拍,通过打拍获得 Y_data_r,它的数据就相当于是 j,而原数据就相当于是 j+1。

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            Y_data_r <= 8'd0;
        end
        else begin
            Y_data_r <= Y_data;
        end
    end
    
    assign emboss = Y_data - Y_data_r + value; //-255 ~ 510

      这里要注意一下 emboss 信号,它可能出现负数,因此我们得从极端情况来设计,极端情况下 Y_data、Y_data_r 和 value 是 0 或255,那 emboss 的值就是 -255~510之间,因此我们可以将emboss信号定义成有符号数:  wire signed [ 9:0] emboss; 。

      处理好这步后,就可以进行浮雕画的处理了,代码如下所示:

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            emboss_data <= 16'h0000;
        end
        else if(emboss > 255) begin
            emboss_data <= 16'hffff;
        end
        else if(emboss < 0) begin
            emboss_data <= 16'h0000;
        end
        else begin
            emboss_data <= {emboss[7:3],emboss[7:2],emboss[7:3]};
        end
    end

      到这里数据方面就设计完成了,但是还没有完,千万千万不要忘了信号同步!行场信号、使能信号如果不同步,最后的图像肯定出问题。信号同步的代码如下所示:

    //==========================================================================
    //==                        信号同步
    //==========================================================================
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            Y_de_r    <= 2'b0;
            Y_hsync_r <= 2'b0;
            Y_vsync_r <= 2'b0;
        end
        else begin  
            Y_de_r    <= {Y_de_r,    Y_de};
            Y_hsync_r <= {Y_hsync_r, Y_hsync};
            Y_vsync_r <= {Y_vsync_r, Y_vsync};
        end
    end
    
    assign emboss_de    = Y_de_r[1];
    assign emboss_hsync = Y_hsync_r[1];
    assign emboss_vsync = Y_vsync_r[1];

    3、上板验证

      和上面一样,我用按键提供value阈值,数码管实时显示当前阈值,当阈值为80时,得到如下结果:

      和 MATLAB 效果是一样的,实验成功。

      完整实验的视频如下所示:(板子有问题,黑色显示成了红色)

    参考资料:[1] OpenS Lee:FPGA开源工作室(公众号)

  • 相关阅读:
    Python3中urllib使用介绍
    python urllib和urllib3包
    Python--urllib3库
    Python基础-变量作用域
    Python 面向对象三(转载)
    Python 面向对象二(转载)
    Python 面向对象一(转载)
    YAML 在Python中的应用
    Redis 命令二
    基于Redis的Bloomfilter去重(转载)
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/12485854.html
Copyright © 2011-2022 走看看