FPGA簡單圖像處理

這個小項目讀取一張bmp格式的圖像文件,做灰度化,二值化或者色彩調整並輸出

工程爲驗證性仿真工程,無需上板,含有不可綜合代碼,也不能上板

首先,需要藉助MATLAB將bmp格式圖像文件轉化爲hex格式

imdata = imread('kodim23.bmp'); % 24-bit BMP image RGB888 

tmp=1:768*512*3;
m = 1;
for i=1:512
    for j=1:768
        for k = 1:3
            tmp(m)=imdata(i,j,k);
            m = m+1;
        end
    end
end

fid = fopen('kodim23.hex', 'wt');
fprintf(fid, '%x\n', tmp);
fclose(fid);

disp('Text file write done');
disp(' ');

Verilog代碼部分包含一個圖像讀取模塊,該模塊有圖像處理的部分,和一個圖像寫模塊,還有一個參數文件用於選擇對圖像進行那種處理

在讀模塊中,定義一個位寬爲8,深度爲數據長度的二維數組用於存儲圖像數據

    reg    [7:0]    total_memory[0:DATA_SIZE-1];

    initial begin
        $readmemh(INFILE, total_memory, 0, DATA_SIZE-1);
    end

然後通過一段不可綜合代碼將其中的R, G, B數據分開存儲

    always @(start) begin
        if(start) begin
            for(i=0;i<DATA_SIZE;i=i+1) begin
                temp_bmp[i] = total_memory[i][7:0];
            end
            for(i=0;i<HEIGHT;i=i+1) begin
                for(j=0;j<WIDTH;j=j+1) begin
                    temp_r[WIDTH*i+j] = temp_bmp[(WIDTH*i+j)*3+0];
                    temp_g[WIDTH*i+j] = temp_bmp[(WIDTH*i+j)*3+1];
                    temp_b[WIDTH*i+j] = temp_bmp[(WIDTH*i+j)*3+2];
                end
            end
        end
    end

