書(shū)接上文,趁著今天休假,采用SpinalHDL做一個(gè)小的demo,看看在SpinalHDL里如何優(yōu)雅的實(shí)現(xiàn)Sobel邊緣檢測(cè)。
Sobel邊緣檢測(cè)
Sobel邊緣檢測(cè)原理教材網(wǎng)上一大堆,核心為卷積處理。
Sobel卷積因子為:
該算子包含兩組3x3的矩陣,分別為橫向及縱向,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。如果以A代表原始圖像,Gx及Gy分別代表經(jīng)橫向及縱向邊緣檢測(cè)的圖像灰度值,其公式如下:
圖像的每一個(gè)像素的橫向及縱向灰度值通過(guò)以下公式結(jié)合,來(lái)計(jì)算該點(diǎn)灰度的大?。?/p>
通常,為了提高效率使用不開(kāi)平方的近似值:
最后,當(dāng)計(jì)算出來(lái)的值大于某一閾值時(shí)即認(rèn)為為邊緣像素點(diǎn)。
歸結(jié)起來(lái),Sobel邊緣檢測(cè)分為三大步:卷積計(jì)算、灰度計(jì)算、閾值比較處理。結(jié)合上文實(shí)現(xiàn)的bufWindow,在SpinalHDL里實(shí)現(xiàn)Sobel邊緣檢測(cè)也就幾行代碼的事情(如果是寫(xiě)Verilog我還是拒絕的)。
卷積計(jì)算
通過(guò)bufWindow,我們可以得到一個(gè)3x3的矩陣窗口,拿到結(jié)果第一步即是計(jì)算卷積,由于卷積因子是帶符號(hào)的,而在做卷積時(shí)又需要考慮位寬擴(kuò)展的事情,在寫(xiě)Verilog時(shí)還是需要小心的設(shè)計(jì)下的,而在SpinalHDL里,兩行代碼:
val Gx=(windowbuf.io.dataOut.payload(0)(2).expand.asSInt-^windowbuf.io.dataOut.payload(0)(0).expand.asSInt)+| ((windowbuf.io.dataOut.payload(1)(2).expand.asSInt-^windowbuf.io.dataOut.payload(1)(0).expand.asSInt)<<1)+| (windowbuf.io.dataOut.payload(2)(2).expand.asSInt-^windowbuf.io.dataOut.payload(2)(0).expand.asSInt)val Gy=(windowbuf.io.dataOut.payload(0)(0).expand.asSInt-^windowbuf.io.dataOut.payload(2)(0).expand.asSInt)+| ((windowbuf.io.dataOut.payload(0)(1).expand.asSInt-^windowbuf.io.dataOut.payload(2)(1).expand.asSInt)<<1)+| (windowbuf.io.dataOut.payload(0)(2).expand.asSInt-^windowbuf.io.dataOut.payload(2)(2).expand.asSInt)
首先將bufWindow輸出的窗口矩陣值擴(kuò)展一位位寬轉(zhuǎn)換為有符號(hào)值,然后進(jìn)行計(jì)算卷積。計(jì)算卷積運(yùn)用了兩個(gè)運(yùn)算符“-^”,"+|"來(lái)處理加減運(yùn)算時(shí)的位寬處理(可參照SpinalHDL手冊(cè)或本公眾號(hào)的《SpinalHDL—數(shù)據(jù)類(lèi)型:UInt/SIn》)。最終得到Gx、Gy。
灰度計(jì)算
灰度計(jì)算這里采用近似值,通過(guò)取絕對(duì)值的方式進(jìn)行實(shí)現(xiàn),在SpinalHDL里也就一行代碼的事情:
sobelResult.payload:= (sobelConv.payload(0).abs+| sobelConv.payload(1).abs).fixTo(cfg.dataWidth-1 downto 0,RoundType.ROUNDUP)由于在卷積計(jì)算時(shí)有擴(kuò)展位寬,這里計(jì)算最后調(diào)用fixTo進(jìn)行高位飽和處理。最終得到位寬與輸入保持一致(想想你在Veirlog里實(shí)現(xiàn)這一步要做多少事情,少年)。
閾值比較
閾值比較就很簡(jiǎn)單了,比較兩個(gè)值大小取兩個(gè)極端:
when(sobelResult.payload>io.thresholdValue){ io.dataOut.payload:=(default->true) }otherwise{ io.dataOut.payload:=(default->false) }最終實(shí)現(xiàn)Sobel邊緣檢測(cè)代碼如下:
case class sobelProc(cfg:lineBufferCfg) extends Component{ require(cfg.lineNum==3) val io=new Bundle{ val thresholdValue =in UInt(cfg.dataWidth bits) val dataIn=slave Flow(UInt(cfg.dataWidth bits)) val dataOut=master Flow(UInt(cfg.dataWidth bits)) dataOut.valid.setAsReg().init(False) dataOut.payload.setAsReg().init(0) } noIoPrefix() val sobel=new Area{ val windowbuf=bufWindow(cfg) val sobelConv=Reg(Flow(Vec(SInt(),2))) val sobelResult=Reg(Flow(UInt(cfg.dataWidth bits))) sobelConv.valid.init(False) sobelResult.valid.init(False) io.dataIn<>windowbuf.io.dataIn val Gx=(windowbuf.io.dataOut.payload(0)(2).expand.asSInt-^windowbuf.io.dataOut.payload(0)(0).expand.asSInt)+| ((windowbuf.io.dataOut.payload(1)(2).expand.asSInt-^windowbuf.io.dataOut.payload(1)(0).expand.asSInt)<<1)+| (windowbuf.io.dataOut.payload(2)(2).expand.asSInt-^windowbuf.io.dataOut.payload(2)(0).expand.asSInt) val Gy=(windowbuf.io.dataOut.payload(0)(0).expand.asSInt-^windowbuf.io.dataOut.payload(2)(0).expand.asSInt)+| ((windowbuf.io.dataOut.payload(0)(1).expand.asSInt-^windowbuf.io.dataOut.payload(2)(1).expand.asSInt)<<1)+| (windowbuf.io.dataOut.payload(0)(2).expand.asSInt-^windowbuf.io.dataOut.payload(2)(2).expand.asSInt) sobelConv.valid:=windowbuf.io.dataOut.valid sobelConv.payload(0):=Gx sobelConv.payload(1):=Gy sobelResult.valid:=sobelConv.valid sobelResult.payload:= (sobelConv.payload(0).abs+| sobelConv.payload(1).abs).fixTo(cfg.dataWidth-1 downto 0,RoundType.ROUNDUP) io.dataOut.valid:=sobelResult.valid when(sobelResult.payload>io.thresholdValue){ io.dataOut.payload:=(default->true) }otherwise{ io.dataOut.payload:=(default->false)} }}區(qū)區(qū)不到四十行代碼,簡(jiǎn)潔而優(yōu)雅,基本上就是描述算法,出錯(cuò)概率應(yīng)該很小吧!
做圖像處理的小伙伴想想在做仿真驗(yàn)證時(shí)需要怎么搞,matlab生成灰度圖像二進(jìn)制數(shù)據(jù)放在文件里,然后仿真時(shí)再導(dǎo)入,仿真完成后將結(jié)果保存到文件里,最后再在matlab里做對(duì)比。 太麻煩。SpinalHDL提供了仿真支持,而SpinalHDL是基于Scala的,可以完美實(shí)現(xiàn)整個(gè)仿真驗(yàn)證流程:從圖片直接獲取數(shù)據(jù),然后進(jìn)行仿真驗(yàn)證,仿真結(jié)果直接再次生成圖片。
-
Verilog
+關(guān)注
關(guān)注
28文章
1343瀏覽量
109925 -
代碼
+關(guān)注
關(guān)注
30文章
4722瀏覽量
68234 -
sobel
+關(guān)注
關(guān)注
0文章
12瀏覽量
7890
原文標(biāo)題:FPGA圖像處理——老戲新說(shuō)
文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論