python - 删除二进制阈值图像中具有连接边缘的小破折号
解决方案
因为我们有一个空心的形状,所以我采取了懒惰的方法。这是一个相对简单的问题的平滑方法(检查从内部到外部的距离),但是它丢失了细节,因为它在一个简单的封闭形状的假设下运行。如果这还不够好,请告诉我;有更复杂的方法可以做你想做的事情,可以得到更清晰的结果。
所以基本步骤是这样的:首先,使用 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);
推荐阅读
- android - Kotlin 上的 Android Retrofit 如何为响应添加时间戳?
- javascript - 如何实现“如果单击图像,则 textContent 更改为 X”。
- python - python jarvis没有运行
- sql - 如何在我的报告中输入填充日期?
- python - Coinbase Websocket API,秒级准确的订单簿构建
- amazon-web-services - 尽管响应成功,AWS SMS 仍未发送
- python - 读取文本文件到元组pyspark
- c# - FindObjectsWithTag 在 Unity 中以随机顺序带回对象?
- jwt - AWS 临时凭证中的“Session Token”有什么意义?
- sql - 根据条件分组和删除行