第三章
計算機視覺三種常用色彩空間:
- 灰度色彩空間
- BGR
- HSV(Hue:色調,Saturation:飽和度,Value:明亮程度)
使用函數cv2.imread(filepath,flags)讀入一圖片
- filepath:要讀入圖片的完整路徑
- flags:讀入圖片的標誌
- cv2.IMREAD_COLOR:默認參數,讀入一副彩色圖片,忽略alpha通道
- cv2.IMREAD_GRAYSCALE:讀入灰度圖片(0)
- cv2.IMREAD_UNCHANGED:讀入完整圖片,包括alpha通道
高通濾波器
- 根據像素與鄰近像素的亮度差值提升該像素的亮度
import cv2
import numpy as np
from scipy import ndimage
kernal_3x3 = np.array( #卷積核(卷積矩陣,奇數行,列)
[[-1,-1,-1],
[-1,8,-1],
[-1,-1,-1]
])
kernal_5x5 = np.array(
[[-1,-1,-1,-1,-1],
[-1,1,2,1,-1],
[-1,2,4,2,-1],
[-1,1,2,1,-1],
[-1,-1,-1,-1,-1]
])
img = cv2.imread("3_1.jpg",0)
k3 = ndimage.convolve( img , kernal_3x3 ) #卷積
k5 = ndimage.convolve( img , kernal_5x5 )
#GaussianBlur:用高斯濾波器(GaussianFilter)對圖像進行平滑處理,將源圖像與指定的高斯內核進行卷積
blurred = cv2.GaussianBlur( img , (11,11) , 0 )
g_hpf = img - blurred
cv2.imshow("3x3",k3)
cv2.imshow("5x5",k5)
cv2.imshow("g_hpf",g_hpf)
cv2.waitKey()
cv2.destroyAllWindows()
低通濾波器
- 在像素與周圍像素的亮度差值小於一個特定值時,平滑該像素的亮度
- 主要用於去噪和模糊化(高斯模糊是最常用的模糊濾波器(平滑濾波器)之一,是一個削弱高頻信號強度的低通濾波器)
邊緣檢測
OpenCV提供的邊緣檢測濾波函數
- Laplacian()
- Sobel()
- Scharr()
這些濾波函數將非邊緣區域轉爲黑色,邊緣區域轉爲白色或者其他飽和的顏色。但容易將噪聲識別爲邊緣,解決方法是在找到邊緣之前對圖像進行模糊處理
OpenCV提供的模糊濾波函數
- blur():簡單的算術平均
- medianBlur():去除數字化的視頻噪聲非常有效,特別是去除彩色圖像的噪聲
- GaussianBlur()
import cv2
import numpy
import utils
def strokeEdges( src , blurKsize = 7 , edgeKsize = 5 ):
if blurKsize >= 3:
blurredSrc = cv2.medianBlur(src,blurKsize)
graySrc = cv2.cvtColor(blurredSrc,cv2.COLOR_BGR2GRAY)
else :
graySrc = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
cv2.Laplacian(graySrc,cv2.CV_8U,graySrc,ksize=edgeKsize)
normalizedInverseAlpha = (1.0 / 255) * ( 255 - graySrc )
channels = cv2.split(src)
for channel in channels:
channel[:] = channel * normalizedInverseAlpha
cv2.merge(channels,dst)
用定製內核做卷積
- 卷積矩陣:奇數行,奇數列的二維矩陣,中心元素對應於感興趣像素,其他元素對應於這個像素周圍鄰近像素,每個元素都有一個整數或浮點數值,就是應用在像素值上的權重。
kernal_3x3 = np.array( #卷積核
[[-1,-1,-1],
[-1,8,-1],
[-1,-1,-1]
])
此3x3卷積矩陣表示感興趣像素權重爲8,鄰近像素權重爲-1。感興趣像素的新像素是當前像素值*9,減去8個鄰近像素值。若感興趣像素與鄰近像素有一點差別,則差別增加,圖像銳化
。
- OpenCV提供了通用的
filter2D()
函數,用戶指定任意核
cv2.filter2D(src,-1,kernal,dst)
第二個參數指明目標圖像每個通道的位深度(cv2.CV_8U表示每個通道爲8位),若爲負值,則表示目標圖像和源圖像位深度相同。- 對於彩色圖像,
filter2D()
對每個通道都用相同的核,若要對每個通道使用不同的核,必須用split()和merge()函數
- 對於彩色圖像,
Canny邊緣檢測
算法過程:
- 高斯濾波器對圖像去噪
- 計算梯度
- 在邊緣使用非最大抑制(NMS)
- 在檢測的邊緣上使用雙閾值去除假陽性
- 分析所有邊緣及其之間的連接
在OpenCV中一行代碼就能實現:cv2.Canny(img,threshold1,threshold2)
threshold2
用於檢測圖像中明顯的邊緣,但一般情況下檢測的效果不會那麼完美,邊緣檢測出來是斷斷續續的。所以這時候用較小的threshold1
用於將這些間斷的邊緣連接起來。- 返回一個
二值圖像
,包含的是檢測出來的邊緣
import cv2
import numpy as np
img = cv2.imread("3_1.jpg",0)
cv2.imwrite("canny.jpg",cv2.Canny(img,200,300))
cv2.imshow("canny",cv2.imread("canny.jpg"))
cv2.waitKey()
cv2.destroyAllWindows()
輪廓檢測
與其相關的操作:檢測圖像視頻幀中物體輪廓
,計算多邊形邊界
,形狀逼近
,計算感興趣區域
下例檢測出正方形輪廓,並用綠色畫出
import cv2
import numpy as np
#黑色空白圖像200*200
img = np.zeros( ( 200 , 200 ) , dtype = np.uint8 )
#中央放置一個白色方塊(np數組在切片上的賦值)
img[50:150, 50:150] = 255
"""
cv2.threshold(src, thresh, maxval, type) → retval, dst
src:表示的是圖片源
thresh:表示的是閾值(起始值)
maxval:表示的是最大值
type:表示的是這裏劃分的時候使用的是什麼類型的算法,常用值爲0(cv2.THRESH_BINARY)
返回 閾值 和 處理後圖像
"""
ret , thresh = cv2.threshold( img , 127 , 255 , 0 ) # 二值化(黑白)操作 , 0 :(cv2.THRESH_BINARY)
"""
findContours():
參數:輸入圖像,層次類型,輪廓逼近方法
"""
# 圖像的輪廓,層次
contours , hierarchy = cv2.findContours( thresh , cv2.RETR_TREE , cv2.CHAIN_APPROX_SIMPLE )
color = cv2.cvtColor( img , cv2.COLOR_GRAY2BGR )
img = cv2.drawContours(color , contours , -1 , (0,255,0) , 2 )
cv2.imshow("contours" , color)
cv2.waitKey()
cv2.destroyAllWindows()
邊界框,最小矩形區域,最小閉圓區域
加載圖像,在源圖像基礎上二值化操作
在灰度圖像上執行所有計算輪廓的操作,在源圖像上利用色彩信息畫這些輪廓
import cv2
import numpy as np
img = cv2.pyrDown(cv2.imread("3_3.png",cv2.IMREAD_UNCHANGED)) #圖像降採樣,對圖像縮小
ret , thresh = cv2.threshold(cv2.cvtColor(img.copy(),cv2.COLOR_BGR2GRAY),127,255,cv2.THRESH_BINARY)
contours , hier = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# find bounding box coordinates
x , y , w , h = cv2.boundingRect(c)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
# find minimum area
rect = cv2.minAreaRect(c)
# calculate coordinates of the minimum area rectangle
box = cv2.boxPoints(rect)
# normalize coordinates to integers
box = np.int0(box)
# draw contours
cv2.drawContours( img , [box] , 0 , (0,0,255) , 3 )
# 第二個參數接收一個保存着輪廓的數組,[box]將box這組點放入數組中
# 第三個參數是要繪製的輪廓數組的索引,-1表示繪製所有輪廓,否則只繪製輪廓數組裏的輪廓
(x,y),radius = cv2.minEnclosingCircle(c)
# cast to integers
center = (int(x),int(y))
radius = int(radius)
# draw the circle
img = cv2.circle( img , center , radius , (0,255,0),2)
cv2.drawContours( img , contours , -1 , (255,0,0) , 1)
cv2.imshow("contours",img)
cv2.waitKey()
凸輪廓與Douglas-Peucker算法
- 凸形狀內任意兩點的連線都在該形狀裏面
cv2.approxPolyDP
計算近似的多邊形框
- 第一個參數爲輪廓
- 第二個參數
epsilon
爲源輪廓與近似多邊形的最大差值(越小與輪廓越接近)- 計算輪廓周長
cv2.arclength(cnt,True)
cnt
爲一個輪廓 epsilon
可取輪廓的1%,如:
epsilon = 0.01 * cv2.arcLength(cnt,True) approx = cv2.approxPolyDP(cnt,epsilon,True)
- 計算輪廓周長
- 第三個參數爲bool標記,表示多邊形是否閉合
直線檢測
import cv2
import numpy as np
img = cv2.imread('3_3.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,120) # Canny處理的單通道二值圖像
minLineLength = 20 # 最小直線長度
maxLineGap = 5 # 最大線段間隙
#需要處理的圖像,線段的幾何表示(1 , np.pi/180 , 閾值),返回numpy.ndarray(N維數組對象,用於存放同類型元素的多維數組)
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
print(type(lines))
for x1 , y1 , x2 , y2 in lines[0]:
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imshow("edges",edges)
cv2.imshow("lines",img)
cv2.waitKey()
cv2.destroyAllWindows()
圓檢測
import cv2
import numpy as np
planets = cv2.imread('3_3.png')
gray = cv2.cvtColor(planets,cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,120,param1=100,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
cv2.circle(planets,(i[0],i[1]),2,(0,255,0),3)
cv2.imshow("planets_circles",planets)
cv2.waitKey()
cv2.destroyAllWindows()