此书极好,值得借鉴学习,并且开源开放。Python在实现过程中,体现出来了非常强的优势,特别是结合Numpy来进行矩阵计算,有很多简化方法。这里将学习过程代码进行增编、添加后进行展示。

  Python目前的缺点应该是缺乏一个像ImageWatch这样的工具,这将影响算法研究;另外Numpy的过度抽象,某种程度上也会造成障碍。



1、寻找指定色彩区域



Python的特色,在于Numpy的使用



import cv2



import numpy  as np



src = cv2.imread( "e:/template/tiantan.jpg")



hsv = cv2.cvtColor(src,cv2.COLOR_BGR2HSV)



lower_blue = np.array([ 100, 43, 46])



upper_blue = np.array([ 124, 255, 255])



mask = cv2.inRange(hsv,lower_blue,upper_blue)



res = cv2.bitwise_and(src,src,mask=mask)



cv2.imshow( "hsv",hsv)



cv2.imshow( "mask",mask)



cv2.imshow( "res",res)



cv2.waitKey( 0)



2、warpperspective 透视变化的python实现




段力辉版本《OpenCV-Python 中文教程》学习_ci


import cv2


import numpy  as np


src = cv2.imread( "e:/template/steel03.jpg")


rows,cols,ch = src.shape


pts1 = np.float32([[ 122, 0],[ 814, 0],[ 22, 540],[ 910, 540]])


pts2 = np.float32([[ 0, 0],[ 960, 0],[ 0, 540],[ 960, 540]])


M = cv2.getPerspectiveTransform(pts1,pts2)


dst = cv2.warpPerspective(src,M,(cols,rows))


cv2.imshow( "src",dst)


cv2.waitKey( 0)


这里操作的核心,是一个np的矩阵。在C++中,使用Vector,可能会造成很多浪费。


3、自适应阈值


import cv2


import numpy  as np


 


obj = cv2.imread( "e:/template/pig.jpg", 0)


ret,th1 = cv2.threshold(obj, 100, 255,cv2.THRESH_BINARY)


th2 = cv2.adaptiveThreshold(obj, 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY, 11, 2)


ret3,th3 = cv2.threshold(obj, 0, 255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)


cv2.imshow( "th3",th3)


print(ret3)


cv2.waitKey()


当参数选择OTSU的时候,能够根据计算,自动算出下限。但是我认为这一点并没有什么特别的用途。


4、模糊处理


obj = cv2.imread( "e:/template/pig.jpg", 0)


blur= cv2.blur(obj,( 3, 3))


gaussBlur=cv2.GaussianBlur(obj,( 3, 3), 0)


median = cv2.medianBlur(obj, 5)


bilate = cv2.bilateralFilter(obj, 0.75, 0.75)


5、形态学变换


obj = cv2.imread( "e:/template/pig.jpg", 0)


opening = cv2.morphologyEx(obj,cv2.MORPH_OPEN,( 7, 7))


cv2.imshow( "obj",obj)


cv2.imshow( "opening",opening)


我喜欢这种写法,这将有长远影响。


6、梯度变化,包括1阶、2阶和混合的。


obj = cv2.imread( "e:/template/pig.jpg", 0)


laplacian = cv2.Laplacian(obj,cv2.CV_64F)


sobelx=cv2.Sobel(obj,cv2.CV_64F, 1, 0,ksize= 5)


sobely=cv2.Sobel(obj,cv2.CV_64F, 0, 1,ksize= 5)



段力辉版本《OpenCV-Python 中文教程》学习_ci_02


7、梯度融合


曾经这段代码很神秘的,但是今日使用Python来写,就非常简单。可以看出,Python用来处理二维矩阵信息是很强的。


# Standard imports


import cv2


import numpy  as np


 


A = cv2.imread( "e:/template/apple.jpg")


B = cv2.imread( "e:/template/orange.jpg")


G = A.copy()


gpA=[G]


for i  in range( 6):


    G = cv2.pyrDown(G)


    gpA.append(G)


G = B.copy()


gpB = [G]


for i  in range( 6):


    G = cv2.pyrDown(G)


    gpB.append(G)


lpA = [gpA[ 5]]


