彩色MT9V034攝像頭 Bayer轉rgb FPGA實現


1 圖像bayer格式介紹

  bayer格式是伊士曼·柯達公司科學家Bryce Bayer發明的,Bryce Bayer所發明的拜耳陣列被廣泛運用數字圖像。Bayer格式是相機內部的原始數據, 一般后綴名為.raw。

  對於彩色圖像,一般是三原色數據,rgb格式。但是攝像頭一個像素點只有rgb中一種數據(下圖為bayer色彩濾波陣列)。但是有很多攝像頭直接輸出rgb和yuv格式,如ov5640、ov7725等等,這是因為在Sensor模組的內部會有一個ISP模塊,會將 Sensor采集到的數據進行插值和特效處理,所以直接輸出彩色圖像。但不是所有的攝像頭都集成ISP,而直接輸出Bayer數據,這就需要自己寫Bayer轉rgb算法。

2 MT9V034簡單介紹

   做圖像處理的朋友都知道,MT9V034是一款十分出色的做機器視覺的攝像頭,一般都是灰度的。但是也有彩色款,當時我覺得灰度的效果那么好,一時頭熱就買一個彩色款的。mt9v034用起來很方便,可以不用寄存器配置,上電默認752*480分辨率。根據需求也可以iic配置。

  全局快門(相對滾動快門) 拍攝高速物體的效果:

  高動態效果:

3 MT9V034 datasheet 簡單解析

  1)有效圖像 752x480

    最大時鍾為27Mhz

    最大幀率為60fps

    10位的adc(我的是八位的輸出,店家只將高8位引出,有點影響最后圖像的精度)

   2)這是mt9v034Bayer陣列,注意輸出方向,從左到右,從上到下。

 

   3)攝像頭ID號要根據 S_CTRL_ADR1, S_CTRL_ADR0這兩個引腳咋連接的

  4)下圖是攝像頭原理圖,很明顯S_CTRL_ADR1, S_CTRL_ADR0是被拉低了,所以攝像頭ID為0x90.上面說到攝像頭只有高8位被引出,在這里可以證實了。

 

  5)下面是大部分寄存器,mt9v034可配置的寄存器很少。0x00是芯片版本。03、04是攝像頭分辨率

 

  6)datasheet就介紹到這里,更多信息可以自己去閱讀。

 4 Bayer轉rgb算法解析

我是用shift register ip 緩存兩行數據,形成2*2窗口(這是FPGA做圖像算法最常用的方法和ip),不是很會的朋友可以百度搜一搜,有很多博客可以學習,一定要自己仿真一下,搞明白,這有點難理解。

根據窗口移動,不難發現,總結出一條重要的規律:總共只有四種窗口,而且與行和列的奇偶有關。

假設計數器從零開始記數:

第一種{行偶,列偶}

 第二種{行偶,列奇}

 第三種{行奇,列偶}

第四種{行奇,列奇}

 

5 算法實現

首先說明我是用xilinx的zynq fpga,altera的也有類似的ip。我直接說明一下ip 參數修改,其他的怎么添加ip什么的我就不講了,不會的自己百度學習。

  1)這是ip首頁,藍框自定義ip名,修改一下紅框的參數,我們是8位數據,一行數據為640個。clock enable端與sclr端可以根據自己的要求決定勾不勾選。其他默認就行,點擊ok可以了。

 

   2)vivado也提供端口例化模板,如下圖操作就行,

 

  3)源碼

    用兩個shift register ip形成2*2的窗口,代碼就不具體解說了,自己仿真一下結合源碼理解吧。

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2019/02/04 10:29:56
// Design Name: colour MT98V034 bayer2rgb
// Module Name: MT_bayer2rgb
// Project Name: Colour_MT_bayer2rgb
// Target Devices: ZYNQ7020
// Tool Versions: vivado2018.3
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module MT_bayer2rgb(
    //system singal
    input                        s_rst_n            ,
    //cmos simgals
    input                        vsync_i            ,
    input                        hsync_i            ,
    input                        pclk            ,
    input            [7:0]        bayer_data        ,
    //輸出
    output                        vsync_o            ,
    output                        hsync_o            ,
    output            [23:0]        rgb_data        
    );

//========================================================================\
// =========== Define Parameter and Internal signals =========== 
//========================================================================/

reg             [9:0]        col_cnt            ;
reg             [8:0]        row_cnt            ;

reg                         hsync_i_1        ;
reg                         hsync_i_2        ;
reg                         hsync_i_3        ;

reg                         vsync_i_1        ;
reg                         vsync_i_2        ;
reg                         vsync_i_3        ;

wire             [7:0]        line_1            ;
wire             [7:0]        line_2            ;
reg                [2:0]        data_control    ;

reg             [7:0]        line1_1            ;    
reg             [7:0]        line1_2            ;    

reg             [7:0]        line2_1            ;    
reg             [7:0]        line2_2            ;    


