1. 程式人生 > >數字影象處理筆記(三):使用OpenCV檢測影象特徵

數字影象處理筆記(三):使用OpenCV檢測影象特徵

1 - 引言

在數字影象處理中還提供了許多檢測影象簡單特徵的方法,例如邊緣檢測、輪廓檢測、直線檢測、圓檢測等。讓我們用OpenCV實現以下這些演算法吧

2 - Canny邊緣檢測

OpenCV提供了一個非常方便的Canny函式(以演算法的發明者命名)

import cv2
import numpy as np

img = cv2.imread('images/12.jpg',0)
cv2.imwrite("canny.jpg",cv2.Canny(img,200,300))
cv2.imshow("canny",cv2.imread("canny.jpg"))
cv2.waitKey(0)

原始圖片:在這裡插入圖片描述
輸出圖片:
在這裡插入圖片描述
Canny邊緣檢測演算法由5個步驟:

  • 高斯濾波器對影象去噪
  • 計算梯度
  • 在邊緣上使用非最大抑制
  • 在檢測到的邊緣上使用雙閾值去除假陽性
  • 分析邊緣及其之間的連線,以保留真正的邊緣並消除不明顯的邊緣

3 - 輪廓檢測

在計算機視覺中,輪廓檢測是另一個比較重要的任務,不單是用來檢測影象或者視訊幀中物體的輪廓,而且還有其他操作與輪廓檢測有關。下面給出一個簡單的例子來檢測出正方形的輪廓

import cv2
import numpy as np

img = np.zeros((200,200),dtype=np.uint8)
img[50:150,50:150]=255

ret,thresh = cv2.threshold(img,127,255,0)
image,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.waitKey(0)

在這裡插入圖片描述
找到一個正方形的輪廓很簡單,要找到不規則的就需要使用cv2.findContours與其他程式碼結合起來實現

import cv2
import numpy as np

img = cv2.pyrDown(cv2.imread("images/test.jpg", cv2.IMREAD_UNCHANGED))
# threshold 函式對影象進行二化值處理,由於處理後圖像對原影象有所變化,因此img.copy()生成新的影象,cv2.THRESH_BINARY是二化值
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)
# findContours函式查詢影象裡的圖形輪廓
# 函式引數thresh是影象物件
# 層次型別,引數cv2.RETR_EXTERNAL是獲取最外層輪廓,cv2.RETR_TREE是獲取輪廓的整體結構
# 輪廓逼近方法
# 輸出的返回值,image是原影象、contours是影象的輪廓、hier是層次型別
image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
    # 輪廓繪製方法一
    # boundingRect函式計算邊框值,x,y是座標值,w,h是矩形的寬和高
    x, y, w, h = cv2.boundingRect(c)
    # 在img影象畫出矩形,(x, y), (x + w, y + h)是矩形座標,(0, 255, 0)設定通道顏色,2是設定線條粗度
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

    # 輪廓繪製方法二
    # 查詢最小區域
    rect = cv2.minAreaRect(c)
    # 計算最小面積矩形的座標
    box = cv2.boxPoints(rect)
    # 將座標規範化為整數
    box = np.int0(box)
    # 繪製矩形
    cv2.drawContours(img, [box], 0, (0, 0, 255), 3)

    # 輪廓繪製方法三
    # 圓心座標和半徑的計算
    (x, y), radius = cv2.minEnclosingCircle(c)
    # 規範化為整數
    center = (int(x), int(y))
    radius = int(radius)
    # 勾畫圓形區域
    img = cv2.circle(img, center, radius, (0, 255, 0), 2)

# # 輪廓繪製方法四
# 圍繞圖形勾畫藍色線條
cv2.drawContours(img, contours, -1, (255, 0, 0), 2)
# 顯示影象
cv2.imshow("contours", img)
cv2.waitKey()
cv2.destroyAllWindows()


原始影象:在這裡插入圖片描述

實驗影象:
在這裡插入圖片描述

