因为在做3*3卷积的时候,图像大小会变小,具体计算公式如下
其中o是输出特征图的大小,i是输入特征图的大小,p是padding的大小,k是卷积核的大小,s是指stride的大小,当k的值是3,p的值是1,s的值也是1,的时候o的值和i的值相等。
为了保持输出图像的大小在经过卷积后和输入的大小一样,我们需要进行padding操作,在这里我采用了复制周围一圈的方式来完成。
采用python完成sobel算法的参考模型
import cv2 as cvimport numpy as npimg = cv.imread(rg:shiyanidc.jpg)img_gray = cv.cvtcolor(img, cv.color_rgb2gray)h, w = img_gray.shapeimg_padding = np.zeros((h + 2, w + 2), np.uint8)img_padding[1:h + 1, 1:w + 1] = img_grayimg_padding[0:1, 1:w + 1] = img_gray[0:1, :]img_padding[h + 1:h + 2, 1:w + 1] = img_gray[h - 1:h, :]img_padding[:, 0:1] = img_padding[:, 1:2]img_padding[:, w + 1:w + 2] = img_padding[:, w:w + 1]th = 200sobel_rf = np.zeros((h, w), np.uint8)for i in range(1, h): for j in range(1, w): gx1 = img_padding[i - 1][j + 1] + 2 * img_padding[i][j + 1] + img_padding[i + 1][j + 1] gx2 = img_padding[i - 1][j - 1] + 2 * img_padding[i][j - 1] + img_padding[i + 1][j - 1] gy1 = img_padding[i - 1][j - 1] + 2 * img_padding[i - 1][j] + img_padding[i - 1][j + 1] gy2 = img_padding[i + 1][j - 1] + 2 * img_padding[i + 1][j] + img_padding[i + 1][j + 1] gx = abs(gx1 - gx2) gy = abs(gy1 - gy2) if gx + gy > th: sobel_rf[i - 1][j - 1] = 255 else: sobel_rf[i - 1][j - 1] = 0cv.imshow(sobel_rf, sobel_rf)cv.imshow(src, img_gray)cv.waitkey()cv.destroyallwindows()
根据算法模型完成hdl:提供spinalhdl源码
import spinal.core._import spinal.lib._class sobel(th: int, imagecolnum: int, imagerownum: int) extends component { val io = new bundle { val datain = slave(imagestream(8, imagecolnum, imagerownum, 1)) val dataout = master(imagestream(8, imagecolnum, imagerownum, 1)) } noioprefix() val genmatrix = new genmatrix(scala.math.pow(2, log2up(imagecolnum)).toint, imagecolnum, imagerownum) genmatrix.io.datain io.datain val genmatrixout = imagestream(8, imagecolnum, imagerownum, 9) genmatrixout := genmatrix.io.dataout val gx1 = regnext(genmatrixout.data(0).asuint +^ (genmatrixout.data(1) ## b1'b0).asuint +^ genmatrixout.data(2).asuint) val gx2 = regnext(genmatrixout.data(6).asuint +^ (genmatrixout.data(7) ## b1'b0).asuint +^ genmatrixout.data(8).asuint) val gx = reg(uint(11 bits)) val gy1 = regnext(genmatrixout.data(6).asuint +^ (genmatrixout.data(3) ## b1'b0).asuint +^ genmatrixout.data(0).asuint) val gy2 = regnext(genmatrixout.data(8).asuint +^ (genmatrixout.data(5) ## b1'b0).asuint +^ genmatrixout.data(2).asuint) val gy = reg(uint(11 bits)) when(gx1 > gx2) { gx := gx1 - gx2 } otherwise { gx := gx2 - gx1 } when(gy1 > gy2) { gy := gy1 - gy2 } otherwise { gy := gy2 - gy1 } val g = regnext(gx + gy) val sobelout = reg(bits(8 bits)) when(g > th) { sobelout := 255 } otherwise { sobelout := 0 } io.dataout.data(0) := sobelout io.dataout.row := delay(genmatrixout.row, 4) io.dataout.col := delay(genmatrixout.col, 4) io.dataout.c.hsync := delay(genmatrixout.c.hsync, 4,init = false) io.dataout.c.vsync := delay(genmatrixout.c.vsync, 4,init = false) io.dataout.c.de := delay(genmatrixout.c.de, 4,init = false)}object sobel extends app { spinalconfig().generateverilog(new sobel(200, 640, 480))}
仿真代码:
import spinal.lib._import spinal.core._import spinal.core.sim._import scala.collection.mutable.queueimport java.io.fileoutputstreamimport scala.io.sourceclass tbsobelc(th: int) extends sobel(th, 430, 430) { var src = array[string]() var destdut = array[string]() var destref = array[string]() // var srclen = 0 var width = array[int]() var high = array[int]() val dutdata = queue[int]() val refdata = queue[int]() var framelen = 0 def init(srcfile: array[string], destdutfile: array[string], destreffile: array[string], imgshape: array[(int, int)]) = { clockdomain.forkstimulus(10) io.datain.data(0) #= 0 io.datain.row #= 0 io.datain.col #= 0 src = srcfile destdut = destdutfile destref = destreffile io.datain.c.de #= false io.datain.c.vsync #= false io.datain.c.hsync #= false framelen = src.length width = imgshape.map(i => i._1) high = imgshape.map(i => i._2) clockdomain.waitsampling(10) } def frame(src: string, width: int, high: int) = { val srcfile = source.fromfile(src) val srcdata = srcfile.getlines() var colcnt = 0 var rowcnt = 0 io.datain.row #= width io.datain.col #= high io.datain.c.de #= false io.datain.c.vsync #= false io.datain.c.hsync #= false clockdomain.waitsampling(20) while (srcdata.hasnext) { val data = srcdata.next() io.datain.data(0) #= data.toint io.datain.c.de #= true if (colcnt == 0 && rowcnt == 0) { io.datain.c.vsync #= true println(xx) } else { io.datain.c.vsync #= false } if (colcnt == width - 1 && rowcnt == high - 1) { clockdomain.waitsampling(1) io.datain.c.de #= false clockdomain.waitsampling(200) } if (colcnt == 0) { io.datain.c.hsync #= true } else { io.datain.c.hsync #= false } if (colcnt == width - 1 && rowcnt != high - 1) { clockdomain.waitsampling(1) io.datain.c.de #= false clockdomain.waitsampling(20) } if (colcnt == width - 1) { colcnt = 0 if (rowcnt == high - 1) { rowcnt = 0 } else { rowcnt = rowcnt + 1 } } else { colcnt = colcnt + 1 } clockdomain.waitsampling() } clockdomain.waitsampling(1000) srcfile.close() } def driver = { val dri = fork { for (i <- 0 until framelen) { println(sframe = ${i}) frame(src(i), width(i), high(i)) } } } def dutout = { val dutoutfile = new fileoutputstream(destdut(0)) val d = fork { while (true) { if (io.dataout.c.de.toboolean) { dutdata.enqueue(io.dataout.data(0).toint) dutoutfile.write((io.dataout.data(0).toint.tostring + ).getbytes()) } clockdomain.waitsampling() } } } def reffun = { val d = fork { while (true) { for (i <- 0 until framelen) { val file = source.fromfile(destref(i)) val srcdata = file.getlines() while (srcdata.hasnext) { clockdomain.waitsampling() val data = srcdata.next().toint refdata.enqueue(data) } } } } } def scoreboard = { val d = fork { var index = 0 while (true) { while (dutdata.nonempty && refdata.nonempty) { clockdomain.waitsampling() val dut = dutdata.dequeue() val ref = refdata.dequeue() // if(dut != ref){ // println(si:${index} dutdata:${dut} refdata:${ref}) // } index = index + 1 assert(scala.math.abs(ref - dut) < 5, sindex:${index}, dutdata:${dut} refdata:${ref}) // if (scala.math.abs(ref - dut) != 0) { // println(sref = ${ref} , dut = ${dut}) // } } clockdomain.waitsampling() } } } def waitsimdone = { val d = fork { var index = 0 while (index dut.init(testfile, dutfile, reffile, imgshape) dut.driver dut.reffun dut.dutout dut.scoreboard dut.waitsimdone }}object tbsobel extends app { val tb = new tbsobel}
经过分析之后,该代码可以跑到238mhz,占用330lut,312ff。
欧盟RoHS指令新增豁免条款六价铬
全球PC市场逐渐回暖苹果Mac销量却出现下滑
博通集成成为2019年首批过会企业
采用神经网络和DSP模块实现锡炉在线实时补偿加热控制系统的设计
如何使用LinkIt One板控制LED指示灯
FPGA图像处理-Sobel边缘检测原理
Power Integrations推出PAR38筒灯驱动器设计方案
这款“养猪机器人”,外形看上去是一台平常的喂料机
半导体产业即将连续3 年创下设备支出新高纪录
全球已有40个国家和地区推出了一项或多项支持3GPP标准的5G服务
松下伺服电机调整电机负载如何设置?
车用半导体市场将年增9%达到320亿美元
高通/联发科/华为海思/紫光展锐四家的芯片专家聚在一起会发生什么?
Hitless Protection Switching w
电容器在电源中损坏的现象
提升无人机航程— 无人机智能电池5C技术知识揭秘
数字信号处理有什么特点和优点
常熟瑞特电器研发中心能耗监测系统的应用
转码技术在视频领域内的应用分析
魏德米勒:以挑战为机遇 深扎中国市场