ROS小车调用摄像头实时识别圆形限速牌上的数字

简介

最近做一个ros项目,需要ros小车调用摄像头去识别迷你的限速牌上的速度,让小车根据限速的数字判断小车当前的运动状态。

遇到难点

一开始感觉难度不大,应该会有现成的库可以使用,后面我发现我想得过于简单了。首先,难点有以下几点:

一是客户要求小车的最大运行速度比较大,而限速牌数字比较小,加上限速牌只能放在小车右手边,摄像头位置在正前方,这样一来,当速度快的时候,限速牌在图像右侧一闪而过,根本来不及反映。

二是现有的成熟的库我也测试过识别效果太慢,其中包括谷歌开源的Tesseract OCR识别,以及采用的深度学习的方式也不行,静态测试准确性挺高的,但是识别速度也很慢,现有的硬件的处理能力根本无法满足实时性需求,导致小车的图像消息大部分被丢失,延迟很大,最终采取了图像模板匹配的方法,经过图像预处理后识别速度完全满足要求。

解决思路

1. 加载所有的限速牌模板图片,并将其缩放为28x28像素大小。(模板图像要提前做好的)

2. 创建ROS节点和订阅者,接收来自摄像头的图像消息。

3. 在图像中查找圆,如果发现则截取圆形区域进行数字识别。

4. 在截取的圆形区域中,先将图像缩放到28x28大小,并将其变为灰度图像。然后使用二值化处理,只保留红色圆圈中的数字,其余部分变成白色。

5. 对于每张限速牌模板图片,使用OpenCV的模板匹配功能来寻找数字,得到最佳匹配的模板,返回其代表的数字。

6. 将程序识别到的数字展示在原始图像上。

7. 通过cv2.imshow()函数,将图像实时显示在屏幕上。

最终程序

#!/usr/bin/env python

import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import tensorflow as tf
import numpy as np

class SpeedLimitDetector():

    def __init__(self):
	
        # 加载模板图片
        self.templates = []
		# 30~120
        for i in range(30, 130, 10):
            filename = "template/template_{}.png".format(i)
            img = cv2.imread(filename, 0)
            img = cv2.resize(img, (28, 28))
            self.templates.append(img)

        # 创建ROS节点和订阅者
        rospy.init_node('speed_limit_detector')
        self.img_sub = rospy.Subscriber('/camera/image_raw', Image, self.image_callback)
        self.cv_bridge = CvBridge()

    def image_callback(self, img_msg):
        # 将ROS图像消息转换为OpenCV图像格式
        cv_img = self.cv_bridge.imgmsg_to_cv2(img_msg, desired_encoding='bgr8')

        # 在图像中查找圆
        gray_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
        circles = cv2.HoughCircles(gray_img, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=int(min(gray_img.shape)/2))

        if circles is not None:
            # 找到圆后,将圆内的区域截取下来,进行数字识别
            img, x, y, r = self.circle_crop(cv_img, circles[0])
            digit = self.detect_digit(img)

            # 显示结果
            if digit is not None:
                rospy.loginfo("Detected speed limit: {} km/h".format(digit))
                cv2.putText(cv_img, "Speed Limit: {} km/h".format(digit), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

        # 显示图像
        cv2.imshow('Speed Limit Detector', cv_img)
        cv2.waitKey(1)

    def circle_crop(self, img, circle):
        x = int(circle[0][0])
        y = int(circle[0][1])
        r = int(circle[0][2] * 0.5)
        cropped_img = img[y-r:y+r, x-r:x+r]
        return cropped_img, x, y, r

    def detect_digit(self, img):
        # 缩小图像到28*28像素,变为灰度图,并二值化处理
        img = cv2.resize(img, (28, 28))
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        _, binary_img = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
        binary_img = cv2.bitwise_not(binary_img)

        # 使用模板匹配获取数字
        max_match = None
        match_idx = None
        for i, template in enumerate(self.templates):
            result = cv2.matchTemplate(binary_img, template, cv2.TM_CCOEFF_NORMED)
            _, max_val, _, max_loc = cv2.minMaxLoc(result)
            if max_match is None or max_val > max_match:
                max_match = max_val
                match_idx = i * 10

        if max_match > 0.6:
            return match_idx + 30
        else:
            return None

    def run(self):
        rospy.spin()

    def __del__(self):
        self.sess.close()

if __name__ == '__main__':
    detector = SpeedLimitDetector()
    detector.run()

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您提供一些指导。要实现这个任务,您需要做以下步骤: 1. 安装ROS摄像头驱动程序。 2. 选择适合您的小车硬件,并将其连接到ROS系统。 3. 使用OpenCV库编写C++代码来捕获摄像头图像,并使用物体检测算法(如Haar级联分类器或深度学习模型)来识别目标物体。 4. 将目标物体的位置信息传递给小车控制器,使其移动并击倒目标物体。 下面是一个大致的代码框架,供您参考: ```c++ #include <ros/ros.h> #include <opencv2/opencv.hpp> int main(int argc, char** argv) { // ROS节点初始化 ros::init(argc, argv, "object_detection_node"); ros::NodeHandle nh; // 摄像头初始化 cv::VideoCapture cap(0); // 物体检测模型初始化 cv::CascadeClassifier object_cascade; object_cascade.load("path/to/object/cascade.xml"); while(ros::ok()) { // 读取摄像头图像 cv::Mat frame; cap >> frame; // 物体检测 std::vector<cv::Rect> objects; object_cascade.detectMultiScale(frame, objects); // 显示检测结果 for(int i=0; i<objects.size(); i++) { cv::rectangle(frame, objects[i], cv::Scalar(0,0,255), 2); } cv::imshow("Object Detection", frame); // 判断是否击倒目标物体 // 如果是,向小车控制器发送指令 // ... // 等待按键退出 if(cv::waitKey(1) == 'q') { break; } } // 释放资源 cap.release(); cv::destroyAllWindows(); return 0; } ``` 需要注意的是,这只是一个简单的框架,您需要根据您的具体情况进行修改和完善。另外,物体检测算法的选择也非常重要,您需要根据您的应用场景和硬件特性进行选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值