• 基于FPGA的半透明字幕叠加系统实现


    我之所以做了这个半透明字幕叠加,得谢谢CB哥给我分配的任务。当时,他给了我这样的一条公式:

    1

    其中A为图像源,B为字幕,C为字幕叠加后的图像,a%为透明度。

    CB哥让我在48小时内用FPGA实现,最后我也按时完成任务了。接下来,我将介绍该设计的实现过程。当拿到这个任务后,我就用VC++验证了半透明字幕叠加的效果,如下所示:

    用软件测试了之后,发现效果挺不错的。呵呵,接下来该把它移植到FPGA上了。首先,我们可以从公式中看出它其实进行了浮点数计算,如果在FPGA中也进行浮点数计算,结果你会发现实现起来真的很复杂、很吃力。然而,FPGA对整数的运算却是非常的简单。既然这样,我们何不一开始对把它进行适当的缩放,然后进行整数运算,最后对结果进行缩放以得到预期的数据。为了实现这个目的,我对公式的两边同时乘以256。例如,对于

    6

    公式两边乘以256后为

    7

    最后再将结果8’d256*C向右移8位以得到预期的图像数据C。大概的思路就是这样~~它的代码实现如下:

    /*******************************************************
    Author       :  crazyBird
    Filename     :  lcd_driver.v
    Data         :  2015-3-4
    Description  :  driver of lcd 
    ********************************************************/
    `timescale 1ns/1ps 
    module lcd_driver
    ( 
        //global clock 
        input          clk,         //system clock 
        input          rst_n,       //sync reset 
     
        //lcd interface 
        output         lcd_dclk,    //lcd pixel clock 
        output         lcd_blank,   //lcd blank 
        output         lcd_sync,    //lcd sync 
        output         lcd_hs,      //lcd horizontal sync 
        output         lcd_vs,      //lcd vertical sync 
        output         lcd_en,      //lcd display enable 
        output [23:0]  lcd_rgb,     //lcd display data 
     
        //user interface 
        output         lcd_request, //lcd data request 
        output [10:0]  lcd_xpos,    //lcd horizontal coordinate 
        output [10:0]  lcd_ypos,    //lcd vertical coordinate 
        input  [23:0]  lcd_data,    //lcd data 
        input  [ 7:0]  ret_data
    );     
    `include "lcd_para.v" 
    //------------------------------------------ 
    //h_sync counter & generator 
    reg [10:0] hcnt; 
     
    always @(posedge clk or negedge rst_n) 
    begin 
        if (!rst_n)
            hcnt <= 11'd0; 
        else 
            begin 
            if(hcnt < `H_TOTAL - 1'b1)  
                hcnt <= hcnt + 1'b1; 
            else
                hcnt <= 11'd0; 
            end 
    end 
     
    assign lcd_hs = (hcnt <= `H_SYNC - 1'b1) ? 1'b0 : 1'b1; 
    //------------------------------------------ 
    //v_sync counter & generator 
    reg [10:0] vcnt; 
     
    always@(posedge clk or negedge rst_n) 
    begin 
        if (!rst_n)
            vcnt <= 11'b0; 
        else if(hcnt == `H_TOTAL - 1'b1)  
            begin 
            if(vcnt < `V_TOTAL - 1'b1)  
                vcnt <= vcnt + 1'b1; 
            else
                vcnt <= 11'd0; 
            end 
    end 
     
    assign lcd_vs = (vcnt <= `V_SYNC - 1'b1) ? 1'b0 : 1'b1; 
    //------------------------------------------ 
    assign lcd_dclk  = ~clk; 
    assign lcd_blank = lcd_hs & lcd_vs; 
    assign lcd_sync  = 1'b0; 
    //------------------------------------------ 
    //ahead x clock 
    localparam H_AHEAD = 11'd1; 
    localparam ROM_ADDR_AHEAD = 11'd2; 
    assign lcd_request = (hcnt >= (`H_SYNC + `H_BACK - H_AHEAD)           &&
                          hcnt < (`H_SYNC + `H_BACK + `H_DISP - H_AHEAD)) &&
                         (vcnt >= (`V_SYNC + `V_BACK)                     &&
                          vcnt <  (`V_SYNC + `V_BACK + `V_DISP)) ? 1'b1 : 1'b0; 
    //lcd xpos & ypos 
    assign lcd_xpos = lcd_request ? (hcnt - (`H_SYNC+`H_BACK-H_AHEAD)) : 11'd0; 
    assign lcd_ypos = lcd_request ? (vcnt - (`V_SYNC + `V_BACK)) : 11'd0; 
    wire [10:0] rom_xpos = lcd_request ? (hcnt - (`H_SYNC + `H_BACK - ROM_ADDR_AHEAD)) : 11'd0; 
    wire [10:0] rom_ypos = lcd_request ? (vcnt - (`V_SYNC + `V_BACK)) : 11'd0; 
    //-------------------------------------------------------- 
    wire [ 2:0] word_data; 
    wire area1 = (rom_ypos < 11'd160); 
    wire [16:0] rom_addr = area1?{6'b0,rom_xpos}+({6'b0,rom_ypos})*10'd640: 17'd0; 
    
    word u_word
    (
        .address(rom_addr ),
        .clock  (clk      ),
        .q      (word_data)
    ); 
     
    reg [15:0]  lcd_data_r = 16'b0; 
    reg [15:0]  lcd_data_g = 16'b0; 
    reg [15:0]  lcd_data_b = 16'b0; 
     
    always @(*) 
    begin 
        if(word_data == 3'b111)  
            begin
            lcd_data_r = {lcd_data[23:16],8'b0}; 
            lcd_data_g = {lcd_data[15: 8],8'b0}; 
            lcd_data_b = {lcd_data[ 7: 0],8'b0}; 
            end 
        else 
            begin
            lcd_data_r = lcd_data[23:16] * ret_data + {8{word_data[2]}} *  
                        (8'd255 - ret_data); 
            lcd_data_g = lcd_data[15: 8] * ret_data + {8{word_data[1]}} * 
                        (8'd255 - ret_data); 
            lcd_data_b = lcd_data[ 7: 0] * ret_data + {8{word_data[0]}} * 
                        (8'd255 - ret_data); 
            end 
    end 
    //----------------------------------------- 
    assign lcd_en = (hcnt >= (`H_SYNC + `H_BACK)            &&
                     hcnt <  (`H_SYNC + `H_BACK + `H_DISP)) &&
                    (vcnt >= (`V_SYNC + `V_BACK)            &&
                    vcnt <  (`V_SYNC + `V_BACK + `V_DISP)) ? 1'b1 : 1'b0; 
    assign lcd_rgb = lcd_en ? {lcd_data_r[15:8],lcd_data_g[15:8],lcd_data_b[15:8]} : 24'h0;  
     
    endmodule

    上述代码中的ret_data是来自外部模块的,它的值由按键控制,即透明度可调。

    FPGA测试结果如下:

    先写到这吧,更详细地以后再补充~~~又是该睡觉的时候了,晚安,88*^_^*

  • 相关阅读:
    史上最大型广告欺诈活动Methbot:黑客是如何每天赚到500万美元的
    Google研究人员宣布完成全球首例SHA-1哈希碰撞!
    “无文件”恶意软件的威力:悄无声息一夜之间从ATM机中窃取80万美元
    怎样才能写出高质量的伪原创,并且排名在前?
    新手站长如何快速学习实践SEO?
    .net core 开发注意事项
    写cookies注意事项
    .net core Ocelot 开源的API网关学习
    .net core与asp.net读取网站根目录文件的区别
    asp.net 中webapi读取参数对象和.net core的区别
  • 原文地址:https://www.cnblogs.com/CrazyBirdLin/p/4317067.html
Copyright © 2020-2023  润新知