python+opencv實現(xiàn)機器視覺基礎(chǔ)技術(shù)(邊緣提取,圖像濾波,邊緣檢測算子,投影,車牌字符分割)
擊上方“機器視覺”,點右上角...選擇“置頂/星標”公眾號
接收最新推文!
機器視覺是人工智能正在快速發(fā)展的一個分支。簡單說來,機器視覺就是用機器代替人眼來做測量和判斷。它是一項綜合技術(shù),包括圖像處理、機械工程技術(shù)、控制、電光源照明、光學成像、傳感器、模擬與數(shù)字視頻技術(shù)、計算機軟硬件技術(shù)(圖像增強和分析算法、圖像卡、 I/O卡等)。
下面介紹一些機器視覺的基礎(chǔ)方法,用到的技術(shù)是python+opencv。python是一種很方便的高級編程語言,代碼量少,而OpenCV是一個基于BSD許可發(fā)行的跨平臺計算機視覺庫,可以運行在Linux、Windows、Android和Mac OS操作系統(tǒng)上。它輕量級而且高效——由一系列 C 函數(shù)和少量 C++ 類構(gòu)成,同時提供了Python、Ruby、MATLAB等語言的接口,實現(xiàn)了圖像處理和計算機視覺方面的很多通用算法。
一:邊緣提取
在機器視覺中,一個非?;A(chǔ)的操作就是圖像處理,而在圖像處理中有一個十分重要的知識就是邊緣提取。邊緣提取,指數(shù)字圖像處理中,對于圖片輪廓的一個處理。對于邊界處,灰度值變化比較劇烈的地方,就定義為邊緣。也就是拐點,拐點是指函數(shù)發(fā)生凹凸性變化的點。和高數(shù)的導數(shù)有聯(lián)系,將某個指定的物體的邊緣進行提取出來。而用python+opencv可以很方便地進行邊緣提取操作。
步驟如下:
1.對圖像進行閾值分割并反色
首先需要新建一個python文件,導入cv2的庫(OpenCV2的python庫),并顯示一張圖片,代碼為:
import?cv2
#?讀取本相對路徑下的initial.bmp文件
image?=?cv2.imread?("initial.bmp")??
#?將image對應圖像在圖像窗口顯示出來
cv2.imshow('initial',image)
#?waitKey使窗口保持靜態(tài)直到用戶按下一個鍵
cv2.waitKey(0)
對圖像進行閾值分割,閾值設定為80,得到二值化灰度圖,代碼為:
#?對圖像進行閾值分割,閾值設定為80,得到二值化灰度圖
ret,image1?=?cv2.threshold(image,80,255,cv2.THRESH_BINARY)
cv2.imshow('grayscale',image1)
將圖像進行反色,代碼如下:
image2?=?image1.copy() #?復制圖片
for?i?in?range(0,image1.shape[0]): #image.shape表示圖像的尺寸和通道信息(高,寬,通道)
for?j?in?range(0,image1.shape[1]):
image2[i,j]=?255?-?image1[i,j]
cv2.imshow('colorReverse',image2)
2.邊緣提取
下面就是邊緣提取了,用findContours差影法或者Canny方法檢測邊緣,用原圖像減去腐蝕后的收縮圖像,提取邊緣。代碼如下:
#?邊緣提取
img?=?cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
canny_img_one?=?cv2.Canny(img,300,150)
canny_img_two?=?canny_img_one.copy() #?復制圖片
for?i?in?range(0,canny_img_one.shape[0]): #image.shape表示圖像的尺寸和通道信息(高,寬,通道)
for?j?in?range(0,canny_img_one.shape[1]):
canny_img_two[i,j]=?255?-?canny_img_one[i,j]
cv2.imshow('edge',canny_img_two)最終我們就可以得到一個邊緣提取后的圖形,如下:
二:圖像濾波
圖像濾波,即在盡量保留圖像細節(jié)特征的條件下對目標圖像的噪聲進行抑制,是圖像預處理中不可缺少的操作,其處理效果的好壞將直接影響到后續(xù)圖像處理和分析的有效性和可靠性。
噪聲就是由于成像系統(tǒng)、傳輸介質(zhì)和記錄設備等的不完善,數(shù)字圖像在其形成、傳輸記錄過程中或者在圖像處理的某些環(huán)節(jié)當輸入的像對象并不如預想時受到的污染。
而圖像濾波有很多種濾波方式,本次實驗采用的濾波方式是均值濾波,中值濾波和高斯濾波,以及高斯邊緣檢測。
均值濾波是典型的線性濾波算法,它是指在圖像上對目標像素給一個模板,該模板包括了其周圍的臨近像素(以目標像素為中心的周圍8個像素,構(gòu)成一個濾波模板,即去掉目標像素本身),再用模板中的全體像素的平均值來代替原來像素值。
中值濾波是基于排序統(tǒng)計理論的一種能有效抑制噪聲的非線性信號處理技術(shù),中值濾波的基本原理是把數(shù)字圖像或數(shù)字序列中一點的值用該點的一個鄰域中各點值的中值代替,讓周圍的像素值接近的真實值,從而消除孤立的噪聲點。
高斯濾波是一種線性平滑濾波,適用于消除高斯噪聲,廣泛應用于圖像處理的減噪過程。高斯濾波就是對整幅圖像進行加權(quán)平均的過程,每一個像素點的值,都由其本身和鄰域內(nèi)的其他像素值經(jīng)過加權(quán)平均后得到。
邊緣檢測的目的是標識數(shù)字圖像中亮度變化明顯的點。高斯邊緣檢測是用高斯濾波的方式進行邊緣檢測。
步驟如下:
1.讀取原圖
首先展示原圖,代碼如下:
import?cv2
import?cv2?as?cv
#?讀取本相對路徑下的initial.bmp文件
image?=?cv2.imread?("initial.png")
#?加入文本信息
cv2.putText(image,'initial',(50,50),cv2.FONT_HERSHEY_SIMPLEX,1.5,(255,0,?0),4)
#?將image對應圖像在圖像窗口顯示出來
cv2.imshow('initial',image)
cv2.waitKey(0)
2.均值濾波
然后進行均值濾波,代碼如下:
#?均值濾波
image2?=?cv2.blur(image,(10,5))
cv2.putText(image2,'averageFiltering',(50,50),cv2.FONT_HERSHEY_SIMPLEX,1.5,(255,0,?0),4)
cv2.imshow('averageFiltering',image2)
3.中值濾波
然后進行中值濾波,代碼如下:
image3?=?cv2.medianBlur(image,?5)
cv2.putText(image3,'medianFiltering',(50,50),cv2.FONT_HERSHEY_SIMPLEX,1.5,(255,0,?0),4)
cv2.imshow('medianFiltering',image3)
4.高斯濾波
之后進行高斯濾波,代碼如下:
#?高斯濾波
image4?=?cv2.GaussianBlur(image,(5,5),0)
cv2.putText(image4,'gaussianFilter',(50,50),cv2.FONT_HERSHEY_SIMPLEX,1.5,(255,0,?0),4)
cv2.imshow('gaussianFilter',image4)
5.高斯邊緣檢測
最終進行高斯邊緣檢測,代碼如下:
#?高斯邊緣檢測
gau_matrix?=?np.asarray([[-2/28,-5/28,-2/28],[-5/28,28/28,-5/28],[-2/28,-5/28,-2/28]])
img?=?np.zeros(image.shape)
hight,width?=?image.shape
for?i?in?range(1,hight-1):
for?j?in?range(1,width-1):
img[i-1,j-1]?=?np.sum(image[i-1:i+2,j-1:j+2]*gau_matrix)
image5?=?img.astype(np.uint8)
cv2.putText(image5,'gaussianEdgeDetection',(50,50),cv2.FONT_HERSHEY_SIMPLEX,1.5,(255,0,?0),4)
cv2.imshow('gaussianEdgeDetection',image5)
三:邊緣檢測算子
邊緣檢測是圖像處理和計算機視覺中的基本問題,邊緣檢測的目的是標識數(shù)字圖像中亮度變化明顯的點。包括深度上的不連續(xù)、表面方向不連續(xù)、物質(zhì)屬性變化和場景照明變化等。是計算機視覺的特征提取的一個領(lǐng)域。
在實際的圖像分割中,往往只用到一階和二階導數(shù),雖然原理上,可以用更高階的導數(shù),但是因為噪聲的影響,在純粹二階的導數(shù)操作中就會出現(xiàn)對噪聲的敏感現(xiàn)象,三階以上的導數(shù)信息往往失去了應用價值。二階導數(shù)還可以說明灰度突變的類型。在某些情況下,如灰度變化均勻的圖像,只利用一階導數(shù)可能找不到邊界,此時二階導數(shù)就能提供很有用的信息。二階導數(shù)對噪聲也比較敏感,解決的方法是先對圖像進行平滑濾波,消除部分噪聲,再進行邊緣檢測。不過,利用二階導數(shù)信息的算法是基于過零檢測的,因此得到的邊緣點數(shù)比較少,有利于后繼的處理和識別工作。
計算機視覺正是模仿人類視覺的這個過程。因此在檢測物體邊緣時,先對其輪廓點進行粗略檢測,然后通過鏈接規(guī)則把原來檢測到的輪廓點連接起來,同時也檢測和連接遺漏的邊界點及去除虛假的邊界點。圖像的邊緣是圖像的重要特征,是計算機視覺、模式識別等的基礎(chǔ),因此邊緣檢測是圖象處理中一個重要的環(huán)節(jié)。
而在opencv中也有幾個邊緣檢測方法,一階的有Roberts Cross算子,Prewitt算子,Sobel算子,Canny算子,Krisch算子,羅盤算子;而二階的還有Marr-Hildreth,在梯度方向的二階導數(shù)過零點。
步驟如下:
1.顯示原圖
首先用下面的代碼表現(xiàn)出原圖像:
#?讀取本相對路徑下的dip_switch_02.bmp文件
src_s?=?cv2.imread?("dip_switch_02.bmp",0)
cv2.imshow('src_s',src_s)
2.對圖像進行反色
對圖像進行反色,反色是與原色疊加可以變?yōu)榘咨念伾?,可以用白色(RGB:255,255,255)減去原來圖片的顏色,因此對于黑白圖片,我們先加載一個8位灰度圖像,每一個像素對應的灰度值從0-255,則只需要讀取每個像素的灰度值A(chǔ),再將255-A寫入,這樣操作一遍后,圖像就會反色了。代碼如下:
src?=?cv.imread("dip_switch_02.bmp")
height,?width,?channels?=?src.shape
for?row?in?range(height):
????for?list?in?range(width):
????????for?c?in?range(channels):
????????????pv?=?src[row,?list,?c]
????????????src[row,?list,?c]?=?255?-?pv
cv.imshow("AfterDeal",?src)
3.對圖像用sobel方法進行邊緣檢測
Sobel算子是一種用于邊緣檢測的離散微分算子,它結(jié)合了高斯平滑和微分求導。該算子用于計算圖像明暗程度近似值。根據(jù)圖像邊緣旁邊明暗程度把該區(qū)域內(nèi)超過某個數(shù)的特定點記為邊緣。Sobel 算子在Prewitt算子的基礎(chǔ)上增加了權(quán)重的概念,認為相鄰點的距離遠近對當前像素點的影響是不同的,距離越近的像素點對應當前像素的影響越大,從而實現(xiàn)圖像銳化并突出邊緣輪廓。
Sobel算子的邊緣定位更準確,常用于噪聲較多,灰度漸變的圖像
Sobel算子包含兩組3x3的矩陣,分別為橫向及縱向模板,將之與圖像作平面卷積,即可分別得出橫向及縱向的亮度差分近似值。
代碼如下:
#?用sobel方法進行邊緣檢測
x?=?cv2.Sobel(src,cv2.CV_16S,1,0)
y?=?cv2.Sobel(src,cv2.CV_16S,0,1)
absX?=?cv2.convertScaleAbs(x)???#?轉(zhuǎn)回uint8
#?cv2.imshow("absX",?absX)
#?截圖后反轉(zhuǎn)
def?inverse_color(image):
height,?width,?channels?=?image.shape
for?row?in?range(height):
for?list?in?range(width):
for?c?in?range(channels):
pv?=?image[row,?list,?c]
image[row,?list,?c]?=?255?-?pv
cv.imshow("result",?image)
one?=?cv.imread("2.jpg")
inverse_color(one)
4.對圖像用robert方法進行邊緣檢測
Roberts 算子又稱為交叉微分算子,它是基于交叉差分的梯度算法,通過局部差分計算檢測邊緣線條。常用來處理具有陡峭的低噪聲圖像,當圖像邊緣接近于正 45 度或負 45 度時,該算法處理效果更理想。其缺點是對邊緣的定位不太準確,提取的邊緣線條較粗。
#?用robert方法進行邊緣檢測
dst?=?cv2.addWeighted(absX,0.5,absY,0.5,0)
#?cv2.imshow("dst",?dst)
#?截圖后反轉(zhuǎn)
def?inverse_color(image):
height,?width,?channels?=?image.shape
for?row?in?range(height):
for?list?in?range(width):
for?c?in?range(channels):
pv?=?image[row,?list,?c]
image[row,?list,?c]?=?255?-?pv
cv.imshow("result",?image)
three?=?cv.imread?("3.jpg")
inverse_color(three)
四:投影
投影就是就是把一個場景投影到攝像機的像平面上。類型有透視投影,仿射投影,弱透視投影與類透視投影等。
在opencv中,投影主要分為水平投影和垂直投影。水平投影是二維圖像在y軸上的投影;垂直投影是二維圖像在x軸上的投影。
在水平和垂直的方向上進行投影,先將投影的圖像轉(zhuǎn)化為灰度圖,然后進行二值化閾值分割,之后在水平和垂直的方向上進行投影。所用庫為cv2以及matplotlib數(shù)據(jù)分析庫進行操作。
步驟如下:
1.顯示原圖
import?cv2?
import?numpy?as?np?
from?matplotlib?import?pyplot?as?plt?
img=cv2.imread('123.jpg')
2.垂直方向投影
img=cv2.imread('123.jpg')?#讀取圖片,裝換為可運算的數(shù)組
GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)?#將BGR圖轉(zhuǎn)為灰度圖
ret,thresh1=cv2.threshold(GrayImage,130,255,cv2.THRESH_BINARY)#將圖片進行二值化(130,255)之間的點均變?yōu)?55(背景)
(h,w)=thresh1.shape?#返回高和寬
a?=?[0?for?z?in?range(0,?w)]?
#記錄每一列的波峰
for?j?in?range(0,w):?#遍歷一列?
for?i?in?range(0,h):?#遍歷一行
if?thresh1[i,j]==0:?#如果改點為黑點
a[j]+=1?#該列的計數(shù)器加一計數(shù)
thresh1[i,j]=255?#記錄完后將其變?yōu)榘咨?
for?j?in?range(0,w):?#遍歷每一列
for?i?in?range((h-a[j]),h):?#從該列應該變黑的最頂部的點開始向最底部涂黑
thresh1[i,j]=0?#涂黑
plt.imshow(thresh1,cmap=plt.gray())
plt.show()
cv2.imshow('one',thresh1)?
cv2.waitKey(0)
3.水平方向投影
for?j?in?range(0,h):? for?i?in?range(0,w):? if?thresh1[j,i]==0:? a[j]+=1? thresh1[j,i]=255 for?j?in?range(0,h):? for?i?in?range(0,a[j]):? thresh1[j,i]=0? plt.imshow(thresh1,cmap=plt.gray()) plt.show()

