首先使用canny或其他方法将图片边缘轮廓提取:
(下图为mask处理后的图像)
参考论文
《A Sub-Pixel Edge Detector: an Implementation of theCanny/Devernay Algorithm》
提取后的亚像素级边缘散点如下:
由于亚像素级别的点太小,肉眼可能不好辨识,这边放一下局部效果图:
之后根据八邻域算法进行改进,提出了一种边缘亚像素点连线的方法:
import random
import cv2
from tqdm import tqdm
from json_open_close import open_json, save_json
# 获取两点间距离
def get_dis(x1, y1, x2, y2):
return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
# 获取相邻最近的三个结点
def get_nearest_nodes(x, y, new_locs):
tem_dis = []
for loc in new_locs:
if not loc['visited']:
tem_dis.append(((x - loc['loc'][0]) ** 2 + (y - loc['loc'][1]) ** 2) ** 0.5)
else:
tem_dis.append(1e5)
_min = min(tem_dis)
if _min > 200:
return -1, -1, -1
else:
_index1 = tem_dis.index(_min)
tem_dis[_index1] += 1e5
_min = min(tem_dis)
_index2 = tem_dis.index(_min)
tem_dis[_index2] += 1e5
_min = min(tem_dis)
_index3 = tem_dis.index(_min)
tem_dis[_index3] += 1e5
return _index1, _index2, _index3
# 打开json格式存储的点位置文件
f = open_json("Pic1-3board.json")
locs = f['2']
length = len(locs)
new_locs = []
# 设置新的字典存储点位置
for i in range(length):
tem = {
"visited": False,
"loc": locs[i],
"id": 0,
"end": False
}
new_locs.append(tem)
# 随机访问结点
start = random.randint(0, length - 1)
now_id = 0
new_locs[start]['id'] = now_id
new_locs[start]['visited'] = True
for i in tqdm(range(len(new_locs) - 1)):
now_id += 1
_index1, _index2, _index3 = get_nearest_nodes(new_locs[start]['loc'][0], new_locs[start]['loc'][1], new_locs)
if _index1 == -1:
new_locs[start]['id'] = now_id
new_locs[start]['visited'] = True
new_locs[start]['end'] = True
count = 0
for loc in new_locs:
if not loc['visited']:
start = count
break
count += 1
else:
_grad1 = (new_locs[start]['loc'][0] - new_locs[_index1]['loc'][0]) / (
new_locs[start]['loc'][1] - new_locs[_index1]['loc'][1] + 1e-6)
_grad2 = (new_locs[start]['loc'][0] - new_locs[_index2]['loc'][0]) / (
new_locs[start]['loc'][1] - new_locs[_index2]['loc'][1] + 1e-6)
_grad3 = (new_locs[start]['loc'][0] - new_locs[_index3]['loc'][0]) / (
new_locs[start]['loc'][1] - new_locs[_index3]['loc'][1] + 1e-6)
dis1 = (new_locs[start]['loc'][0] - new_locs[_index1]['loc'][0]) ** 2 + (
new_locs[start]['loc'][1] - new_locs[_index1]['loc'][1]) ** 2
dis2 = (new_locs[start]['loc'][0] - new_locs[_index2]['loc'][0]) ** 2 + (
new_locs[start]['loc'][1] - new_locs[_index2]['loc'][1]) ** 2
dis3 = (new_locs[start]['loc'][0] - new_locs[_index3]['loc'][0]) ** 2 + (
new_locs[start]['loc'][1] - new_locs[_index3]['loc'][1]) ** 2
_grad1, _grad2, _grad3 = abs(_grad1), abs(_grad2), abs(_grad3)
# 为每个结点打分
score1 = dis1 * 0.9
score2 = dis2 * 0.9
score3 = dis3 * 0.9
scores = (score1, score2, score3)
# 选取最优结点
_min = min(scores)
_index = scores.index(_min)
# 更新索引
if _index == 0:
start = _index1
elif _index == 1:
start = _index2
else:
start = _index3
new_locs[start]['id'] = now_id
new_locs[start]['visited'] = True
# 储存结果
save_json("new_loc.json", new_locs)
其中提取出的的数据格式为:
{
"visited": true,
"loc": [12931, 911],
"id": 901,
"end": false
}
使用cv.line进行连线,为了方便观察,这里用较粗线条进行连接。
效果图:
效果较为满意。