Python OpenCV未检测到明显的轮廓

2024-03-28 16:22:58 发布

您现在位置:Python中文网/ 问答频道 /正文

抱歉,我对OpenCV和整个图像处理领域都很陌生

我在Python中使用OpenCV来检测此图像中的轮廓/框

Original

它几乎能检测出所有的轮廓,但由于一些奇怪的原因,它不能提取最后一行和最后一列明显的轮廓。此图显示了它试图识别的轮廓的边界框

enter image description here

不完全确定为什么它不能轻松地拾取剩余的轮廓。我研究过类似的问题,但没有找到合适的答案

这是我的密码

import numpy as np
import cv2
import math
import matplotlib.pyplot as plt

#load image
img = cv2.imread(path)

#remove noise
img = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)

#convert to gray scale
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#make pixels darker
_, img = cv2.threshold(img, 240, 255, cv2.THRESH_TOZERO)
        
#thresholding the image to a binary image
thresh, img_bin = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

#inverting the image 
img_bin = 255 - img_bin

# countcol(width) of kernel as 100th of total width
kernel_len = np.array(img).shape[1]//100

# Defining a vertical kernel to detect all vertical lines of image 
ver_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, kernel_len))

# Defining a horizontal kernel to detect all horizontal lines of image
hor_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_len, 1))

# A kernel of 2x2
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))

#Use vertical kernel to detect and save the vertical lines in a jpg
image_1 = cv2.erode(img_bin, ver_kernel, iterations = 3)
vertical_lines = cv2.dilate(image_1, np.ones((10, 4),np.uint8), iterations = 30)
vertical_lines = cv2.erode(vertical_lines, np.ones((10, 4),np.uint8), iterations = 29)

#Use horizontal kernel to detect and save the horizontal lines in a jpg
image_2 = cv2.erode(img_bin, np.ones((1, 5),np.uint8), iterations = 5)
horizontal_lines = cv2.dilate(image_2, np.ones((2, 40),np.uint8), iterations = 20)
horizontal_lines = cv2.erode(horizontal_lines, np.ones((2, 39),np.uint8), iterations = 19)

# Combine horizontal and vertical lines in a new third image, with both having same weight.
img_vh = cv2.addWeighted(vertical_lines, 0.5, horizontal_lines, 0.5, 0.0)
rows, cols = img_vh.shape

#shift image so the enhanced lines overlap with original image
M = np.float32([[1,0,-30],[0,1,-21]])
img_vh = cv2.warpAffine(img_vh ,M,(cols,rows))

#Eroding and thesholding the image
img_vh = cv2.erode(~img_vh, kernel, iterations = 2)
thresh, img_vh = cv2.threshold(img_vh, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

bitxor = cv2.bitwise_xor(img, img_vh)
bitnot = cv2.bitwise_not(bitxor)

#find contours
contours, _ = cv2.findContours(img_vh, cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

#create list empty list to append with contours less than a specified area
new_contours = []

for contour in contours:
    if cv2.contourArea(contour) < 4000000:
        new_contours.append(contour)

#get bounding boxes
bounding_boxes = [cv2.boundingRect(contour) for contour in new_contours]

#plot detected bounding boxes
img_og = cv2.imread(path)
for bounding_box in bounding_boxes:
    x,y,w,h = bounding_box
    img_plot = cv2.rectangle(img_og, (x, y), (x+w, y+h), (255, 0, 0) , 2)

    plotting = plt.imshow(img_plot, cmap='gray')
    plt.show()

Tags: thetoinimageimgnpcv2kernel
1条回答
网友
1楼 · 发布于 2024-03-28 16:22:58

就像@ypnos所暗示的那样,膨胀和侵蚀很可能将“保存水平线”部分中的最后一行从图像中挤出。因此image_vh在搜索轮廓时不会有最后一行。我通过在每次转换后查看图像来测试(注意:1)

具体来说,迭代次数太多了。您已经使用了大小合理的内核。它在代码的第43行和第44行使用iterations = 2给出了完美的结果

将其修改为:

horizontal_lines = cv2.dilate(image_2, np.ones((2, 40), np.uint8), iterations=2)
horizontal_lines = cv2.erode(horizontal_lines, np.ones((2, 39), np.uint8), iterations=2)

边界框的矩形有点偏离了图像。通过将代码第51行更改为:

M = np.float32([[1, 0, -30], [0, 1, -5]])

这就是结果Image with bounding rectangles

注:

  1. 我通常使用此函数进行测试/调试
def test(image, title):
    cv2.imshow(title, image)
    cv2.waitKey(0)
    cv2.destroyWindow(title)

可变的位置和方便的等待键让我平静下来

相关问题 更多 >