五:車牌字符分割
車牌識別系統(tǒng)(Vehicle License Plate Recognition,VLPR) 是計算機視頻圖像識別技術(shù)在車輛牌照識別中的一種應用。
車牌識別技術(shù)要求能夠?qū)⑦\動中的汽車牌照從復雜背景中提取并識別出來,通過車牌提取、圖像預處理、特征提取、車牌字符識別等技術(shù),識別車輛牌號、顏色等信息,目前最新的技術(shù)水平為字母和數(shù)字的識別率可達到99.7%,漢字的識別率可達到99%。
要將車牌進行字符分割,先進行字符識別操作。這里進行的是直接用方框識別并括起來。需要的步驟是首先要讓彩色的車牌圖像轉(zhuǎn)化為灰度圖,再反色,閾值分割,再利用水平和垂直方向的投影依次截取需要的小方框的長和寬,進行識別。用到的技術(shù)是python+opencv其中的cv2庫以及數(shù)據(jù)分析numpy庫。
步驟如下:
1.讀取原圖
import?cv2
import?cv2?as?cv
import?numpy?as?np
image1?=?cv.imread('123456.jpg',1)
cv.imshow('image1',?image1)
2.灰度轉(zhuǎn)換
然后把圖片轉(zhuǎn)化為灰度圖,這里設置讀取圖片用灰度圖片讀取即可。
image2?=?cv.imread('123456.jpg',0)
cv.imshow('image2',?image2)
3.反色
接著將圖像進行反色,記錄寬高和深度,并用255減去灰度圖顏色的寬高。
height,?width,?deep?=?image1.shape
dst?=?np.zeros((height,width,1),?np.uint8)
for?i?in?range(0,?height):
????for?j?in?range(0,?width):
????????grayPixel?=?image2[i,?j]
????????dst[i,?j]?=?255-grayPixel
cv2.imshow('image3',?dst)
4.閾值分割
然后將反色后的圖像進行閾值分割,閾值設為100。
ret,?thresh?=?cv2.threshold(dst,?100,?255,?cv2.THRESH_TOZERO)
cv2.imshow('image4',?thresh)
5.投影
之后在水平和垂直方向上進行投影,畫出投影圖,并記錄投影小黑點的單位起始長度數(shù)組,設定兩個函數(shù),返回之后要用到的每個小分割矩形的特征點坐標值。
#?水平方向投影 def?hProject(binary): ????h,?w?=?binary.shape ????#?水平投影 ????hprojection?=?np.zeros(binary.shape,?dtype=np.uint8) ????#?創(chuàng)建h長度都為0的數(shù)組 ????h_h?=?[0]*h ????for?j?in?range(h): ????????for?i?in?range(w): ????????????if?binary[j,i]?==?0: ????????????????h_h[j]?+=?1 ????#?畫出投影圖 ????for?j?in?range(h): ????????for?i?in?range(h_h[j]): ????????????hprojection[j,i]?=?255 ????return?h_h #?垂直反向投影 def?vProject(binary): ????h,?w?=?binary.shape ????#?垂直投影 ????vprojection?=?np.zeros(binary.shape,?dtype=np.uint8) ????#?創(chuàng)建?w?長度都為0的數(shù)組 ????w_w?=?[0]*w ????for?i?in?range(w): ????????for?j?in?range(h): ????????????if?binary[j,?i?]?==?0: ????????????????w_w[i]?+=?1 ????for?i?in?range(w): ????????for?j?in?range(w_w[i]): ????????????vprojection[j,i]?=?255 ????return?w_w