reg             [7:0]        rgb_r            ;
reg             [8:0]        rgb_g            ;
reg             [7:0]        rgb_b            ;
//=============================================================================
//****************************     Main Code    *******************************
//=============================================================================

//列計數
always @ (negedge pclk or negedge s_rst_n) begin
    if(s_rst_n == 1'b0)
        col_cnt <= 10'd0;
    else if (hsync_i_3 == 1'b1 && hsync_i_2 == 1'b1)
        col_cnt <= col_cnt + 1'b1;    
    else    
        col_cnt <= 10'd0;
end

always @ (posedge pclk or negedge s_rst_n) begin 
    if(s_rst_n == 1'b0) begin
        hsync_i_1 <= 1'b0;
        hsync_i_2 <= 1'b0;
        hsync_i_3 <= 1'b0;
    end
    else begin
        hsync_i_1 <= hsync_i;
        hsync_i_2 <= hsync_i_1;
        hsync_i_3 <= hsync_i_2;
    end
end


always @ (posedge pclk or negedge s_rst_n) begin 
     if(s_rst_n == 1'b0) begin
        vsync_i_1 <= 1'b0;
        vsync_i_2 <= 1'b0;
        vsync_i_3 <= 1'b0;
    end
    else begin
        vsync_i_1 <= vsync_i;
        vsync_i_2 <= vsync_i_1;
        vsync_i_3 <= vsync_i_2;
    end
end

//行計數
always @ (posedge pclk or negedge s_rst_n) begin
    if(s_rst_n == 1'b0)
        row_cnt <= 9'd0;
    else if(~hsync_i && hsync_i_1)
        row_cnt <= row_cnt + 1'b1;
    else if (~vsync_i && vsync_i_1)
        row_cnt <= 9'd0;     
end


//data_control
always @ (posedge pclk or negedge s_rst_n) begin
    if(s_rst_n == 1'b0)
        data_control <= 3'b100;
    else if (hsync_i_2 == 1'b1 && hsync_i_1 == 1'b1)
        data_control <= {1'b0,row_cnt[0],~col_cnt[0]};
    else
        data_control <= 3'b100;       
end

shift_ram        shift_ram_1 (
  .D             (bayer_data     ),        // input wire [7 : 0] D
  .CLK             (pclk            ),      // input wire CLK
  .CE             (hsync_i         ),       // input wire CE
  .SCLR            (~s_rst_n        ),      // input wire SCLR
  .Q             (line_1            )         // output wire [7 : 0] Q
);

shift_ram        shift_ram_2 (
  .D             (line_1            ),        // input wire [7 : 0] D
  .CLK             (pclk            ),      // input wire CLK
  .CE             (hsync_i         ),       // input wire CE
  .SCLR            (~s_rst_n        ),      // input wire SCLR
  .Q             (line_2            )         // output wire [7 : 0] Q
);


always @ (posedge pclk or negedge s_rst_n) begin
    if(s_rst_n == 1'b0) begin
        line1_1    <= 8'd0;
        line1_2    <= 8'd0;

        line2_1 <= 8'd0;
        line2_2 <= 8'd0;
    end
    else begin
        line1_1    <= line_1;
        line1_2    <= line1_1;

        line2_1    <= line_2;
        line2_2    <= line2_1;
    end    
        
end


always @ (data_control) begin
       case(data_control)
           3'b000 : begin 
               rgb_r = line1_1; 
               rgb_g = line2_1 + line1_2; 
               rgb_b = line2_2;
           end
           3'b001 : begin
               rgb_r = line1_2;
               rgb_g = line1_1 + line2_2; 
               rgb_b = line2_1;
           end
           3'b010 : begin
               rgb_r = line2_1;
               rgb_g = line1_1 + line2_2;
               rgb_b = line1_2;
           end
           3'b011 : begin
               rgb_r = line2_2;
               rgb_g = line2_1 + line1_2;
               rgb_b = line1_1;
           end
           default: begin 
               rgb_r = 8'd0;
               rgb_g = 9'd0;
               rgb_b = 8'd0; 
           end
           endcase
end

assign rgb_data =  {rgb_r,rgb_g[8:1],rgb_b};
assign vsync_o     = vsync_i_3;
assign hsync_o     = hsync_i_3;
endmodule

 

  4)最后欣賞一下效果 ,效果還不錯,繼承了灰度款的優良性能。

 

 

 

最后說明一下,最后分辨率改為640*480,但是發現480指的是0~480,所以行計數器在481清零。我是用的zynq,所以沒進行iic硬件配置,用的是ps端arm的 iic接口做的。如果用默認的分辨率就需要修改一下ip的深度和行計數器的清零的數值就行了。說到仿真,vivado自帶的仿真器還是沒有modelsim好,但是modelsim仿真含有vivado ip的工程時,很麻煩,獨立仿真更不行,ip仿真的源文件不好添加,聯合仿真操作有點繁瑣,這里呢先不講,我下次再另外寫一篇博客總結一下。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM