Posted on

使用opencv尋找邊緣

使用Canny算子

Canny 邊緣檢測是一種從不同的視覺對像中提取有用的結構信息並顯著減少要處理的數據量的技術。它已廣泛應用於各種計算機視覺系統。Canny發現,邊緣檢測在不同視覺系統上的應用需求是比較相似的。因此,可以在各種情況下實施滿足這些要求的邊緣檢測解決方案。邊緣檢測的一般標準包括:

錯誤率低的邊緣檢測,這意味著檢測應該盡可能準確地捕獲圖像中顯示的邊緣
算子檢測到的邊緣點應該準確地定位在邊緣的中心。
圖像中的給定邊緣應僅標記一次,並且在可能的情況下,圖像噪聲不應產生錯誤邊緣。

以下為一個簡單使用範例

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
edges = cv.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()

使用cartToPolar

使用 cv2.Sobel 函數計算圖像的梯度值和方向,並使用 cv2.cartToPolar 函數將梯度值和方向轉換為極坐標形式。

import numpy as np
import cv2
gray = cv2.imread('./unknow/img_2022-12-15_18-47-31_1.jpg')
gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
gray = gray/255.0
# 計算圖像的梯度值和方向
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=1)
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=1)
magnitude, angle = cv2.cartToPolar(sobelx, sobely, angleInDegrees=True)

cv2.imshow("magnitude",magnitude)
cv2.imshow("angle",angle)
cv2.imshow("gray",gray)

在上面的方法中,要注意的是使用cv.CV_64F能有較好的結果,若想要有CV_8U的結果,可以先採用CV_64F再用下面方式轉為CV_8U

# 輸出數據類型 = cv.CV_64F。然後取其絕對值並轉換為 cv.CV_8U
sobelx64f = cv.Sobel (img,cv.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)

分水嶺演算法

OpenCV 實現了一種基於標記的分水嶺算法,您可以在其中指定哪些是要合併的所有谷點,哪些不是。它是一種交互式圖像分割。我們所做的是為我們所知道的對象賦予不同的標籤。用一種顏色(或強度)標記我們確定是前景或物體的區域,用另一種顏色標記我們確定是背景或非物體的區域,最後是我們不確定的區域,用 0 標記它。那是我們的標記。然後應用分水嶺算法。然後我們的標記將使用我們提供的標籤進行更新,並且對象的邊界值為 -1。

import cv2
import numpy

img = cv2.imread("image/water_coins.jpg")
cv2.imshow("img", img)

# 1.圖像二值化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)

kernel = numpy.ones((3, 3), dtype=numpy.uint8)
# 2.噪聲去除
open = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 3.確定背景區域
sure_bg = cv2.dilate(open, kernel, iterations=3)
# 4.尋找前景區域
dist_transform = cv2.distanceTransform(open, 1, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, cv2.THRESH_BINARY)
# 5.找到未知區域
sure_fg = numpy.uint8(sure_fg)
unknow = cv2.subtract(sure_bg, sure_fg)

# 6.類別標記
ret, markers = cv2.connectedComponents(sure_fg)
# 為所有的標記加1,保證背景是0而不是1
markers = markers + 1
# 現在讓所有的未知區域為0
markers[unknow == 255] = 0

# 7.分水嶺算法
markers = cv2.watershed(img, markers)
img[markers == -1] = (0, 0, 255)

cv2.imshow("gray", gray)
cv2.imshow("thresh", thresh)
cv2.imshow("open", open)
cv2.imshow("sure_bg", sure_bg)
cv2.imshow("sure_fg", sure_fg)
cv2.imshow("unknow", unknow)
cv2.imshow("img_watershed", img)
cv2.waitKey(0)
cv2.destroyWindow()


下面是我自己的嘗試

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread('./img_2022-12-15_18-47-31_1.jpg')
imageHSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
# 白色的部分
lower_white = np.array([0, 0, 220], dtype=np.uint8)
upper_white = np.array([180, 130, 255], dtype=np.uint8)
thresh = cv.inRange(imageHSV, lower_white, upper_white)

# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2)
cv.imshow("opening",opening)

# sure background area - Green
sure_bg = cv.dilate(opening, kernel, iterations=3)
cv.imshow("sure_bg",sure_bg)

# Finding sure foreground area
# 紅色的部分
red_lower = np.array([0, 30, 100], dtype=np.uint8)
red_upper = np.array([30, 255, 240], dtype=np.uint8)
red_lower2 = np.array([135, 30, 100], dtype=np.uint8)
red_upper2 = np.array([180, 255, 240], dtype=np.uint8)
red_mask = cv.bitwise_or(cv.inRange(imageHSV, red_lower, red_upper),cv.inRange(imageHSV, red_lower2, red_upper2))
red_mask = cv.dilate(red_mask, kernel, iterations=3)
sure_fg = cv.bitwise_or(thresh, red_mask)

# 黑色的部分
black_lower = np.array([85, 0, 0], dtype=np.uint8)
black_upper = np.array([180, 40, 100], dtype=np.uint8)
black_lower2 = np.array([0, 0, 0], dtype=np.uint8)
black_upper2 = np.array([35, 40, 100], dtype=np.uint8)
black_mask = cv.bitwise_or(cv.inRange(imageHSV, black_lower, black_upper),cv.inRange(imageHSV, black_lower2, black_upper2))
black_mask = cv.dilate(black_mask, kernel, iterations=3)
cv.imshow("black_mask",black_mask)
sure_fg = cv.bitwise_or(sure_fg, black_mask)
sure_fg = cv.erode(sure_fg, kernel, iterations=3)
cv.imshow("sure_fg",sure_fg)

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg,sure_fg)
cv.imshow("unknown",unknown)
# Marker labelling
ret, markers = cv.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0

markers = cv.watershed(img,markers)
img[markers == -1] = (0, 0, 255)
cv.imshow("watershed",img)
cv.waitKey(0)