參照視頻數據流幀格式,輸出行場同步信號,通過一個狀態機做流程控制,在數據處理時,對圖像進行如下處理

    always @* begin
        if(state_c == S_DATA) begin
            `ifdef BRIGHTNESS_OPERATION
                if(SIGN == 1) begin
                    DATA_R0 = (temp_r[WIDTH*cnt_row+cnt_col]+VALUE>255) ? 255 : temp_r[WIDTH*cnt_row+cnt_col]+VALUE;
                    DATA_R1 = (temp_r[WIDTH*cnt_row+cnt_col+1]+VALUE>255) ? 255 : temp_r[WIDTH*cnt_row+cnt_col+1]+VALUE;
                    DATA_G0 = (temp_g[WIDTH*cnt_row+cnt_col]+VALUE>255) ? 255 : temp_g[WIDTH*cnt_row+cnt_col]+VALUE;
                    DATA_G1 = (temp_g[WIDTH*cnt_row+cnt_col+1]+VALUE>255) ? 255 : temp_g[WIDTH*cnt_row+cnt_col+1]+VALUE;
                    DATA_B0 = (temp_b[WIDTH*cnt_row+cnt_col]+VALUE>255) ? 255 : temp_b[WIDTH*cnt_row+cnt_col]+VALUE;
                    DATA_B1 = (temp_b[WIDTH*cnt_row+cnt_col+1]+VALUE>255) ? 255 : temp_b[WIDTH*cnt_row+cnt_col+1]+VALUE;
                end
                else begin
                    DATA_R0 = (temp_r[WIDTH*cnt_row+cnt_col]-VALUE<0) ? 0 : temp_r[WIDTH*cnt_row+cnt_col]-VALUE;
                    DATA_R1 = (temp_r[WIDTH*cnt_row+cnt_col+1]-VALUE<0) ? 0 : temp_r[WIDTH*cnt_row+cnt_col+1]-VALUE;
                    DATA_G0 = (temp_g[WIDTH*cnt_row+cnt_col]-VALUE<0) ? 0 : temp_g[WIDTH*cnt_row+cnt_col]-VALUE;
                    DATA_G1 = (temp_g[WIDTH*cnt_row+cnt_col+1]-VALUE<0) ? 0 : temp_g[WIDTH*cnt_row+cnt_col+1]-VALUE;
                    DATA_B0 = (temp_b[WIDTH*cnt_row+cnt_col]-VALUE<0) ? 0 : temp_b[WIDTH*cnt_row+cnt_col]-VALUE;
                    DATA_B1 = (temp_b[WIDTH*cnt_row+cnt_col+1]-VALUE<0) ? 0 : temp_b[WIDTH*cnt_row+cnt_col+1]-VALUE;                
                end
            `else
                `ifdef INVERT_OPERATION
                    DATA_R0 = 255-((temp_r[WIDTH*cnt_row+cnt_col]+temp_g[WIDTH*cnt_row+cnt_col]+temp_b[WIDTH*cnt_row+cnt_col])/3);
                    DATA_G0 = 255-((temp_r[WIDTH*cnt_row+cnt_col]+temp_g[WIDTH*cnt_row+cnt_col]+temp_b[WIDTH*cnt_row+cnt_col])/3);
                    DATA_B0 = 255-((temp_r[WIDTH*cnt_row+cnt_col]+temp_g[WIDTH*cnt_row+cnt_col]+temp_b[WIDTH*cnt_row+cnt_col])/3);
                    DATA_R1 = 255-((temp_r[WIDTH*cnt_row+cnt_col+1]+temp_g[WIDTH*cnt_row+cnt_col+1]+temp_b[WIDTH*cnt_row+cnt_col]+1)/3);
                    DATA_G1 = 255-((temp_r[WIDTH*cnt_row+cnt_col+1]+temp_g[WIDTH*cnt_row+cnt_col+1]+temp_b[WIDTH*cnt_row+cnt_col]+1)/3);
                    DATA_B1 = 255-((temp_r[WIDTH*cnt_row+cnt_col+1]+temp_g[WIDTH*cnt_row+cnt_col+1]+temp_b[WIDTH*cnt_row+cnt_col]+1)/3);
                `else
                    `ifdef THRESHOLD_OPERATION
                        DATA_R0 = ((temp_r[WIDTH*cnt_row+cnt_col]+temp_g[WIDTH*cnt_row+cnt_col]+temp_b[WIDTH*cnt_row+cnt_col])/3>THRESHOLD) ? 255 : 0;
                        DATA_G0 = ((temp_r[WIDTH*cnt_row+cnt_col]+temp_g[WIDTH*cnt_row+cnt_col]+temp_b[WIDTH*cnt_row+cnt_col])/3>THRESHOLD) ? 255 : 0;
                        DATA_B0 = ((temp_r[WIDTH*cnt_row+cnt_col]+temp_g[WIDTH*cnt_row+cnt_col]+temp_b[WIDTH*cnt_row+cnt_col])/3>THRESHOLD) ? 255 : 0;
                        DATA_R1 = ((temp_r[WIDTH*cnt_row+cnt_col+1]+temp_g[WIDTH*cnt_row+cnt_col+1]+temp_b[WIDTH*cnt_row+cnt_col+1])/3>THRESHOLD) ? 255 : 0;
                        DATA_G1 = ((temp_r[WIDTH*cnt_row+cnt_col+1]+temp_g[WIDTH*cnt_row+cnt_col+1]+temp_b[WIDTH*cnt_row+cnt_col+1])/3>THRESHOLD) ? 255 : 0;
                        DATA_B1 = ((temp_r[WIDTH*cnt_row+cnt_col+1]+temp_g[WIDTH*cnt_row+cnt_col+1]+temp_b[WIDTH*cnt_row+cnt_col+1])/3>THRESHOLD) ? 255 : 0;
                    `else
                        DATA_R0 = temp_r[WIDTH*cnt_row+cnt_col];
                        DATA_R1 = temp_r[WIDTH*cnt_row+cnt_col+1];
                        DATA_G0 = temp_g[WIDTH*cnt_row+cnt_col];
                        DATA_G1 = temp_g[WIDTH*cnt_row+cnt_col+1];
                        DATA_B0 = temp_b[WIDTH*cnt_row+cnt_col];
                        DATA_B1 = temp_b[WIDTH*cnt_row+cnt_col+1];
                    `endif
                `endif
            `endif
        end
        else begin
            DATA_R0 = 0;
            DATA_R1 = 0;
            DATA_G0 = 0;
            DATA_G1 = 0;
            DATA_B0 = 0;
            DATA_B1 = 0;
        end    
    end

寫模塊將讀模塊輸出的數據寫入到bmp格式文件中,重點需要注意的是

!!!bmp存儲數據是從最後一行開時,依次往上,即以一個數據是圖像左下的的像素的數據,且每個像素的數據是以B, G, R的順序依次存儲

bmp格式頭請參考 http://www.fastgraph.com/help/bmp_header_format.html

原始圖片如下

亮度減弱後的效果如下

 

本項目參考網上一個教程,教程地址https://www.fpga4student.com/2016/11/image-processing-on-fpga-verilog.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章