1. 程式人生 > 實用技巧 >計算機視覺-計算機視覺基礎

計算機視覺-計算機視覺基礎

計算機視覺-計算機視覺基礎

1、載入、顯示、儲存影象

import argparse
import cv2
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")#讀取指定指令,獲取圖片。引數1:輸入指令的頭字母,引數2:需要輸入的指令
args = vars(ap.parse_args())

image = cv2.imread(args["image"
]) #讀取指定引數的,讀取照片 print "width: %d pixels" % (image.shape[1]) # 獲取影象的寬度,橫向尺寸,影象座標系中,第二個引數 print "height: %d pixels" % (image.shape[0] )#獲取影象的高度,豎向尺寸,影象座標系中,第一個引數 注意:讀取影象x,y互換 print "channels: %d" % (image.shape[2]) cv2.imshow("Image", image)#顯示圖片 cv2.imwrite("
newimage.jpg", image) #將圖片寫入指定路徑 cv2.waitKey(0)#等待程式結束

2、影象基礎

(h, w) = image.shape[:2] #(x,y)畫素中的顯示,獲取圖片的高度(x),獲取圖片的寬度(y)

(b, g, r) = image[0, 0] #獲取指定位置的畫素,儲存方式為bgr

(cX, cY) = (w / 2, h / 2) #cX:圖片的寬度,cY:圖片高度
tl = image[0:cY, 0:cX] #獲取圖片的左上角部分[起始點x座標:終點x座標,起點的y座標:終點y座標],得出的值分別指高度和寬度
 

#運用畫素指定位置賦值方法,向Background圖片上插入圖片resized_left
for left_x in xrange(0, 500, 1):   for left_y in xrange(0, 500, 1):
    Background[
400 + left_x, 20 + left_y] = resized_left[left_x, left_y]

3、繪圖

canvas = np.zeros((300, 300, 3), dtype="uint8") #設定畫布尺寸

green = (0, 255, 0)#設定線條顏色
cv2.line(canvas, (0, 0), (300, 300), green) #引數1:指定畫布,引數2:線條的開始位置,引數3:線條終點位置,引數4:線條顏色
cv2.line(canvas, (300, 0), (0, 300), red, 3) #引數5:線條畫素厚度

cv2.rectangle(canvas, (10, 10), (60, 60), green)#引數1:指定畫布,引數2:矩形起點位置,引數3:矩形對角線點的位置,線條顏色
cv2.rectangle(canvas, (50, 200), (200, 225), red, 5)#引數5:線條寬度,負數表示填充矩形
 
(centerX, centerY) = (canvas.shape[1] / 2, canvas.shape[0] / 2)#設定圓心座標
white = (255, 255, 255)#設定圓的線條顏色
 
cv2.circle(canvas, (centerX, centerY), r, white)#引數1:畫布,引數2:圓心點,引數3:設定圓的半徑,設定畫圓的線條顏色
 
cv2.circle(canvas, tuple(pt), radius, color, -1)#引數4:設定畫圓的線條粗細,如果為負數,表示填充圓
 

4、影象處理

4.1、翻譯

M = np.float32([[1, 0, -50], [0, 1, -90]]) #定義翻譯矩陣 :引數1:[1,0,x]:x表示畫素向左或者向右移動個數,x為負值影象左移,正值為右移定。引數2:[0,1,y]:y表示畫素上下移動,y為負值向上移動,正值向下移動。記憶口訣:前左負右正,後上負下正
shifted = cv2.warpAffine(image, M, (image.shape[1],image.shape[0]))#對矩陣進行翻譯 引數1:翻譯的目標影象,引數2:翻譯的矩陣,引數3:翻譯後圖像大小

#imutils模組的翻譯函式
shifted = imutils.translate(image, 0, 100)#引數1:移動的目標影象,引數2:左右移動的值,引數3:上下移動的值

注:不會改變影象大小。

4.2、旋轉

注:運用翻譯將圖片移到中心位置,四周留出黑色邊框,在運用旋轉(旋轉角度為0),可將圖片放大

(h, w) = image.shape[:2] #獲取影象的高和寬
(cX, cY) = (w / 2, h / 2) #獲取影象的中心點

