簡體   English   中英

使用 python 和 Opencv2 檢測邊緣

[英]detect edge using python and Opencv2

我有下面這張圖片,我想把它分成兩個部分,所以我可以單獨處理每個部分,我添加了那些黑點來讓我的算法檢測到這些點並分離部分,但它檢測到了紙上的所有元素' 不像我預期的那樣工作,我不知道為什么

這是我的代碼

import cv2
import numpy as np

image = cv2.imread('18936-model-1.jpg')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (23, 23), 0)
cv2.imshow("blurred", blurred)
canny = cv2.Canny(blurred, 30, 30)
cnts, _ = cv2.findContours(canny.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
print(f"Contours in the image, %d" % (len(cnts)))
shape = image.copy()
cv2.drawContours(shape, cnts, -1, (0, 255, 0), 2)
cv2.imwrite('{}.png'.format('sunflower'), shape)
cv2.imshow("Edges", shape)
cv2.waitKey(0)

這是原始圖像

在此處輸入圖像描述

這就是我想要分離我的圖片的方式

在此處輸入圖像描述

這就是我得到的

在此處輸入圖像描述

這是一個可能的解決方案。 這個想法只是使用水平線來分割圖像。 但是,我們並不真正需要完整的圖像。 這條線沿着所有寬度延伸,所以我只提取了前幾列,將它們縮減為一列並搜索存在最大強度值的位置(或索引)。

獲得此信息后,我可以沿該參考拆分原始圖像。 讓我們看看代碼:

# Imports
import numpy as np
import cv2

# Image path
path = "D://opencvImages//"
fileName = "xIe0M.jpg"

# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)

# To grayscale:
grayImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)

# Otsu Threshold:
_, binaryImage = cv2.threshold(grayImage, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV)

# Apply thinning:
binaryImage = cv2.ximgproc.thinning(binaryImage, None, 1)

# Show the image:
showImage("binaryImage", binaryImage)

# Get image dimensions:
(imageHeight, imageWidth) = binaryImage.shape[:2]

# Get ROIs:
roiHeight = imageHeight
roiWidth = int(0.01 * imageWidth)

# Store ROIs here:
verticalCropPoints = []

# Crop first and last row:
horizontalMargin = 2
binaryImage = binaryImage[0:imageHeight, horizontalMargin:imageWidth - horizontalMargin]

# Extract left and right ROIs:
# Set Cropping dimensions:
xStart = clamp((imageWidth - roiWidth), 0, imageWidth)
xEnd = roiWidth
yStart = 0
yEnd = roiHeight

# Crop the ROI:
currentRoi = binaryImage[yStart:yEnd, xStart:xStart + xEnd]

# Image reduction to a column:
reducedImage = cv2.reduce(currentRoi, 1, cv2.REDUCE_MAX)

第一步涉及將圖像轉換為二進制,然后應用細化。 此操作會將水平寬度標准化為一個像素。 水平線我真的不需要超過一個像素。 這是迄今為止的結果:

這是非常微妙的,但這是減少到只有一列的 ROI(原始寬度的1% )。 讓我們找出最大值所在的位置(您實際上可以在過去的圖像上看到一個微弱的白色像素):

# Get indices of maximum values:
maxIndexCol = np.nonzero(reducedImage)

# Store all the indices here:
verticalCropPoints = np.append(verticalCropPoints, maxIndexCol[0])

現在我有了水平線的垂直位置。 讓我們根據這些信息進行裁剪。 該方法是通過一個循環來實現的,該循環迭代地裁剪直到達到最后一個垂直坐標:

# Crop image:
cropImage = True
cropCounter = len(verticalCropPoints)

# Loop variables:
xStart = 0
xEnd = imageWidth
yPast = 0
j = 0

while cropImage:

    if j < cropCounter:
        y = int(verticalCropPoints[j])
        yStart = yPast
        yEnd = y
        yPast = y
    else:
        yStart = yPast
        yEnd = imageHeight
        cropImage = False

    currentCrop = inputImage[yStart:yEnd, xStart:xStart + xEnd]
    cv2.imshow("currentCrop", currentCrop)
    cv2.waitKey(0)

    # Increment step counter:
    j += 1

這些是結果(為帖子縮放,在新標簽中打開它們以全分辨率查看它們):

讓我們看看該算法如何擴展到不止一條水平線。 這是對原始圖像的修改,有兩條水平線:

這會產生這些單獨的圖像:

我使用了一個輔助功能,將數字限制在有效范圍內:

# Clamps an integer to a valid range:
def clamp(val, minval, maxval):
    if val < minval: return minval
    if val > maxval: return maxval
    return val

您還需要OpenCV 的擴展圖像處理模塊來骨架化/細化圖像。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM