01
圖像處理算子概述
FPGA最大的優(yōu)勢(shì)體現(xiàn)在其低功耗和并行運(yùn)算的特點(diǎn)上,數(shù)字圖像蘊(yùn)含數(shù)據(jù)量大,采用FPGA可以在保證低功率運(yùn)算的情況下,有效提高圖像算法的實(shí)時(shí)性。
圖像處理算子/卷積核是并行運(yùn)算最常采用的手段——圖像處理算子/卷積核對(duì)圖像矩陣自左向右、自上到下循環(huán)線性運(yùn)算,循環(huán)過(guò)程各運(yùn)算相互獨(dú)立,不存在順序依賴。
掌握基于FPGA的圖像處理算子/卷積核實(shí)現(xiàn)方法,對(duì)提升圖像算法實(shí)時(shí)性和神經(jīng)網(wǎng)絡(luò)運(yùn)算具有重要意義。
1.1 圖像處理算子概念
圖像處理算子是對(duì)圖像進(jìn)行處理時(shí)所用到的算子,根據(jù)計(jì)算機(jī)視覺(jué)(Computer Vision)圖像內(nèi)容表示方法不同,可劃分為基于全局特征的圖像內(nèi)容表示方法下的全局特征描述算子和基于局部特征的圖像內(nèi)容表示方法下的局部特征描述算子。盡管根據(jù)圖像不同特征設(shè)計(jì)出不同的圖像算法,但全局特征和局部特征描述算子在本質(zhì)上沒(méi)有明顯差異。
類似于卷積神經(jīng)網(wǎng)絡(luò),當(dāng)算法設(shè)計(jì)采用多級(jí)/層運(yùn)算時(shí),每級(jí)/層采用的圖像處理算子/卷積核的尺寸越小,越利于運(yùn)算深度的擴(kuò)展。因此,本文主要以局部特征描述算子為主進(jìn)行介紹。
圖像處理算子設(shè)計(jì)通常要求具備重復(fù)性、判別性、局部不變性、富含信息、量化描述和精確高效等特性。根據(jù)圖像處理算子的應(yīng)用功能可分為微分算子、基于矩的描述算子、基于濾波器的描述算子和基于分布統(tǒng)計(jì)的描述算子等。因此,圖像處理算子在圖像增強(qiáng)領(lǐng)域使用較為廣泛。
1.2 圖像處理算子功能
圖像處理算子/卷積核設(shè)計(jì)尺寸通常采用奇數(shù):3×3、5×5、7×7...從而通過(guò)中心點(diǎn)(central pixel)確定像素位置信息,便于以中心點(diǎn)為基準(zhǔn)實(shí)現(xiàn)算子滑動(dòng)運(yùn)算。
圖像處理算子/卷積核設(shè)計(jì)尺寸在特定情況下也會(huì)采用偶數(shù):基于分布統(tǒng)計(jì)的描述算子——SIFT描述算子采用4×4×8維描述圖像的尺度不變特征。
由于奇數(shù)尺寸圖像處理算子/卷積核應(yīng)用廣泛,這里以一階微分算子為例簡(jiǎn)要介紹圖像處理算子的工作原理:
對(duì)圖像進(jìn)行上述一階微分運(yùn)算:
相應(yīng)的一階微分算子G滿足:
利用一階微分算子G對(duì)數(shù)字圖像循環(huán)遍歷,得到一階微分處理后的圖像結(jié)果:
微分運(yùn)算常用于研究相鄰像素差異,主要應(yīng)用在圖像邊緣提取操作中,具體原理在微分算子中進(jìn)行具體介紹。
02
圖像處理算子原理
圖像處理算子根據(jù)應(yīng)用功能不同可主要分為微分算子、基于矩的描述算子、基于濾波器的描述算子和基于分布統(tǒng)計(jì)的描述算子四類。本節(jié)以微分算子為例,介紹圖像處理算子的設(shè)計(jì)與原理。
2.1 離散數(shù)據(jù)微分運(yùn)算
微分算子用于對(duì)圖像進(jìn)行微分運(yùn)算,通常用于實(shí)現(xiàn)邊緣檢測(cè)和圖像二值化等功能。對(duì)于連續(xù)函數(shù)的微分運(yùn)算通常定義為:
相應(yīng)地,二元函數(shù)的偏微分運(yùn)算定義為:
數(shù)字圖像像素是一組二維離散數(shù)據(jù),h無(wú)法趨近于無(wú)窮小,因此其導(dǎo)數(shù)采用差分方差的形式近似:
差分方差根據(jù)不同形式可分為:
不同差分形式求解數(shù)據(jù)微分運(yùn)算可能存在一定的誤差,通常根據(jù)不同的應(yīng)用場(chǎng)景靈活選擇差分形式。以一維離散數(shù)據(jù)為例,利用差分方差求解一階微分和二階微分的結(jié)果可表示為:
2.2 微分算子設(shè)計(jì)原理
基于離散數(shù)據(jù)的微分運(yùn)算方程,以3×3算子為例解釋數(shù)字圖像微分算子的設(shè)計(jì)原理。為便于后續(xù)原理解釋,約定對(duì)于以(x,y)為中心像素的3×3數(shù)字圖像區(qū)域,各像素按坐標(biāo)位置進(jìn)行命名:
微分算子對(duì)數(shù)字圖像求微分操作通過(guò)矩陣乘法實(shí)現(xiàn):
因此,根據(jù)不同的差分形式微分方程,可以構(gòu)建不同的圖像微分算子。這里給出三種典型的微分算子設(shè)計(jì):
1. 一階微分算子設(shè)計(jì):
2. 二階微分算子設(shè)計(jì):
3. 拉普拉斯算子設(shè)計(jì):
? ?
2.3 微分算子實(shí)現(xiàn)效果
以拉普拉斯算子為例,對(duì)拍攝的原始圖像利用拉普拉斯算子進(jìn)行微分處理后,得到邊緣提取后的圖像,將提取邊緣與原始圖像相加,可以對(duì)原始圖像完成銳化操作。
03
圖像處理算子實(shí)現(xiàn)
并行運(yùn)算是FPGA圖像處理的主要優(yōu)勢(shì),通過(guò)圖像處理算子的方式對(duì)圖像區(qū)域并行處理,可以有效提高算法運(yùn)行速率,提升系統(tǒng)的實(shí)時(shí)性。
以3×3區(qū)域?yàn)槔?,由于圖像數(shù)據(jù)通常按照從上到下、從左到右的順序逐個(gè)像素點(diǎn)進(jìn)行掃描,所以無(wú)法直接讀取中心像素周圍3×3范圍內(nèi)的所有數(shù)據(jù)。因此,本節(jié)采用FIFO緩存的方式,直接從中心像素提取相鄰3×3區(qū)域內(nèi)的像素值,為后續(xù)圖像處理算法提供基礎(chǔ)模板。
? ?
3.1 圖像處理算子實(shí)現(xiàn)策略
由于數(shù)字圖像數(shù)據(jù)是逐行逐列、逐個(gè)像素讀取,考慮讀取一個(gè)3×3區(qū)域內(nèi)的數(shù)據(jù),需要緩存輔助實(shí)現(xiàn)。因此,利用兩個(gè)FIFO存儲(chǔ)當(dāng)前讀取像素位置前兩行的數(shù)據(jù),如下圖所示。此時(shí),在讀取像素的同時(shí)可以按照坐標(biāo)關(guān)系,從FIFO中讀出3×3區(qū)域內(nèi)的其他所有像素值。需要注意的是,這種方法所讀取到的區(qū)域并非以當(dāng)前讀取像素為中心,而是以I(x-1,y-1)為中心像素的3×3區(qū)域。
讀取過(guò)程中存在的一個(gè)值得關(guān)注問(wèn)題是邊界像素的處理。例如,在掃描第一個(gè)數(shù)據(jù)時(shí),相鄰3×3區(qū)域像素需要包括圖中灰色部分的五個(gè)像素值,而這五個(gè)像素值實(shí)際是不存在的。如果邊界像素處理不好,圖像處理效果可能會(huì)大打折扣:以微分運(yùn)算為例,當(dāng)邊緣像素處理不合適時(shí),圖像周圍可能會(huì)出現(xiàn)明顯邊緣特征,對(duì)實(shí)際邊緣提取操作造成嚴(yán)重影響。
對(duì)于邊緣像素的處理通常根據(jù)應(yīng)用場(chǎng)景的不同,會(huì)采用不同的處理方法以提高算法的性能,最常用的處理方法主要有兩種:
舍棄邊緣像素值,保證算子不會(huì)超出圖像區(qū)域;
擴(kuò)展邊緣(圖中灰色部分)賦初值0或255(8 bit數(shù)據(jù))。
3.2 圖像處理算子Verilog代碼
Verilog編寫(xiě)圖像算子生成代碼cx_operator.v,并導(dǎo)入FIFO Generator IP核用于緩存前兩行的圖像數(shù)據(jù),以sim_tb.v為仿真文件輸出波形驗(yàn)證算子的正確性。
各模塊代碼如下:
1. 算子生成模塊 cx_operator.v:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/04/02
// Design Name: Image_Processing_Operator
// Module Name: cx_operator
// Tool Versions: v1.0
// Description: Generate image processing operator
//
//////////////////////////////////////////////////////////////////////////////////
module cx_operator(
input wireclk,
input wirerst_n,
inputwireen,
inputwire [7:0]data,
output reg [7:0]operator_11,
output reg [7:0]operator_12,
output reg [7:0]operator_13,
output reg [7:0]operator_21,
output reg [7:0]operator_22,
output reg [7:0]operator_23,
output reg [7:0]operator_31,
output reg [7:0]operator_32,
output reg [7:0]operator_33
);
parameter V_ACTIVE = 480;
reg [10:0]h_cnt;
reg [10:0]v_cnt;
reg fifo_1_wr_en;
reg fifo_1_rd_en;
wire [7:0]fifo_1_in;
wire [7:0]fifo_1_out;
reg fifo_2_wr_en;
reg fifo_2_rd_en;
wire [7:0]fifo_2_in;
wire [7:0]fifo_2_out;
// Horizontal pixel count
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
h_cnt <= 11'b0;
else if(en)
begin
if(h_cnt == H_ACTIVE - 1)
h_cnt <= 11'b0;
else
h_cnt <= h_cnt + 1'b1;
end
end
// Vertical pixel count
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
v_cnt <= 11'b0;
else if(h_cnt == H_ACTIVE - 1)
begin
if(v_cnt == V_ACTIVE - 1)
v_cnt <= 11'b0;
else
v_cnt <= v_cnt + 1'b1;
end
end
// Write enable signal of the first FIFO
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
fifo_1_wr_en <= 1'b0;
else if(v_cnt < V_ACTIVE - 1)
fifo_1_wr_en <= en;
else
fifo_1_wr_en <= 1'b0;
end
// Write enable signal of the second FIFO
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
fifo_2_wr_en <= 1'b0;
else if(v_cnt > 0)
fifo_2_wr_en <= en;
else
fifo_2_wr_en <= 1'b0;
end
// Read enable signal of the first FIFO
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
fifo_1_rd_en <= 1'b0;
else if(v_cnt > 0)
fifo_1_rd_en <= en;
else
fifo_1_rd_en <= 1'b0;
end
// Read enable signal of the second FIFO
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
fifo_2_rd_en <= 1'b0;
else if(v_cnt > 1)
fifo_2_rd_en <= en;
else
fifo_2_rd_en <= 1'b0;
end
// FIFO data in
assign fifo_1_in= data;
assign fifo_2_in= fifo_1_out;
// Instance of the first FIFO
cx_fifo inst_row_1(
.clk(clk),
.srst(!rst_n ),
.din (fifo_1_in),
.wr_en(fifo_1_wr_en),
.rd_en(fifo_1_rd_en),
.dout (fifo_1_out),
.full (),
.empty()
);
// Instance of the second FIFO
cx_fifo inst_row_2(
.clk(clk),
.srst(!rst_n ),
.din (fifo_2_in),
.wr_en(fifo_2_wr_en),
.rd_en(fifo_2_rd_en),
.dout (fifo_2_out),
.full (),
.empty()
);
// 3×3 operator generation
always@(negedge clk or negedge rst_n)
begin
if(!rst_n)
begin
operator_11<= 8'd0;
operator_12<= 8'd0;
operator_13<= 8'd0;
operator_21<= 8'd0;
operator_22<= 8'd0;
operator_23<= 8'd0;
operator_31<= 8'd0;
operator_32<= 8'd0;
operator_33<= 8'd0;
end
else
begin
operator_11<= operator_12;
operator_12<= operator_13;
operator_13<= fifo_2_out;
operator_21<= operator_22;
operator_22<= operator_23;
operator_23<= fifo_1_out;
operator_31<= operator_32;
operator_32<= operator_33;
operator_33<= data;
end
end
endmodule
2. 仿真模塊 sim_tb.v:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Cascatrix
// Engineer: Carson
//
// Create Date: 2023/03/02
// Design Name: Image_Histogram_Statistic
// Module Name: sim_tb
// Tool Versions: v1.0
// Description: Image output simulation
//
//////////////////////////////////////////////////////////////////////////////////
module sim_tb(
);
reg clk;
reg rst_n;
reg [31:0] pixel_cnt;
wire hsyn;
wire vsyn;
wire de;
wire [7:0] gray_data;
integer image_txt;
parameter PIXEL_TOTAL = 1920*1080;
//parameter PIXEL_TOTAL = 1680*1050;
//parameter PIXEL_TOTAL = 1280*1024;
//parameter PIXEL_TOTAL = 1280*720;
//parameter PIXEL_TOTAL = 1024*768;
//parameter PIXEL_TOTAL = 800*600;
//parameter PIXEL_TOTAL = 640*480;
cx_top inst_cx_top
(
.clk (clk ),
.en (de ),
.hsyn (hsyn ),
.vsyn (vsyn ),
.gray_data (gray_data )
);
always #1 clk = ~clk;
initial
begin
clk = 1;
rst_n = 0;
#100
rst_n = 1;
end
initial
begin
image_txt = $fopen("D:/FPGA_Document/CX_
Document/CX_Image/03_Image_histogram_statistic
/image_src/image_out.txt");
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
pixel_cnt <= 0;
end
else if(de)
begin
pixel_cnt = pixel_cnt + 1;
$fwrite(image_txt,"%h ",gray_data);
end
end
always@(posedge clk)
begin
if(pixel_cnt == PIXEL_TOTAL && ~vsyn)
begin
$display("CX: image_out.txt is output completed successfully! %t", $realtime, "ps");
$fclose(image_txt);
$stop;
end
end
endmodule
3. FIFO Generator IP配置:
Native Ports配置FIFO位寬為8、深度為2048,使能Reset Pin:
Status Flags可以不做配置:
Data Counts可以不做配置:
3.3 測(cè)試數(shù)據(jù)生成Matlab代碼
為便于算子的仿真測(cè)試,利用Matlab生成尺寸為640×480的測(cè)試數(shù)據(jù)data_640_480.txt,數(shù)據(jù)內(nèi)容以0~160進(jìn)行循環(huán),每行循環(huán)640/160=4次,每列重復(fù)循環(huán)。當(dāng)仿真波形中,算子各行相應(yīng)列數(shù)據(jù)相同時(shí),可以驗(yàn)證算子時(shí)序正確。
Matlab測(cè)試數(shù)據(jù)生成代碼:
%**********************************************************************
% -------------------------------------------------------------------
% Company: Cascatrix
% Engineer: Carson
%
% Create Date: 2023/04/02
% Design Name: data_generate
% Module Name: data_generate
% Tool Versions: v1.0
% Description: Generate loop data for operator
%-------------------------------------------------------------------
%*********************************************************************/
clear;clear all;clc;
% Data size
row = 480;
col = 640;
% Data initialization
data = 0;
% Create .txt file
FileName = ['data_640_480','.txt'];
% Open data file
FileData = fopen(FileName,'w');
% Write data into file
for x = 1:row
for y = 1:col
fprintf(FileData,'%s ',dec2hex(data));
if data < 159
data = data + 1;
else
data = 0;
end
end
end
% Close data file
fclose(FileData);
3.4 仿真結(jié)果分析
仿真波形驗(yàn)證結(jié)果如下:
1. 當(dāng)寫(xiě)入第一行數(shù)據(jù)前,所有算子像素值置0,第一行數(shù)據(jù)直接從operator3_中讀出;
2. 當(dāng)寫(xiě)入第二行數(shù)據(jù)時(shí),第一行數(shù)據(jù)存入FIFO1中,并從operator2_中讀出,第二行數(shù)據(jù)直接從operator3_中讀出;
3. 當(dāng)寫(xiě)入第三行數(shù)據(jù)時(shí),第一行數(shù)據(jù)存入FIFO2中,并從operator1_中讀出,第二行數(shù)據(jù)存入FIFO1中,并從operator2_中讀出,第三行數(shù)據(jù)直接從operator3_中讀出;
4. 按以上方式循環(huán)遍歷數(shù)據(jù),波形算子輸出始終滿足operator1x = operator2x = operator3x,即測(cè)試數(shù)據(jù)逐行對(duì)齊,驗(yàn)證3×3算子生成的時(shí)序無(wú)誤,實(shí)現(xiàn)從一個(gè)像素讀取相鄰像素值的功能。
審核編輯:劉清
-
FPGA
+關(guān)注
關(guān)注
1629文章
21738瀏覽量
603459 -
濾波器
+關(guān)注
關(guān)注
161文章
7817瀏覽量
178148 -
數(shù)字圖像處理
+關(guān)注
關(guān)注
7文章
103瀏覽量
18925 -
計(jì)算機(jī)視覺(jué)
+關(guān)注
關(guān)注
8文章
1698瀏覽量
45994
原文標(biāo)題:FPGA數(shù)字圖像處理基礎(chǔ)(三)——圖像處理算子(Verilog)
文章出處:【微信號(hào):Carlinx FPGA,微信公眾號(hào):Carlinx FPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論