最佳答案
因为我们有一个空心形状,所以我采取了懒惰的方法。这是解决问题的平滑方法,相对简单(检查从内部到外部的距离),但它会丢失细节,因为它是在简单闭合形状的假设下运行的。如果这还不够好,请告诉我;有更复杂的方法可以做你想做的事情,可以得到更清晰的结果。
所以基本步骤是这样的:首先,使用 findContours 获取形状的内层和外层(膨胀直到得到两个,在这种情况下我们不需要这样做,因为它已经这样做了)。
然后,计算每个点到另一个轮廓上最近点的距离。从图中您可以很好地了解我们在这里要做什么。破折号是相对统一的图表的明显异常值。这里我手动将截止值设置为 10,但我们可以使用平均值和标准差来自动设置截止值。
一旦我们删除了离群点,我们就可以使用轮廓重新绘制形状。
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);
关于python - 删除二值阈值图像中具有连接边缘的小破折号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66420186/