问题描述
我有一个二进制阈值图像,我想从图像中删除小破折号.连接到圈子.我的主要重点是提取圆弧.
I have a binary threshold image and I want to remove small dashes from an image. which is connected to the circle. My main focus is to extract an arc of the circle.
- 原始图片:
- 将图像输出为:
推荐答案
由于我们具有空心形状,因此我采用了惰性方法.这是一种相对简单的问题的平滑方法(检查从内部到外部的距离),但是由于它在简单的封闭形状的假设下运行,因此丢失了细节.如果这还不够好,请告诉我;有更复杂的方法可以完成您想要的操作,从而获得更清晰的结果.
I took the lazy approach to this since we have a hollow shape. This is a smoothing approach to the problem which is relatively simple (check the distance from inner to outer), but it loses details since it runs under the assumption of a simple closed shape. If this isn't good enough, let me know; there are more complicated methods for doing what you want that can give cleaner results.
因此,基本步骤如下:首先,使用findContours来获取形状的内层和外层(扩张直到得到两个,我们在这种情况下不必这样做,因为它已经做到了).
So the basic steps are this: First, use findContours to get the inner and outer layer of the shape (dilate until you get two, we didn't have to for this case since it already does that).
然后,计算从每个点到另一个轮廓上最接近点的距离.从图中可以很好地了解我们要在这里做什么.破折号是相对均匀图形的明显异常值.在这里,我将截止值手动设置为10,但是我们可以使用平均值和标准偏差来自动设置截止值.
Then, calculate the distance from the each point to the closest point on the other contour. From the graph you can get a pretty good idea of what we're going for here. The dashes are clear outliers to a relatively uniform graph. Here I manually set the cutoff to 10, but we could use averages and standard deviation to automatically set a cutoff.
一旦我们删除了离群点,我们就可以使用轮廓重新绘制形状.
Once we've removed the outlier points, we can just redraw the shape using the contours.
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);
这篇关于在二进制阈值图像中去除边缘连接的小破折号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!