去除二值阈值图像中带有连接边的小破折号

2024-06-09 14:38:16 发布

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

我有一个二进制阈值图像,我想删除图像中的小破折号。它与圆相连。我的主要关注点是提取圆的圆弧

  • 原始图像:

enter image description here

  • 将图像输出为:

enter image description here


Tags: 图像二进制阈值关注点破折号圆弧
2条回答

因为我们有一个中空的形状,所以我采取了懒惰的方法。这是一种解决问题的平滑方法,相对简单(检查从内部到外部的距离),但由于它是在简单闭合形状的假设下运行的,因此会丢失细节。如果这还不够好,让我知道;有更复杂的方法来做你想做的事情,可以得到更干净的结果

因此,基本步骤如下:首先,使用findContours获得形状的内层和外层(放大直到得到两层,我们不必在这种情况下这样做,因为它已经这样做了)

然后,计算从每个点到另一个轮廓上最近点的距离。从图中你可以很好地了解我们的目的。破折号是相对统一图形的明显异常值。在这里,我手动将截止值设置为10,但我们可以使用平均值和标准偏差自动设置截止值

enter image description here

一旦我们删除了异常点,我们就可以使用轮廓重新绘制形状

enter image description here

import cv2
import numpy as np

# returns a smoothed contour
def smoothed(contour, dists, cutoff):
    smooth_con = [];
    for a in range(len(dists)):
        if dists[a] < cutoff:
            smooth_con.append(contour[a]);
    return np.asarray(smooth_con);

# get the distance list for an array of points
def distList(src, other):
    dists = [];
    for point in src:
        point = point[0]; # drop extra brackets
        _, dist = closestPoint(point, other);
        dists.append(dist);
    return dists;

# returns squared distance of two points
def squaredDist(one, two):
    dx = one[0] - two[0];
    dy = one[1] - two[1];
    return dx*dx + dy*dy;

# find closest point (just do a linear search)
def closestPoint(point, arr):
    # init tracker vars
    closest = None;
    best_dist = 999999999;

    # linear search
    for other in arr:
        other = other[0]; # remove extra brackets
        dist = squaredDist(point, other);
        if dist < best_dist:
            closest = other;
            best_dist = dist;
    return closest, best_dist;

# load image
img = cv2.imread("circle_dashed.png");

# make a mask
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);
mask = cv2.inRange(gray, 0, 100);

# get contours # OpenCV 3.4, if you're using OpenCV 2 or 4, it returns (contours, _)
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
print(len(contours)); # we have two, inner and outer, no need to dilate first

# split
one = contours[0];
two = contours[1];

# get distances
one_dists = distList(one, two);
two_dists = distList(two, one);

# dump values greater than 10
smooth_one = smoothed(one, one_dists, 10);
smooth_two = smoothed(two, two_dists, 10);

# draw new contour
blank = np.zeros_like(mask);
cv2.drawContours(blank, [smooth_one], -1, (255), -1);
cv2.drawContours(blank, [smooth_two], -1, (0), -1);

# show
cv2.imshow("Image", img);
cv2.imshow("Smooth", blank);
cv2.waitKey(0);
  • 我想从图像中删除小破折号

我们删除了小破折号,但也会丢失一些功能。我们需要:


二进制掩码

  • enter image description here

  • 我们需要确定范围的下限和上限

  • 如我们所见,虚线被删除,但圆变成了点

放大面具

  • enter image description here

  • 点是可见的,但仍缺少一些特征

反转遮罩

  • enter image description here

代码:

# Load libraries
import cv2
import numpy as np

# Load the image
img = cv2.imread("GOETr.png")

# Convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# Get the binary-mask
msk = cv2.inRange(hsv, np.array([0, 0, 214]), np.array([179, 255, 217]))

# Dilate the mask
krn = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
dlt = cv2.dilate(msk, krn, iterations=8)

# Inverse the mask
res = cv2.bitwise_not(dlt)

# Show result
cv2.imshow("res", res)
cv2.waitKey(0)

您需要更改参数以获得不同的结果

相关问题 更多 >