去轮廓分支
在一个应用中,需要提取轮廓线,但初次提取的会有一些细小分支,由于知道起点和终点,所以这里采用回溯法去掉轮廓分支
import cv2
def findPath(start, end, image, stack):
# image: 二值图 value: 0 or 255
# start: 起点位置 (int h, int w)
# end: 终点位置 (int h, int w)
h, w = image.shape[:2]
if start[0] >= h or start[0] < 0 or start[1] >= w or start[1] < 0:
return False
if end[0] >= h or end[0] < 0 or end[1] >= w or end[1] < 0:
return False
stack.append(start)
if len(image.shape) > 2:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 灰度化
_, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_BINARY) # 二值化
if image[start[0]][start[1]] != 255 or image[end[0]][end[1]] != 255:
print("起点或者终点不符合要求")
return False
while len(stack) > 0:
cur = stack[-1]
x_id = cur[0]
y_id = cur[1]
# 八领域 右-->右下-->下-->左下-->左-->左上-->上-->右上
nb_ids = [[x_id, y_id+1], [x_id+1, y_id+1], [x_id+1, y_id], [x_id+1, y_id-1],
[x_id, y_id-1], [x_id-1, y_id-1], [x_id-1, y_id], [x_id-1, y_id+1]]
flag = -1
for nb_id in nb_ids:
x = nb_id[0]
y = nb_id[1]
if x == end[0] and y == end[1]:
stack.append(end_point)
for x in range(h):
for y in range(w):
if image[x][y] == 255:
image[x][y] = 0
return True
if x >= h or x < 0 or y >= w or y < 0:
continue
if image[x][y] == 255:
stack.append(nb_id)
image[x][y] = 128
flag = 1
break
if flag == -1:
stack.pop()
image[x_id][y_id] = 0
if len(stack) == 0:
print("未找到")
return False
img_path = r"D://imageGumlineTest.png"
img = cv2.imread(img_path)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, 2, 1)
cnt = contours[0]
hull = cv2.convexHull(cnt, returnPoints=False)
defects = cv2.convexityDefects(cnt, hull)
max_dist = 0
start_point = -1
end_point = -1
far_point = -1
for i in range(defects.shape[0]):
s, e, f, d = defects[i, 0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
if d > max_dist:
max_dist = d
start_point = start
end_point = end
far_point = far
cv2.line(img, start_point, end_point, [0, 255, 0], 1)
cv2.circle(img, far_point, 2, [0, 0, 255], -1)
print(f"start_point: {start_point}, end_point: {end_point}")
cv2.imshow('final_img', img)
skeleton_img = cv2.imread(r"D://refCenterLineTest1.png")
gray_img = cv2.cvtColor(skeleton_img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY)
print(f"start: {thresh[42][27]}, end: {thresh[35][289]}")
cv2.line(skeleton_img, start_point, end_point, [0, 255, 0], 1)
cv2.circle(skeleton_img, start_point, 3, [0, 0, 255], -1)
cv2.circle(skeleton_img, end_point, 3, [0, 0, 255], -1)
cv2.circle(skeleton_img, far_point, 3, [0, 0, 255], -1)
cv2.imshow('thresh', thresh)
stack = []
s_p = [42, 27]
e_p = [35, 289]
findPath(s_p, e_p, thresh, stack)
cv2.imshow("skeleton", thresh)
cv2.waitKey(0)
stack里面存放得结果即为一条起点到终点得路径
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端