6.字符識別匹配分割
根據(jù)返回的數(shù)組,確定分割位置,進行字符識別匹配分割。
th?=?thresh
h,w?=?th.shape
h_h?=?hProject(th)
start?=?0
h_start,?h_end?=?[],?[]
position?=?[]
#?根據(jù)水平投影獲取垂直分割
for?i?in?range(len(h_h)):
????if?h_h[i]?>?0?and?start?==?0:
????????h_start.append(i)
????????start?=?1
????if?h_h[i]?==0?and?start?==?1:
????????h_end.append(i)
????????start?=?0
for?i?in?range(len(h_start)):
????cropImg?=?th[h_start[i]:h_end[i],?0:w]
????if?i?==0:
????????pass
????w_w?=?vProject(cropImg)
????wstart?,?wend,?w_start,?w_end?=?0,?0,?0,?0
????for?j?in?range(len(w_w)):
????????if?w_w[j]?>?0?and?wstart?==?0:
????????????w_start?=?j
????????????wstart?=?1
????????????wend?=?0
????????if?w_w[j]?==0?and?wstart?==?1:
????????????w_end?=?j
????????????wstart?=?0
????????????wend?=?1
????????#?當確認了起點和終點之后保存坐標???
????????if?wend?==?1:
????????????position.append([w_start,?h_start[i],?w_end,?h_end[i]])
????????????wend?=?0
#?確定分割位置
for?p?in?position:
????cv2.rectangle(thresh,?(p[0],?p[1]),?(p[2],?p[3]),?(0,?0,?255),?2)
cv2.imshow('image7',?thresh)
cv.waitKey(0)

來源:https://www.cnblogs.com/ITXiaoAng/p/12593782.html



003:120圖勾勒全球AI產(chǎn)業(yè)完整圖譜!
004:Facebook 開源計算機視覺系統(tǒng),從像素水平理解圖像(附論文及代碼)
007:圖像處理與計算機視覺基礎(chǔ),經(jīng)典以及最近發(fā)展
009:從洗衣妹到谷歌首席科學家,她靠孤獨改變了人工智能界!
019:機器人控制系統(tǒng)相關(guān)知識大匯集
020:機器人的工作原理,史上最詳細的解析!
021:光源選型知識點
022:這才是機械手,這才是自動化,你那算什么?
023:攝像機和鏡頭的基礎(chǔ)知識
024:物聯(lián)網(wǎng)產(chǎn)業(yè)鏈全景圖(附另13大電子行業(yè)全景圖,必收藏)
025:日本到底強大到什么地步?讓人窒息!看后一夜未眠
026:德國機械用行動驚艷全世界:無敵是多么寂寞
歡迎轉(zhuǎn)發(fā)、留言、點贊、分享,感謝您的支持!