** 凸輪廓與Douglas-Peucker演算法**
凸形狀內部的任意兩點的連線都在該形狀裡面,使用這個演算法後可以畫出一個凸包輪廓包圍著整個物體。

import cv2
import numpy as np

img = cv2.pyrDown(cv2.imread("images/15.jpg", cv2.IMREAD_UNCHANGED))
ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) , 127, 255, cv2.THRESH_BINARY)
# findContours函式查詢影象裡的圖形輪廓
# 函式引數thresh是影象物件
# 層次型別,引數cv2.RETR_EXTERNAL是獲取最外層輪廓,cv2.RETR_TREE是獲取輪廓的整體結構
# 輪廓逼近方法
# 輸出的返回值,image是原影象、contours是影象的輪廓、hier是層次型別
image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 建立新的影象black
black = cv2.cvtColor(np.zeros((img.shape[1], img.shape[0]), dtype=np.uint8), cv2.COLOR_GRAY2BGR)


for cnt in contours:
    # 輪廓周長也被稱為弧長。可以使用函式 cv2.arcLength() 計算得到。這個函式的第二引數可以用來指定物件的形狀是閉合的(True) ,還是開啟的(一條曲線)
    epsilon = 0.01 * cv2.arcLength(cnt, True)
    # 函式approxPolyDP來對指定的點集進行逼近,cnt是影象輪廓,epsilon表示的是精度,越小精度越高,因為表示的意思是是原始曲線與近似曲線之間的最大距離。
    # 第三個函式引數若為true,則說明近似曲線是閉合的,它的首位都是相連,反之,若為false,則斷開。
    approx = cv2.approxPolyDP(cnt, epsilon, True)
    # convexHull檢查一個曲線的凸性缺陷並進行修正,引數cnt是影象輪廓。
    hull = cv2.convexHull(cnt)
    # 勾畫影象原始的輪廓
    cv2.drawContours(black, [cnt], -1, (0, 255, 0), 2)
    # 用多邊形勾畫輪廓區域
    cv2.drawContours(black, [approx], -1, (255, 255, 0), 2)
    # 修正凸性缺陷的輪廓區域
    cv2.drawContours(black, [hull], -1, (0, 0, 255), 2)
# 顯示影象
cv2.imshow("hull", black)
cv2.waitKey()
cv2.destroyAllWindows()

在這裡插入圖片描述

4 - 直線檢測和圓檢測

直線檢測

import cv2
import numpy as np

img = cv2.imread('images/louvre_small.jpg')
# 灰度處理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# canny邊緣處理
edges = cv2.Canny(gray,50,120)
line = 100
minLineLength = 20
# HoughLinesP函式是概率直線檢測,注意區分HoughLines函式
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, lines=line, minLineLength=minLineLength)
# 降維處理
lines1 = lines[:,0,:]
# line 函式勾畫直線
# (x1,y1),(x2,y2)座標位置
# (0,255,0)設定BGR通道顏色
# 2 是設定顏色粗淺度
for x1,y1,x2,y2 in lines1:
    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('images/1.jpg')
# 灰度處理
gray_img = cv2.cvtColor(planets, cv2.COLOR_BGR2GRAY)
# medianBlur 平滑(模糊)處理
img = cv2.medianBlur(gray_img, 5)
# 灰度影象轉彩色影象
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

# 圓檢測
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 100, param1=100, param2=30, minRadius=50, maxRadius=100)
# 轉化整數
circles = np.uint16(np.around(circles))

for i in circles[0,:]:
    # 勾畫圓形,planets影象、(i[0],i[1])圓心座標,i[2]是半徑
    cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
    # 勾畫圓心,圓心實質也是一個半徑為2的圓形
    cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3)
# 顯示影象
cv2.imwrite("planets_circles.jpg", planets)
cv2.imshow("mypic", cimg)
cv2.imshow("HoughCirlces", planets)
cv2.waitKey()
cv2.destroyAllWindows()

在這裡插入圖片描述