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

发布于:2025-04-02 ⋅ 阅读:(16) ⋅ 点赞:(0)

一、前言

区别于之前的直接驱动相机,这里改为读取图像话题进行处理,原因是如果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博客


网站公告

今日签到

点亮在社区的每一天
去签到