for i  in range( 5, 0,- 1):


    GE = cv2.pyrUp(gpA[i])


    L = cv2.subtract(gpA[i- 1],GE)


    lpA.append(L)


lpB = [gpB[ 5]]


for i  in range( 5, 0,- 1):


    GE = cv2.pyrUp(gpB[i])


    L = cv2.subtract(gpB[i- 1],GE)


    lpB.append(L)


LS = []


for la,lb  in zip(lpA,lpB):


    rows,cols,dpt= la.shape


    print(rows,cols)


    ls = np.hstack((la[:, 0:cols// 2],lb[:,cols// 2:]))  #直接横向排列


    LS.append(ls)


ls_ = LS[ 0]


for i  in range( 1, 6):


    ls_ = cv2.pyrUp(ls_)


    ls_ = cv2.add(ls_,LS[i])


real = np.hstack((A[:,:cols// 2],B[:,cols// 2:]))


cv2.imshow( "ls_",ls_)


cv2.imshow( "real",real)


cv2.waitKey()



段力辉版本《OpenCV-Python 中文教程》学习_Standard_03


8、轮廓寻找


import cv2


import numpy  as np


src = cv2.imread( "e:/template/rectangle.jpg")


gray = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)


ret,thresh = cv2.threshold(gray, 127, 255, 0)


contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)


print(contours)


src = cv2.drawContours(src,contours,- 1,( 0, 255, 0), 3)


cv2.imshow( "src",src)


cv2.waitKey()


这里,使用 cv2.CHAIN_APPROX_NONE 或者不同的参数的话,会获得不同的轮廓结果。这对于我现有的轮廓分析研究,也是有帮助的。


9、轮廓的最小 接圆和最大内切圆


外接圆比较简单


(x,y),radius = cv2.minEnclosingCircle(contours[ 0])


center = (int(x),int(y))


radius = int(radius)


src = cv2.circle(src,center,radius,( 0, 255, 0), 2)



段力辉版本《OpenCV-Python 中文教程》学习_Standard_04

 

注意它这里的表示方法。内切圆则采用特殊方法。


# Get the contours


contours, _ = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)


# Calculate the distances to the contour


raw_dist = np.empty(thresh.shape, dtype=np.float32)


for i  in range(src.shape[ 0]):


     for j  in range(src.shape[ 1]):


        raw_dist[i,j] = cv.pointPolygonTest(contours[ 0], (j,i),  True)


minVal, maxVal, _, maxDistPt = cv.minMaxLoc(raw_dist)


minVal = abs(minVal)


maxVal = abs(maxVal)


# Depicting the  distances graphically


drawing = np.zeros((src.shape[ 0], src.shape[ 1],  3), dtype=np.uint8)


for i  in range(src.shape[ 0]):


     for j  in range(src.shape[ 1]):


         if raw_dist[i,j] <  0:


            drawing[i,j, 0] =  255 - abs(raw_dist[i,j]) *  255 / minVal


         elif raw_dist[i,j] >  0:


            drawing[i,j, 2] =  255 - raw_dist[i,j] *  255 / maxVal


         else:


            drawing[i,j, 0] =  255


            drawing[i,j, 1] =  255


            drawing[i,j, 2] =  255    


cv.circle(drawing,maxDistPt,int(maxVal),( 255, 255, 255))


cv.imshow( 'Source', src)


cv.imshow( 'Distance and inscribed circle', drawing)


cv.waitKey()



段力辉版本《OpenCV-Python 中文教程》学习_Standard_05


最大内接圆则复杂许多。


10、寻找轮廓的极点



段力辉版本《OpenCV-Python 中文教程》学习_Standard_06


contours, _  = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)


cnt = contours[ 0]


leftmost = tuple(cnt[cnt[:,:, 0].argmin()][ 0])


rightmost= tuple(cnt[cnt[:,:, 0].argmax()][ 0])


topmost  = tuple(cnt[cnt[:,:, 1].argmin()][ 0])


bottommost=tuple(cnt[cnt[:,:, 1].argmax()][ 0])


cv2.circle(src,leftmost, 5,( 0, 255, 0))


cv2.circle(src,rightmost, 5,( 0, 255, 255))


cv2.circle(src,topmost, 5,( 255, 255, 0))


cv2.circle(src,bottommost, 5,( 255, 0, 0))


cv2.imshow( "src",src)


这是一种很好的方法,能够直接找出轮廓的各方向边界。


11 模板匹配


src = cv.imread( "e:/template/lena.jpg", 0)


template = cv.imread( "e:/template/lenaface.jpg", 0)


w,h = template.shape


res = cv.matchTemplate(src,template,cv.TM_CCOEFF)


min_val,max_val,min_loc,max_loc = cv.minMaxLoc(res)


cv.rectangle(src,max_loc,(max_loc[ 0]+w,max_loc[ 1]+h),( 0, 0, 255), 2)


cv.imshow( "template",template)


cv.imshow( "src",src)


cv.waitKey()



段力辉版本《OpenCV-Python 中文教程》学习_Python_07


我想体现的是python它的写法有很大不同。


src = cv.imread( "e:/template/coin.jpg")


gray = cv.cvtColor(src,cv.COLOR_BGR2GRAY)


template = cv.imread( "e:/template/coincut.jpg", 0)


w,h = template.shape


res = cv.matchTemplate(gray,template,cv.TM_CCOEFF_NORMED)


threshold = 0.4


loc = np.where(res>=threshold)


print(loc)


for pt  in zip(*loc[:: 1]):


    cv.rectangle(src,pt,(pt[ 0]+w,pt[ 1]+h),( 0, 0, 255), 2)


 


cv.imshow( "template",template)


cv.imshow( "src",src)


cv.waitKey()


结合使用阈值,可以实现多目标匹配。


# Standard imports


import cv2  as cv


import numpy  as np


src = cv.imread( "e:/template/coin.jpg")


gray = cv.cvtColor(src,cv.COLOR_BGR2GRAY)


template = cv.imread( "e:/template/coincut.jpg", 0)


w,h = template.shape


res = cv.matchTemplate(gray,template,cv.TM_CCOEFF_NORMED)


threshold = 0.6


loc = np.where(res>=threshold)


print(loc)


for pt  in zip(*loc[::- 1]): #排序方法为height width


    print(pt)


    cv.rectangle(src,pt,(pt[ 0]+w,pt[ 1]+h),( 0, 0, 255), 2)


 


cv.imshow( "template",template)


cv.imshow( "src",src)


cv.waitKey()


特别需要注意其排序方法。但是这里的阈值选择,也是超参数类型的。



段力辉版本《OpenCV-Python 中文教程》学习_Python_08


12 HoughCircle


src = cv.imread( "e:/template/circle.jpg", 0)


src = cv.medianBlur(src, 5)


cimg = cv.cvtColor(src,cv.COLOR_GRAY2BGR)


circles = cv.HoughCircles(src,cv.HOUGH_GRADIENT, 1, 20,param1= 50,param2= 30,minRadius= 0,maxRadius= 0)


circles = np.uint16(np.around(circles))


for i  in circles[ 0,:]:


    cv.circle(cimg,(i[ 0],i[ 1]),i[ 2],( 0, 255, 0), 2)


    cv.circle(cimg,(i[ 0],i[ 1]), 2,( 0, 0, 255), 3)


cv.imshow( "src",cimg)


cv.waitKey()



段力辉版本《OpenCV-Python 中文教程》学习_Python_09


13 风水岭算法


# Standard imports


import cv2  as cv


import numpy  as np


src = cv.imread( "e:/template/water_coins.jpg")


gray =cv.cvtColor(src,cv.COLOR_BGR2GRAY)


_,thresh = cv.threshold(gray, 0, 255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)


kernel = np.ones(( 3, 3),np.uint8)


opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel,iterations= 2)


sur_bg = cv.dilate(opening,kernel)


dist_transform = cv.distanceTransform(opening, 1, 5)


_,sur_fg=cv.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)


sur_fg = np.uint8(sur_fg)


unknow = cv.subtract(sur_bg,sur_fg)


_,markers1 = cv.connectedComponents(sur_fg)


markers = markers1+ 1


markers[unknow == 255] =  0


markers3 = cv.watershed(src,markers)


src[markers3 == - 1] = [ 255, 0, 0]


cv.imshow( "src",src)


 


cv.waitKey()



段力辉版本《OpenCV-Python 中文教程》学习_ci_10


这个结果,具有参考价值。