M = cv2.getRotationMatrix2D((cX, cY), 45, 1.0) #設定旋轉矩陣,引數1:旋轉點 引數2:旋轉角度,正值逆時針旋轉,負值順時針選裝,引數3:旋轉後圖像與原始影象的比例,影象原始大小不會發生變化,類似相機焦距變化
rotated = cv2.warpAffine(image, M, (w, h)) #引數1:目標影象,引數2:旋轉矩陣,引數3#旋轉後的影象尺寸

#imutils模組的旋轉函式
rotated = imutils.rotate(image, 180) #引數1:旋轉目標圖片 引數2:旋轉角度   center=(x,y)可以設定旋轉點

4.3、影象大小調整

注:改變原始圖片的實際大小

r = 150.0 / image.shape[1] #新影象與舊影象的寬比例 注:方便圖片按原比例縮放
dim = (150, int(image.shape[0] * r)) #設定新影象的畫素尺寸
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA) #調整影象大小,返回一個新影象

#運用imutils中的resize函式
resized = imutils.resize(image, width=100) #引數1:目標影象,引數2:設定新影象的寬度,可以為height,運用高度

#運用插值方法縮放大圖片,,通過不同的畫素填充方法放大圖片。
resized = imutils.resize(image, width=image.shape[1] * 3, inter=method)#引數1:目標圖片,引數2:處理後圖片畫素寬(整形),引數3:畫素處理方法
"""method: cv2.INTER_NEAREST:最近鄰內插值
               cv2.INTER_LINEAR:雙線性插值
               cv2.INTER_AREA:區域插值
               cv2.INTER_CUBIC:雙三次插值
               cv2.INTER_LANCZOS4 :雙三次插值     

4.4、影象翻轉

flipped = cv2.flip(image, 1)#水平翻轉
flipped = cv2.flip(image, 0)#上下翻轉
flipped = cv2.flip(image, -1)#水平翻轉後上下翻轉

4.5、影象裁剪

face = image[85:250, 85:220] #引數1:裁切高度 x開始位置:x結束位置,引數2:裁切寬度 y開始位置:y結束位置,返回新圖片

4.6、影象畫素畫素值操作

注:修改圖片的亮度

M = np.ones(image.shape, dtype = "uint8") * 100 #設定與圖片大下相同的矩陣,矩陣填充值為100
added = cv2.add(image, M)#將原始圖片與新矩陣相加,畫素亮度提高100

M = np.ones(image.shape, dtype = "uint8") * 50#設定與圖片大下相同的矩陣,矩陣填充值為50
subtracted = cv2.subtract(image, M)#將原始圖片與新矩陣相減,畫素亮度降低50

4.7、按位操作

注:主要是黑白影象處理

bitwiseAnd = cv2.bitwise_and(rectangle, circle)#當且僅當倆個相同位置的畫素大於0,才返回真
bitwiseOr = cv2.bitwise_or(rectangle, circle)#倆個相同位置的畫素有一個大於0,返回真
bitwiseXor = cv2.bitwise_xor(rectangle, circle)#當且僅當倆個相同位置的畫素只有一個大於0,才返回真
bitwiseNot = cv2.bitwise_not(circle)#畫素值取反

4.8、掩蔽

注:提取影象中感興趣的部分,遮掩的必須用關鍵字mask

mask = np.zeros(image.shape[:2], dtype="uint8") #設定掩蔽畫布的大小
cv2.rectangle(mask, (0, 90), (290, 450), 255, -1)#設定不掩蔽的地方
masked = cv2.bitwise_and(image, image, mask=mask)#圖片顯示的區域

4.9、畫素分割與合併

(B, G, R) = cv2.split(image) #畫素分離影象,B,G,R影象的值為整數,非BGR畫素矩陣組成,其值是如何轉變的?

merged = cv2.merge([B, G, R]) #三個色彩合併,還原為彩色影象,畫素由BGR畫素矩陣組成

zeros = np.zeros(image.shape[:2], dtype = "uint8")#建立一個二值畫布,與各個色彩通道合併,像是各個色彩通道的影響
cv2.imshow("Red", cv2.merge([zeros, zeros, R]))#只有紅色的圖片
cv2.imshow("Green", cv2.merge([zeros, G, zeros]))#只有綠色的圖片
cv2.imshow("Blue", cv2.merge([B, zeros, zeros]))#只有藍色的圖片

問:如何從BGR轉換成整數值

5、核心

6、形態操作

image = cv2.imread(args["image"]) #開啟一張圖片
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)#將圖片轉為二值劃

#侵蝕 將前景物體變小,理解成將影象斷開裂縫變大(在圖片上畫上黑色印記,印記越來越大)
for i in xrange(0, 3):
    eroded = cv2.erode(gray.copy(), None, iterations=i + 1)#引數1:需要侵蝕的影象,引數2:結構元素() 引數3:迭代次數,值越大,侵蝕越嚴重
    cv2.imshow("Eroded {} times".format(i + 1), eroded)
    cv2.waitKey(0)

#擴張 將前景物體變大,理解成將影象斷開裂縫變小(在圖片上畫上黑色印記,印記越來越小)
for i in xrange(0, 3):
    dilated = cv2.dilate(gray.copy(), None, iterations=i + 1)#引數1:需要侵蝕的影象,引數2:結構元素() 引數3:迭代次數,值越大,擴張越大
    cv2.imshow("Dilated {} times".format(i + 1), dilated)
    cv2.waitKey(0)

#開盤 應用侵蝕以去除小斑點,然後應用擴張以重新生成原始物件的大小,用於消除雜質
kernelSizes = [(3, 3), (5, 5), (7, 7)]#定義結構化元素的寬度和高度
 
for kernelSize in kernelSizes:
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernelSize) #引數1:結構化元素的型別 引數2:構造元素的大小
    opening = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel)#引數1:形態學運算的影象 引數2:形態操作的實際  型別 引數3:核心/結構化元素
    cv2.imshow("Opening: ({}, {})".format(kernelSize[0], kernelSize[1]), opening)
    cv2.waitKey(0)

"""形態操作實際型別:
    cv2.MORPH_CLOSE(閉幕):用於封閉物件內的孔或將元件連線在一起
    cv2.MORPH_GRADIENT(形態梯度):用於確定影象的特定物件的輪廓
