将锯齿状边缘近似为线

Sam*_*m O 4 python opencv image-processing computer-vision edge-detection

我试图找到墨渍角的准确位置,如下所示:

我的想法是将线条拟合到边缘,然后找到它们相交的位置。到目前为止,我已经尝试使用 cv2.approxPolyDP() 和各种 epsilon 值来近似边缘,但这看起来不像是要走的路。我的 cv.approxPolyDP 代码给出了以下结果:

理想情况下,这就是我想要制作的(画在油漆上):

是否有针对此类问题的 CV 功能?我已经考虑在阈值步骤之前使用高斯模糊,尽管该方法对于角点查找来说似乎不太准确。此外,我希望这对旋转图像具有鲁棒性,因此在没有其他考虑的情况下过滤垂直和水平线不一定有效。

代码*:

import numpy as np
from PIL import ImageGrab
import cv2


def process_image4(original_image):  # Douglas-peucker approximation
    # Convert to black and white threshold map
    gray = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (5, 5), 0)
    (thresh, bw) = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    # Convert bw image back to colored so that red, green and blue contour lines are visible, draw contours
    modified_image = cv2.cvtColor(bw, cv2.COLOR_GRAY2BGR)
    contours, hierarchy = cv2.findContours(bw, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(modified_image, contours, -1, (255, 0, 0), 3)

    # Contour approximation
    try:  # Just to be sure it doesn't crash while testing!
        for cnt in contours:
            epsilon = 0.005 * cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, epsilon, True)
            # cv2.drawContours(modified_image, [approx], -1, (0, 0, 255), 3)
    except:
        pass
    return modified_image


def screen_record():
    while(True):
        screen = np.array(ImageGrab.grab(bbox=(100, 240, 750, 600)))
        image = process_image4(screen)
        cv2.imshow('window', image)
        if cv2.waitKey(25) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            break

screen_record()
Run Code Online (Sandbox Code Playgroud)
  • 关于我的代码的说明:我正在使用屏幕截图,以便我可以实时处理这些图像。我有一台可以在屏幕上显示实时馈送的数码显微镜,因此持续的屏幕录制将使我能够从视频馈送中进行采样,并在屏幕的另一半实时定位角落。

nat*_*ncy 6

这是使用阈值+形态学操作的潜在解决方案:

  1. 获取二值图像。我们加载图像,用双边滤波器模糊,灰度,然后是大津阈值

  2. 形态学操作。我们执行一系列形态学的开闭来平滑图像并去除噪声

  3. 找到扭曲的近似掩码。我们发现与对象的边界矩形坐标cv2.arcLengthcv2.approxPolyDP再画到这个面具
  4. 寻找角落。我们使用已经实现的 Shi-Tomasi 角点检测器cv2.goodFeaturesToTrack进行角点检测。看看这个对每个参数的解释

这是每个步骤的可视化:

二值图像->形态学操作->近似掩码->检测到的角点

这里是角坐标:

(103, 550)
(1241, 536)
Run Code Online (Sandbox Code Playgroud)

这是其他图像的结果

(558, 949)
(558, 347)
Run Code Online (Sandbox Code Playgroud)

最后对于旋转的图像

(201, 99)
(619, 168)
Run Code Online (Sandbox Code Playgroud)

代码

import cv2
import numpy as np

# Load image, bilaterial blur, and Otsu's threshold
image = cv2.imread('1.png')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.bilateralFilter(gray,9,75,75)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Perform morpholgical operations
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (10,10))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=1)

# Find distorted rectangle contour and draw onto a mask
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
rect = cv2.minAreaRect(cnts[0])
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(image,[box],0,(36,255,12),4)
cv2.fillPoly(mask, [box], (255,255,255))

# Find corners
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(mask,4,.8,100)
offset = 25
for corner in corners:
    x,y = corner.ravel()
    cv2.circle(image,(x,y),5,(36,255,12),-1)
    x, y = int(x), int(y)
    cv2.rectangle(image, (x - offset, y - offset), (x + offset, y + offset), (36,255,12), 3)
    print("({}, {})".format(x,y))

cv2.imshow('image', image)
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('mask', mask)
cv2.waitKey()
Run Code Online (Sandbox Code Playgroud)

注意:扭曲边界框的想法来自如何从模糊图像中找到扭曲矩形的准确角位置中的先前答案

  • @SamO,检查更新。我找到了一种方法来获得您想要的结果:)角不应该再向外,因为边界框应该更好地符合实际对象 (2认同)