当前位置: 首页 > news >正文

ROS订阅相机图像识别颜色并发布识别信息

一、前言

区别于之前的直接驱动相机,这里改为读取图像话题进行处理,原因是如果opencv驱动相机后只能单一使用,就限制了其他识别功能(除非将原始图像发布出来),所以这里改成可以读取任意相机图像话题的方法,增加实用性。

二、原理

利用image_transport::ImageTransport

void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
  // ...
}
 
ros::NodeHandle nh;
image_transport::ImageTransport it(nh);
image_transport::Subscriber sub = it.subscribe(cam_topic, 1, imageCallback);

在回调函数中转化ros图像信息为opencv格式

  try
    {
      cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
      frame = cv_ptr->image;
    }
    catch (cv_bridge::Exception& e)
    {
      ROS_ERROR("cv_bridge exception: %s", e.what());
      return;
    }

这里frame为Mat形式,相当于opencv的帧

之后就可以对frame进行图像处理了

三、使用

launch文件的使用

<?xml version="1.0"?>
<launch>
  <node pkg="color_detect" name="color_topic" type="color_topic" output="screen"/>
            <param name="image_view" type="bool" value="true"/>
            <param name="cam_topic" type="string" value="/usb_cam/image_raw"/>
            <param name="H" type="int" value="100"/>
            <param name="S" type="int" value="100"/>
            <param name="V" type="int" value="100"/>

</launch>

通过更改相机话题名称来读取相机图像话题 。

将图像处理的代码放进回调函数,而不是在while中,防止图像处理有延迟和重复。

void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{

    try
    {
      cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
      frame = cv_ptr->image;
    }
    catch (cv_bridge::Exception& e)
    {
      ROS_ERROR("cv_bridge exception: %s", e.what());
      return;
    }

    Scalar lower_red(H - 30, S - 30, V - 30);
    Scalar upper_red(H + 30, S + 30, V + 30); // 定义红色的HSV范围

         if(!frame.empty()) //画面是否正常
        {  
            /*对图片二次处理*/
        
            cvtColor(frame, imghsv, COLOR_BGR2HSV);// 将图像转换为HSV颜色空间

            split(imghsv, hsvSplit);
		    equalizeHist(hsvSplit[2], hsvSplit[2]);
		    merge(hsvSplit, imghsv);

            inRange(imghsv, lower_red, upper_red, mask);//二值化红色部分

            Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
            morphologyEx(mask, mask, MORPH_OPEN, kernel);//开运算
            morphologyEx(mask, mask, MORPH_CLOSE, kernel);//闭运算
            
            GaussianBlur(mask, mask, Size(5, 5), 0);//高斯滤波
            Canny(mask, mask, 150, 100);//canny算子边缘检测

            vector<vector<Point> > contours;
            vector<Vec4i> hierarchy;
            findContours(mask,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE,Point());  
            //ROS_INFO("个数为%d",int(contours.size()));
            std::vector<std::vector<cv::Point> >::const_iterator itc = contours.begin();
            std::vector<std::vector<cv::Point> >::const_iterator max_c = contours.begin();
            if(	(!contours.empty() && !hierarchy.empty()))
            {
                        //寻找最大面积的轮廓
                        while (itc != contours.end())
                        {
                           if( cv::contourArea(*itc) >  cv::contourArea(*max_c)) {
                                max_c = itc;
                            }
                            itc++;
                        }
            Rect boundRect = boundingRect(*max_c);
            circle(frame, Point(boundRect.x + boundRect.width/2, boundRect.y + boundRect.height/2), 5, Scalar(0,0,255), -1);
            rectangle(frame, Point(boundRect.x, boundRect.y), Point(boundRect.x + boundRect.width, boundRect.y + boundRect.height), Scalar( 0, 0, 255), 2);

            //ROS_INFO("x:%d,y:%d",boundRect.x+ boundRect.width/2, boundRect.y + boundRect.height/2);
            detect_msg.Class = "red";
            detect_msg.xmin = boundRect.x;
            detect_msg.xmax=boundRect.x + boundRect.width;
            detect_msg.ymin=boundRect.y;
            detect_msg.ymax= boundRect.y + boundRect.height;
            }
            else
            {
            }        
             if(image_view)
            {
                namedWindow("video");
                startWindowThread();
                imshow("video", frame);
                setMouseCallback("video", on_mouse, 0);

                //   int c = waitKey(1);
		        //     if (c == 27) {//key:esc
			    //     ros::shutdown();
		        // }
            }
             //opencv转ros
             try
            {
                ros_msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", frame).toImageMsg();  
            }
            catch (cv_bridge::Exception& e)
            {
                ROS_ERROR("cv_bridge exception:%s",e.what());
            }
            image_pub.publish(ros_msg);  
            boundingbox_pub.publish(detect_msg);
    	}  

}

 

所有效果和之前的功能包相同

Opencv+ROS实现特定物品识别_opencv 训练模型 特定物体识别-CSDN博客文章浏览阅读913次,点赞5次,收藏4次。ros实现特定物品识别,基于opencv的hsv值颜色识别算法为原理。_opencv 训练模型 特定物体识别 https://blog.csdn.net/2301_76165902/article/details/144225683具体代码可以去这篇博客查看。

感谢观看。

参考:ROS image_transport使用笔记_image callback-CSDN博客

http://www.dtcms.com/a/112218.html

相关文章:

  • 【进收藏夹吃灰】Python基础学习指南
  • 【读书笔记·VLSI电路设计方法解密】问题61:扫描插入的目的是什么
  • java 局部内部类
  • Git 教程:从 0 到 1 全面指南 教程【全文三万字保姆级详细讲解】
  • DPDI版本升级说明
  • AI提示词:分享卡片生成器
  • 浅析 Spring AI 与 Python:企业级 AI 开发的技术分野
  • 在Git中如何处理冲突?
  • 目前主流OCR/语义理解/ASR
  • 使用mcp自定义编写mcp tool,使用 conda 启动,在cline中配置使用
  • MOM成功实施分享(八)汽车活塞生产制造MOM建设方案(第一部分)
  • fastGPT—前端开发获取api密钥调用机器人对话接口(HTML实现)
  • GIt 分布式版本控制系统
  • ND4J的MemoryWorkspace
  • [2018][note]用于超快偏振开关和动态光束分裂的all-optical有源THz超表——
  • 【FPGA基础学习】状态机思想实现流水灯
  • 推理模型与普通大模型如何选择?
  • vue组件开发:什么是VUE组件?
  • Redis核心机制-缓存、分布式锁
  • selectdb修改表副本
  • leetcode51-N皇后
  • SpringBoot异步任务实践指南:提升系统性能的利器
  • 《P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题》
  • 数据集(Dataset)和数据加载器(DataLoader)-pytroch学习3
  • MySQL 索引原理
  • Koordinator-NodeInfoCollector
  • 微服务架构: SpringCloud服务注册与发现详解
  • P17_ResNeXt-50
  • Apache Struts2 漏洞(CVE-2017-5638)技术分析
  • 七、重学C++—静态多态(编译期)