"""
#頂帽/黑帽 顯示黑色背景上的影象的  明亮區域。適合於灰度影象
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (13, 5))#定義寬度為13 畫素和高度為  5畫素的  矩形 結構元素
blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, rectKernel)#引數1:形態學運算的影象 引數2:形態操作的實際  型別 引數3:核心/結構化元素
 
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) #引數1:形態學運算的影象 引數2:形態操作的實際  型別 引數3:核心/結構化元素

7、平滑和模糊

kernelSizes = [(3, 3), (9, 9), (15, 15)] #定義核心大小引數列表,核心越大,模糊越明顯
 
# loop over the kernel sizes and apply an "average" blur to the image
for (kX, kY) in kernelSizes:
    blurred = cv2.blur(image, (kX, kY))#使用平均模糊方法,引數1:模糊物件,引數2:矩陣大小
    cv2.imshow("Average ({}, {})".format(kX, kY), blurred)
    cv2.waitKey(0)
"""模糊方法:
                平均模糊:過度模糊影象並忽略重要的邊緣
                 blurred =cv2.blur(image, (kX, kY))
                高斯:保留更多的影象邊緣
                 blurred =cv2.GaussianBlur(image, (kX, kY), 0)引數1:模糊物件,引數2:矩陣大小 引數3:標準方差   
                中位數模糊:  影象中去除鹽和胡椒,影象中的雜質點
                blurred = cv2.medianBlur(image, k)引數1:模糊物件,引數2:中位數值,為整型資料,資料越大影象越模糊
                雙邊模糊: 減少噪音同時仍然保持邊緣,我們可以使用雙邊模糊。雙邊模糊通過引入兩個高斯分佈來實現
               blurred =cv2.bilateralFilter(image, diameter, sigmaColor, sigmaSpace)引數1:想要模糊的影象。引數2:畫素鄰域的直徑 - 這個直徑越大,模糊計算中包含的畫素越多。引數3:顏色標準差,模糊時將考慮鄰域中的更多顏色,相似顏色的畫素才能顯
