使用OpenCV快速解决迷宫问题

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

6f58d18f33741054719b3cdba2a810f0.png

联系小编,可以获取该项目的Github源码哦https://github.com/Mnchr2018/Maze_Solution

最近,我们尝试了用相机解决迷宫问题。本文将向大家介绍我们实现该功能的具体流程。

项目主要需求的数据:

  • 数据集:数几百个不同大小、质量、颜色的迷宫图像,但是迷宫图像都需要是矩形的。

  • Maze Detector:一种基于张量流的目标检测模型,采用迁移学习方法进行训练。现有模型已使用有限数量的图像(约 500 张图像)进行训练

  • 迷宫解算器:可分 3 步完成

    •  将原始图像转换为能够通过迷宫搜索解决的格式

    •  使用现有算法解决迷宫问题(Breath First Search)

    •  使用叠加的解决方案恢复图像

  • Main Framework : 一个用于激活相机和执行图像检测模型和迷宫求解器的框架

2. 数据集

大约 500 个不同形状、大小和颜色的随机矩形迷宫已用于训练迷宫检测器模型。可以使用名为 Fatkun Batch Download Image 的扩展程序来批量下载图像。

然后需要正确标记图像。有几种标签工具具有不同的功能,但labelimg库非常方便。Labelimg 库是一个接口,它允许在每个图像中标记对象(标签名称和对象的位置)。下图显示了 labelimg 的示例。输出 xml 文件具有对象/类名称,即 rect_maze 和由 (xmin, ymin) 和 (xmax, ymax) 点/像素定义的图像中迷宫的像素坐标。

dca38d6a31e06514df142635d6bd34bf.png

3.迷宫探测器

从头开始构建对象检测器模型是可能的,但不建议这样做,因为在准备数据集和模型调整方面这是一个相当耗时的过程。迁移学习(或简单地利用现有的训练模型)允许使用数百张图像实现良好的对象检测模型。

Tensor Flow Object Detection Model Zoo 1和Zoo 2中的模型可以通过重新训练重新用于迷宫检测。模型 Zoo 中的每个模型都有其检测速度(以毫秒为单位)和在COCO数据集上获取的平均平均精度分数。通常,精度较高的模型相对较慢。(PS: 这两个模型可以在GitHub上搜索到)

重新训练一个 coco 模型的过程不在本文讨论范围内(详细过程可以在这里找到),但是应该编写一个 python 脚本来执行以下步骤:

  • 导入张量流

  • 加载检测模型

  • 冻结最后一层检测模型

  • 将模型指向包含训练图像的文件夹

  • 达到可接受的准确率后保存训练好的模型

4. 迷宫解算器

解决给出原始图像的图像的算法是最复杂的部分。它已按以下步骤完成:

第 1 步:将原始图像(由 Maze Detector 检测到)转换为迷宫搜索算法的格式。这已分两步进行。首先,使用 OpenCV 将图像转换为二维数组。其次,将二维数组收缩为二进制二维数组,其中 0 和 1 分别代表墙和路。

2792e838f7a48d1dddc304fbfa06ed43.png

第 2 步:一旦准备好 2D 阵列,就可以应用迷宫解算法来找到从 2 到 3 到 1 的路径(仅允许上、下、左和右)。

815d6bef949e8486ec8747c0cb989758.png

第 3 步:一旦迷宫被解决,原始迷宫应该被重建并覆盖解决方案。

6f705942ae9469482355068eb7a0ae98.png

五、主要框架

 最后,需要一个脚本来激活相机,通过检测模型捕获迷宫(在相机前面的图像中),运行求解器,最后将解决方案覆盖在捕获的迷宫上。下面的脚本执行上述步骤。

import time
import numpy as np
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util
import cv2
cap = cv2.VideoCapture(0)
# importing maze solver package
from solve_maze import solve_maze_2
# Path to frozen detection graph. This is the actual model that is used for the object detection.
PATH_TO_CKPT = '.../frozen_inference_graph.pb'
# path to a pbtxt file containing classes the objec was trained on.
PATH_TO_LABELS = 'object-detection.pbtxt'
NUM_CLASSES = 1
detection_graph = tf.Graph()
with detection_graph.as_default():
od_graph_def = tf.GraphDef()
with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
serialized_graph = fid.read()
od_graph_def.ParseFromString(serialized_graph)
tf.import_graph_def(od_graph_def, name='')
label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categories)
# threshold for the accuracy of detection. We dont want to run sover on image with accuracy below this threshold
detection_threshold=0.995
with detection_graph.as_default():
with tf.Session(graph=detection_graph) as sess:
pause=30
initial_flag=True
while True:
if initial_flag==True:
ret, image_np = cap.read()
ret, image_np_clean=cap.read()
image_np_expanded = np.expand_dims(image_np, axis=0)
image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
scores = detection_graph.get_tensor_by_name('detection_scores:0')
classes = detection_graph.get_tensor_by_name('detection_classes:0')
num_detections = detection_graph.get_tensor_by_name('num_detections:0')
(boxes, scores, classes, num_detections) = sess.run(
[boxes, scores, classes, num_detections],
feed_dict={image_tensor: image_np_expanded})
vis_util.visualize_boxes_and_labels_on_image_array(
image_np,
np.squeeze(boxes),
np.squeeze(classes).astype(np.int32),
np.squeeze(scores),
category_index,
use_normalized_coordinates=True,
line_thickness=2)
if scores[0][0]>=detection_threshold:
pause=pause-1
if (scores[0][0]>=detection_threshold)&(pause<0):
height, width, channels = image_np.shape
print("box : ", boxes[0][0])
detected_image_raw=image_np_clean[int(boxes[0][0][0]*height):int(boxes[0][0][2]*height),int(boxes[0][0][1]*width):int(boxes[0][0][3]*width),:]
cv2.imwrite('temp_image_2.tiff',detected_image_raw)
solution=solve_maze_2.master_solver(image='temp_image_2.tiff',
thershold_1=0.7, 
thershold_2=0.5,
thershold_3=0.71)
x_offset=int(boxes[0][0][1]*width)
y_offset=int(boxes[0][0][0]*height)
image_np[y_offset:y_offset+solution.shape[0], x_offset:x_offset+solution.shape[1]] = solution
cv2.imwrite('img2.png',image_np)
vis_util.visualize_boxes_and_labels_on_image_array(
image_np,
np.squeeze(boxes),
np.squeeze(classes).astype(np.int32),
np.squeeze(scores),
category_index,
use_normalized_coordinates=True,
line_thickness=2)
time.sleep(5)
initial_flag=False
cv2.imshow('object detection', cv2.resize(image_np, (800, 600)))
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break

好消息!

小白学视觉知识星球

开始面向外开放啦👇👇👇

 
 

00de7e3c651b053c498f619df1bec9e6.jpeg

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。


下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。


下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。


交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~
  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白学视觉

您的赞赏是我们坚持下去的动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值