[英]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.