著地影響模糊,引數4:空間標準偏差,更大的值意味著畫素越遠離中心畫素直徑 將影響模糊計算。後面3個引數都為整型引數
"""

8、照明和色彩空間

#RGB 紅、黃、藍組成的顏色矩陣,每個色度值範圍[0,255]
image = cv2.imread(args["image"])
for (name, chan) in zip(("B", "G", "R"), cv2.split(image)):
    cv2.imshow(name, chan)

#HSV 色調(H):們正在研究哪種“純”的顏色。飽和度(S):顏色如何“白,例如純紅,隨著零飽和度的顏色是純白色。價值(V):該值允許我們控制我們的顏色的亮度,零值表示純黑色
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
for (name, chan) in zip(("H", "S", "V"), cv2.split(hsv)):
    cv2.imshow(name, chan)

#L * a * b *表  L通道:畫素的“亮度”。a通道:源於L通道的中心,在頻譜的一端定義純綠色,另一端定義純紅色。b通道:  也來自於L通道的中心,但是垂直於a通道。
lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
for (name, chan) in zip(("L*", "a*", "b*"), cv2.split(lab)):
    cv2.imshow(name, chan)

#灰度:轉換成灰度級時,每個RGB通道  不是 均勻加權
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

9、閥值

閥值:影象的二值化

image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)#將影象二值化
blurred = cv2.GaussianBlur(gray, (7, 7), 0)

(T,threshInv)=cv2.threshold(blurred,200,255,cv2.THRESH_BINARY_INV) #引數1:希望閾值的灰度影象。引數2:手動提供我們的T閾值。引數3:設定輸出值。引數4:閾值方法(白色背景,黑色圖),將畫素值小於引數2的值換成引數3輸出,大於引數2的值,輸出值為0
cv2.imshow("Threshold Binary Inverse", threshInv)


(T, thresh) =cv2.threshold(blurred,200,255,cv2.THRESH_BINARY)#引數1:希望閾值的灰度影象。引數2:手動提供我們的T閾值。引數3:設定輸出值。引數4:閾值方法(黑背景,白色圖),將畫素值大於引數2的值換成引數3輸出,小於引數2的值,輸出值為0。
cv2.imshow("Threshold Binary", thresh)

cv2.imshow("Output", cv2.bitwise_and(image, image, mask=threshInv))

#大津方法 引數1:希望閾值的灰度影象。引數2:大津的方法將自動計算出我們的T的最優值。引數3:閾值的輸出值,只要給定畫素通過閾值測試。引數4:對應於Otsu的閾值法
(T, threshInv) = cv2.threshold(blurred, 0, 255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)

#自適應閥值法:引數1:希望閾值的灰度影象。引數2:引數是輸出閾值。引數3:自適應閾值法。引數4:閾值方法。引數5:是我們的畫素鄰域大小。引數6:微調  我們的閾值
thresh=cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 25, 15)
thresh =threshold_adaptive(blurred,29,offset=5).astype("uint8")* 255
thresh = cv2.bitwise_not(thresh)#閾值適配函式執行自適應閾值

10.1、影象漸變

影象漸變:影象梯度主要應用與邊緣檢測

#Sobel核心
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

gX = cv2.Sobel(gray, ddepth=cv2.CV_64F, dx=1, dy=0) #計算x方向的梯度
gY = cv2.Sobel(gray, ddepth=cv2.CV_64F, dx=0, dy=1) #計算y方向的梯度

gX = cv2.convertScaleAbs(gX) #轉換回8位無符號整型
gY = cv2.convertScaleAbs(gY) #轉換回8位無符號整型

sobelCombined = cv2.addWeighted(gX, 0.5, gY, 0.5, 0) #將倆個影象組合成單個影象


gX = cv2.Sobel(gray, cv2.CV_64F, 1, 0) #計算x梯度方向
gY = cv2.Sobel(gray, cv2.CV_64F, 0, 1) #計算y梯度方向
 
mag = np.sqrt((gX ** 2) + (gY ** 2)) #梯度幅度計算:平方梯度的平方根  X和  ÿ 相加
orientation = np.arctan2(gY, gX) * (180 / np.pi) % 180 #梯度方向計算:兩個梯度的反正切
 
idxs = np.where(orientation >= args["lower_angle"], orientation, -1)#手柄選擇,引數1: 函式是我們要測試的條件,尋找大於最小提供角度的索引。引數2:要檢查的陣列在哪裡。引數3:特定值設定為-1。
idxs = np.where(orientation <= args["upper_angle"], idxs, -1)
mask = np.zeros(gray.shape, dtype="uint8")#構造一個 掩碼 - 所有具有相應idxs   值> -1的座標 都設定為  255  (即前景)。否則,它們保留為  0(即背景)
mask[idxs > -1] = 255

10.2、邊緣檢測

邊緣型別:

  步邊:階躍邊緣形式當存在來自不連續到另一的一側的畫素強度的突然變化

  斜坡邊緣:斜坡邊緣就像一個階躍邊緣,僅在畫素強度的變化不是瞬時的。相反,畫素值的變化發生短而有限的距離

  嶺邊:脊邊緣是相似於兩個結合斜坡邊緣,一個右對另一碰撞

  屋頂邊:頂部有一個短而有限的高原的邊緣不同

邊緣檢測法:

  1. 對影象應用高斯平滑來幫助減少噪點。
  2. 使用Sobel核心計算G_ {X}G_ {Y}影象漸變。
  3. 應用非最大值抑制來僅保持指向梯度方向的梯度幅度畫素的區域性最大值。
  4. 定義和應用T_ {}上T_ {}低閾值滯後閾值
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    
    wide = cv2.Canny(blurred, 10, 200)#引數1:想要檢測邊緣的影象。引數2和3:分別提供閾值下限和閾值上限
    
    #自動調整邊緣檢測引數
    #自動調整邊緣檢測引數函式
    def auto_canny(image, sigma=0.33):
        v = np.median(image)
        lower = int(max(0, (1.0 - sigma) * v))
        upper = int(min(255, (1.0 + sigma) * v))
        edged = cv2.Canny(image, lower, upper)
        return edged
    
    #自動調整邊緣檢測引數函式運用
    blurred = cv2.GaussianBlur(gray, (3, 3), 0)
    auto = imutils.auto_canny(blurred)

11.1、查詢和繪製輪廓

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
(cnts, _) = cv2.findContours(gray.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)#引數1:需要繪製輪廓的影象。引數2:返回的輪廓數量的標誌。引數3:輪廓壓縮型別。返回值:第一個值是輪廓本上。第二個值是要檢查的輪廓層次結構
clone = image.copy()
cv2.drawContours(clone, cnts, -1, (0, 255, 0), 2)#引數1:要繪製輪廓的影象。引數2:使用的輪廓列表。引數3:cnts列表中的輪廓索引,-1表示繪製所有輪廓,0是僅畫第一個,1表示繪製第二個輪廓。引數3:繪製輪廓的顏色。引數4:繪製輪廓線的畫素 

#輪廓單個繪製
for (i, c) in enumerate(cnts):
    print "Drawing contour #{}".format(i + 1)
    cv2.drawContours(clone, [c], -1, (0, 255, 0), 2)
    cv2.imshow("Single Contour", clone)
    cv2.waitKey(0)

#返回所有輪廓外觀:
(cnts, _) = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

#輪廓外觀與掩碼的一起使用
for c in cnts:
    # construct a mask by drawing only the current contour
    mask = np.zeros(gray.shape, dtype="uint8")
    cv2.drawContours(mask, [c], -1, 255, -1)
 
    # show the images
    cv2.imshow("Image", image)
    cv2.imshow("Mask", mask)
    cv2.imshow("Image + Mask", cv2.bitwise_and(image, image, mask=mask))

#補充:運用霍夫找圓心
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#輸出影象大小,方便根據影象大小調節minRadius和maxRadius
print(img.shape)
#霍夫變換圓檢測
circles= cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,1,100,param1=100,param2=30,minRadius=5,maxRadius=300)
#輸出返回值,方便檢視型別
print(circles)
#輸出檢測到圓的個數
print(len(circles[0]))
#根據檢測到圓的資訊,畫出每一個圓
for circle in circles[0]:
    #圓的基本資訊
    print(circle[2])
    #座標行列
    x=int(circle[0])
    y=int(circle[1])
    #半徑
    r=int(circle[2])
    #在原圖用指定顏色標記出圓的位置
    img=cv2.circle(img,(x,y),r,(0,0,255),-1)
#顯示新影象
cv2.imshow('res',img)

11.2、簡單的輪廓屬性

質心:質心”或“質心”是影象中物體的中心(x,y)座標

#繪製輪廓質心
(cnts, _) = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
clone = image.copy()
 
for c in cnts:
    # compute the moments of the contour which can be used to compute the
    # centroid or "center of mass" of the region
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])
 
    # draw the center of the contour on the image
    cv2.circle(clone, (cX, cY), 10, (0, 255, 0), -1)

面積和周長:輪廓面積是輪廓輪廓內部的畫素數。類似地,周長(有時稱為弧長)是輪廓的長度

#獲取輪廓的面積與周長
for (i, c) in enumerate(cnts):
    area = cv2.contourArea(c)
    perimeter = cv2.arcLength(c, True)
    print "Contour #%d -- area: %.2f, perimeter: %.2f" % (i + 1, area, perimeter)
 
    cv2.drawContours(clone, [c], -1, (0, 255, 0), 2)
 
#計算影象的質心,並在影象上顯示輪廓數,以便我們可以將形狀與終端輸出相關聯。
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])#
    cY = int(M["m01"] / M["m00"])#
    cv2.putText(clone, "#%d" % (i + 1), (cX - 20, cY), cv2.FONT_HERSHEY_SIMPLEX,
        1.25, (255, 255, 255), 4)

邊框:邊界”和“包含”整個影象的輪廓區域

for c in cnts:
    # fit a bounding box to the contour
    (x, y, w, h) = cv2.boundingRect(c)
    cv2.rectangle(clone, (x, y), (x + w, y + h), (0, 255, 0), 2)

旋轉邊框:

#繪製輪廓的旋轉邊框
for c in cnts:
    # fit a rotated bounding box to the contour and draw a rotated bounding box
    box = cv2.minAreaRect(c)#引數:我們的輪廓。並返回一個包含3個值的元組。元組的第一個值是旋轉的邊界框的起始  (x,y)座標。第二個值是邊界框的寬度和高度。而最終的值就是我們形狀或旋轉的角度
    box = np.int0(cv2.cv.BoxPoints(box))#寬度和高度以及旋轉角轉換為一組座標點
    cv2.drawContours(clone, [box], -1, (0, 255, 0), 2)

最小封閉圓:

for c in cnts:
    ((x, y), radius) = cv2.minEnclosingCircle(c)#返回圓的中心的(x,y)座標以及圓的  半徑
    cv2.circle(clone, (int(x), int(y)), int(radius), (0, 255, 0), 2)

裝配橢圓:將橢圓擬合到輪廓上很像將輪廓的矩形裝配到輪廓上

for c in cnts:
    if len(c) >= 5:
        ellipse = cv2.fitEllipse(c)
        cv2.ellipse(clone, ellipse, (0, 255, 0), 2)

11.3、高階輪廓

長寬比:寬高比=影象寬度/影象寬度

程度:邊界框區域=邊界框寬度X邊框高度

凸海鷗:歐氏空間中的一組X點,凸包是包含這些X的最小可能凸集

密實度:堅固度=輪廓面積/凸包面積

#識別‘X’與‘O’
(cnts, _) = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#獲取輪廓列表
 
for (i, c) in enumerate(cnts):
    area = cv2.contourArea(c)#獲取輪廓面積
    (x, y, w, h) = cv2.boundingRect(c)#獲取輪廓的起始座標,邊界的寬度和高度
    hull = cv2.convexHull(c) #獲取形狀的實際凸包
    hullArea = cv2.contourArea(hull)#計算凸包面積
    solidity = area / float(hullArea)#獲取堅固度

    char = "?"
 #依據堅固度,判斷影象的形狀
    if solidity > 0.9:
        char = "O"
 
    elif solidity > 0.5:
        char = "X"
 
#繪製輪廓
    if char != "?":
        cv2.drawContours(image, [c], -1, (0, 255, 0), 3)
        cv2.putText(image, char, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 1.25,
            (0, 255, 0), 4)
 
    print "%s (Contour #%d) -- solidity=%.2f" % (char, i + 1, solidity)
 
cv2.imshow("Output", image)
cv2.waitKey(0)
#識別俄羅斯方塊
(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#獲取圖片中的輪廓列表
hullImage = np.zeros(gray.shape[:2], dtype="uint8")

for (i, c) in enumerate(cnts):
    area = cv2.contourArea(c)#獲取輪廓面積
    (x, y, w, h) = cv2.boundingRect(c)#獲取輪廓邊界

    aspectRatio = w / float(h)#獲取寬高比
 
    extent = area / float(w * h)#獲取當前輪廓的範圍
 
    hull = cv2.convexHull(c)
    hullArea = cv2.contourArea(hull)#
    solidity = area / float(hullArea)#獲取堅固度,依據堅固度,判斷物體形狀
 
    cv2.drawContours(hullImage, [hull], -1, 255, -1)
    cv2.drawContours(image, [c], -1, (240, 0, 159), 3)
    shape = ""

11.4、輪廓近似

輪廓逼近:一種用減少的點集合減少曲線中的點數的演算法,簡單的稱為分裂合併演算法

#檢測影象中的正方形
import cv2
 
image = cv2.imread("images/circles_and_squares.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
#獲得影象輪廓列表
(cnts, _) = cv2.findContours(gray.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 
#迴圈每個輪廓
for c in cnts:
        #獲取輪廓的周長
    peri = cv2.arcLength(c, True)

    approx = cv2.approxPolyDP(c, 0.01 * peri, True)
 
    if len(approx) == 4:#判斷處理後的輪廓是否有4個頂點
        # draw the outline of the contour and draw the text on the image
        cv2.drawContours(image, [c], -1, (0, 255, 255), 2)
        (x, y, w, h) = cv2.boundingRect(approx)
        cv2.putText(image, "Rectangle", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
            0.5, (0, 255, 255), 2)
 
cv2.imshow("Image", image)
cv2.waitKey(0)    

物體輪廓檢測:

import cv2
 
image = cv2.imread("images/receipt.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edged = cv2.Canny(gray, 75, 200)
 
cv2.imshow("Original", image)
cv2.imshow("Edge Map", edged)

(cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:7]
 
# loop over the contours
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.01 * peri, True)
 
    print "original: {}, approx: {}".format(len(c), len(approx))
 
    if len(approx) == 4:
        cv2.drawContours(image, [approx], -1, (0, 255, 0), 2)
 
cv2.imshow("Output", image)
cv2.waitKey(0)

11.5、排列輪廓

import numpy as np
import argparse
import cv2
 
#引數1:輪廓列表  引數2:排列方法
def sort_contours(cnts, method="left-to-right"):
    reverse = False
    i = 0
 
    if method == "right-to-left" or method == "bottom-to-top":
        reverse = True
 
    if method == "top-to-bottom" or method == "bottom-to-top":
        i = 1
 
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
        key=lambda b:b[1][i], reverse=reverse))
 
    return (cnts, boundingBoxes)


def draw_contour(image, c, i):
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])
 
    cv2.putText(image, "#{}".format(i + 1), (cX - 20, cY), cv2.FONT_HERSHEY_SIMPLEX,
        1.0, (255, 255, 255), 2)
 
    return image


ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the input image")
ap.add_argument("-m", "--method", required=True, help="Sorting method")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])
accumEdged = np.zeros(image.shape[:2], dtype="uint8")
 
for chan in cv2.split(image):
    chan = cv2.medianBlur(chan, 11)
    edged = cv2.Canny(chan, 50, 200)
    accumEdged = cv2.bitwise_or(accumEdged, edged)
 
cv2.imshow("Edge Map", accumEdged)

(cnts, _) = cv2.findContours(accumEdged.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]
orig = image.copy()
 
for (i, c) in enumerate(cnts):
    orig = draw_contour(orig, c, i)
 
cv2.imshow("Unsorted", orig)
 
(cnts, boundingBoxes) = sort_contours(cnts, method=args["method"])
 
for (i, c) in enumerate(cnts):
    draw_contour(image, c, i)
 
cv2.imshow("Sorted", image)
cv2.waitKey(0)

12、直方圖

直方圖:表示影象中的畫素強度

運用cv2.calcHist函式構建直方圖

cv2.calcHist(影象,通道,掩碼,histSize,範圍)

引數詳解:

影象:我們要計算的直方圖的影象

通道:索引列表,其中指定要計算直方圖的通道的索引。

掩碼:提供一個掩碼,那麼只對被掩蓋的畫素計算一個直方圖

histSize:計算直方圖時要使用的分組數

範圍:可能的畫素值的範圍

#灰度直方圖
from matplotlib import pyplot as plt
import argparse
import cv2
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])

image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Original", image)
 
hist = cv2.calcHist([image], [0], None, [256], [0, 256])
 
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.plot(hist)
plt.xlim([0, 256])

hist /= hist.sum()
 
plt.figure()
plt.title("Grayscale Histogram (Normalized)")
plt.xlabel("Bins")
plt.ylabel("% of Pixels")
plt.plot(hist)
plt.xlim([0, 256])
plt.show()
#顏色直方圖
from matplotlib import pyplot as plt
import argparse
import cv2
 
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
image = cv2.imread(args["image"])
cv2.imshow("Original", image)

chans = cv2.split(image)
colors = ("b", "g", "r")
plt.figure()
plt.title("'Flattened' Color Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
 
for (chan, color) in zip(chans, colors):
    hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
    plt.plot(hist, color = color)
    plt.xlim([0, 256])

fig = plt.figure()
 
ax = fig.add_subplot(131)
hist = cv2.calcHist([chans[1], chans[0]], [0, 1], None, [32, 32],
    [0, 256, 0, 256])
p = ax.imshow(hist, interpolation="nearest")
ax.set_title("2D Color Histogram for G and B")
plt.colorbar(p)
 
ax = fig.add_subplot(132)
hist = cv2.calcHist([chans[1], chans[2]], [0, 1], None, [32, 32],
    [0, 256, 0, 256])
p = ax.imshow(hist, interpolation="nearest")
ax.set_title("2D Color Histogram for G and R")
plt.colorbar(p)
 
ax = fig.add_subplot(133)
hist = cv2.calcHist([chans[0], chans[2]], [0, 1], None, [32, 32],
    [0, 256, 0, 256])
p = ax.imshow(hist, interpolation="nearest")
ax.set_title("2D Color Histogram for B and R")
plt.colorbar(p)
 
print "2D histogram shape: %s, with %d values" % (
    hist.shape, hist.flatten().shape[0])

hist = cv2.calcHist([image], [0, 1, 2],
    None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
print "3D histogram shape: %s, with %d values" % (
    hist.shape, hist.flatten().shape[0])
 
plt.show()

#直方圖均衡
import argparse
import cv2
 
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())
 
# load the image and convert it to grayscale
image = cv2.imread(args["image"])
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
# apply histogram equalization to stretch the constrast of our image
eq = cv2.equalizeHist(image)
 
# show our images -- notice how the constrast of the second image has
# been stretched
cv2.imshow("Original", image)
cv2.imshow("Histogram Equalization", eq)
cv2.waitKey(0)

#直方圖和麵具
from matplotlib import pyplot as plt
import numpy as np
import cv2
 
def plot_histogram(image, title, mask=None):

    chans = cv2.split(image)
    colors = ("b", "g", "r")
    plt.figure()
    plt.title(title)
    plt.xlabel("Bins")
    plt.ylabel("# of Pixels")
 
    for (chan, color) in zip(chans, colors):
        hist = cv2.calcHist([chan], [0], mask, [256], [0, 256])
        plt.plot(hist, color=color)
        plt.xlim([0, 256])

image = cv2.imread("beach.png")
cv2.imshow("Original", image)
plot_histogram(image, "Histogram for Original Image")
mask = np.zeros(image.shape[:2], dtype="uint8")
cv2.rectangle(mask, (60, 290), (210, 390), 255, -1)
cv2.imshow("Mask", mask)
 
masked = cv2.bitwise_and(image, image, mask=mask)
cv2.imshow("Applying the Mask", masked)

plot_histogram(image, "Histogram for Masked Image", mask=mask)
 
plt.show()

13、連線分量標籤

發表於 2018-06-28 15:51 天碼丶行滿 閱讀(...) 評論(...) 編輯 收藏 重新整理評論重新整理頁面返回頂部