邊緣/輪廓檢測

邊緣/輪廓檢測

Canny邊緣檢測

Canny邊緣檢測原理

Canny邊緣檢測的一般步驟

  • step1:去噪
    • 邊緣檢測容易受到噪聲的影響。因此,在進行邊緣檢測前,通常需要先進行去噪
    • 通常採用高斯濾波器去除噪聲
  • step2:梯度
    • 對平滑後的圖像採用sobel算子計算梯度和方向
    • 梯度的方向一般總是與邊界垂直
    • 梯度方向被歸爲四類:垂直、水平、兩個對角線
  • step3:非極大值抑制
    • 在獲得了梯度和方向後,遍歷圖像,去除所有不是邊界的點
    • 實現方法:逐個遍歷像素點,判斷當前像素點是否是周圍像素點中具有相同方向梯度的最大值;若是,保留該點;否則,抑制(歸零)
    • 例子:下圖黃色背景的值被保留,其餘點被抑制(處理爲0)
      在這裏插入圖片描述
  • step4:滯後閾值
    • 兩個值:minVal:滯後閾值1;maxVal:滯後閾值2
    • 閾值越大,信息越少
    • 例子:
      在這裏插入圖片描述
Canny函數及使用

edges = cv2.Canny(image, threshold1, threshold2)

  • edges:邊界圖像
  • image:原始圖像
  • threshold1:閾值1(minVal
  • threshold2:閾值2(maxVal

操作小記

import cv2

o = cv2.imread("lena.jpg", cv2.IMREAD_GRAYSCALE)
r = cv2.Canny(o, 100, 200)
cv2.imshow("ori", o)
cv2.imshow("res", r)
cv2.waitKey()
cv2.destroyAllWindows()

效果
在這裏插入圖片描述

輪廓查找和繪製

圖像輪廓

輪廓定義

  • 邊緣檢測能夠測出邊緣,但是邊緣是不連續的
  • 將邊緣連接爲一個整體,構成輪廓

注意問題

  • 對象是二值圖像。所以需要預先進行閾值分割或者邊緣檢測處理
  • 查找輪廓需要更改原始圖像。因此,通常使用原始圖像的一份拷貝操作
  • 在OpenCV中,是從黑色背景中查找白色對象。因此,對象必須是白色的,背景必須是黑色的

使用函數

  • cv2.findContours():查找圖像輪廓的函數
    • contours, hierarchy = cv2.findContours(image, mode, method)
      • contours:輪廓
      • hierarchy:圖像的拓撲信息(輪廓層次)
      • image:原始圖像
      • mode:輪廓檢索模式
        • cv2.RETR_EXTERNAL:表示只檢測外輪廓
        • cv2.RETR_LIST:檢測的輪廓不建立等級關係
        • cv2.RETR_CCOMP:建立兩個等級的輪廓,上面的一層爲外邊界,裏面的一層爲內孔的邊界信息。如果內孔內還有一個連通物體,這個物體的邊界也在頂層
        • cv2.RETR_TREE:建立一個等級樹結構的輪廓
      • method:輪廓的近似方法
        • cv2.CHAIN_APPROX_NONE:存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1,即max(abs(x1-x2), abs(y2-y1)) == 1
        • cv2.CHAIN_APPROX_SIMPLE:壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點座標,例如一個矩形輪廓只需4個點來保存輪廓信息
        • cv2.CHAIN_APPROX_TC89_L1:使用teh-Chinl chain 近似算法
        • cv2.CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain 近似算法
  • cv2.drawContours():將查找的輪廓繪製到圖像上
    • r = cv2.drawContours(o, contours, contourldx, color[, thickness])
      • r:目標圖像,直接修改目標的像素點,實現繪製
      • o:原始圖像
      • contours:需要繪製的邊緣數組
      • contourldx:需要繪製的邊緣索引,如果全部繪製則爲 -1
      • color:繪製的顏色,爲BGR格式的Scalar
      • thickness:可選,繪製的密度,即描述輪廓時所用的畫筆粗細

注意:若是採用這個格式img, contours, hierarchy = cv2.findContours(image, mode, method)會報下面錯誤,原因是opencv的方法改掉了,findCountours方法被修改爲只返回coutours和hierarchy

Traceback (most recent call last):
  File "D:/data/Code/PycharmProjects/helloworld/test.py", line 7, in <module>
    img, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)

Process finished with exit code 1

操作小記

import cv2

o = cv2.imread("money.png")
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
co = o.copy()
r = cv2.drawContours(co, contours, -1, (0, 0, 255), 1)
cv2.imshow("ori", o)
cv2.imshow("res", r)
cv2.waitKey()
cv2.destroyAllWindows()

效果
在這裏插入圖片描述

Hough輪廓檢測

Hough-直線檢測

霍夫直線變換介紹

  • Hough Line Transform用來做直線檢測
  • 前提條件:邊緣檢測已經完成
  • 平面空間到極座標空間轉換
    在這裏插入圖片描述
  • 具體
    在這裏插入圖片描述

操作小記

import cv2
import numpy as np


def line_detection(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
    lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)
    for line in lines:
        rho, theta = line[0]
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0 + 1000 * (-b))
        y1 = int(y0 + 1000 * a)
        x2 = int(x0 - 1000 * (-b))
        y2 = int(y0 - 1000 * a)
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
    cv2.imshow("line_detection", img)


def line_detect_possible_demo(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)
    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
    cv2.imshow("line_detect_possible_demo", img)


img = cv2.imread("Sudoku.png")
cv2.imshow("ori", img)
line_detection(img)
line_detect_possible_demo(img)
cv2.waitKey()

效果
在這裏插入圖片描述

Hough-圓檢測

霍夫圓檢測原理

  • 從平面座標到極座標轉換三個參數C(x0, y0, r)其中x0, y0是圓心
  • 假設平面座標的任意一個圓上的點,轉換到極座標中:C(x0, y0, r) 處有最大值,霍夫變換正是利用這個原理實現圓檢測
    在這裏插入圖片描述

現實考量

  • 因爲霍夫圓檢測對噪聲比較敏感,所以首先要對圖像做中值濾波
  • 基於效率考慮,OpenCV中實現的霍夫變換圓檢測是基於圖像梯度的實現,分爲兩步:
    • 檢測邊緣,發現可能的圓心
    • 基於第一步的基礎上從候選圓心開始計算最佳半徑大小

操作小記

import cv2
import numpy as np


def detect_circles_demo(img):
    dst = cv2.pyrMeanShiftFiltering(img, 10, 100)
    cimg = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
    circles = cv2.HoughCircles(cimg, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        cv2.circle(img, (i[0], i[1]), i[2], (0, 0, 255), 2)
        cv2.circle(img, (i[0], i[1]), 2, (255, 0, 0), 2)
    cv2.imshow("circles", img)


img = cv2.imread("money.png")
cv2.imshow("ori", img)
detect_circles_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果
在這裏插入圖片描述
若採用dst = cv2.GaussianBlur(img, (23, 23), 0, 0)來過濾,效果會更好
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章