ROSNOTE : 视觉系列集

bus 001 Device 002是摄像头 ID 05a3:9230 ARC International

然后输入

dmesg

从上面的打印信息中找到了uvc设备

 

ROS 教程之 vision : 用各种摄像头获取图像

从视频中提取原图片

https://www.cnblogs.com/qixianyu/p/6575276.html

安装usb_camera

sudo apt install ros-melodic-usb-cam

安装好usb_cam包之后,判断设备确定自己的摄像头是viedo0还是viedo1还是...

cd /dev &&find . -name "video*"

读取图像:

roslaunch usb_cam usb_cam-test.launch

这里的launch文件默认是的"/dev/video0",如果你的是其它名称,则需要执行以下命令(这里以"/dev/video1"举例)

roslaunch usb_cam usb_cam-test.launch video_device:="/dev/video1"

此时ros会读取/dev/video1摄像头的数据

标定校准摄像头:

https://blog.csdn.net/weixin_45839124/article/details/106955386?biz_id=102&utm_term=melodic%20usb_camera%20%E6%A0%A1%E5%87%86&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-106955386&spm=1018.2118.3001.4187

https://blog.csdn.net/qq_41746268/article/details/84752914?biz_id=102&utm_term=melodic%20usb_camera%20%E6%A0%A1%E5%87%86&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-84752914&spm=1018.2118.3001.4187

https://blog.csdn.net/pengrui18/article/details/88958487?biz_id=102&utm_term=ros%20usb%20camera&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-88958487&spm=1018.2118.3001.4187

开始标定

rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.024 image:=/usb_cam/image_raw camera:=/usb_cam

出现 

把标定板放入画面中

等到XYSIZESKEW 进度条变化

第一个按钮变亮,然后点击第一个按钮,然后等待一段时间,期间这个窗口会变灰色,但是不用关闭窗口,耐心等待。

参数计算之后会恢复,同时终端会显示标定的结果,点击“save"之后,标定文件会出现在默认的文件夹下,并在终端中看到路径。

(以下内容参考于:这个链接

在用黑白格校准之后,点击“save"之后会在终端出现下图中的最后一行

进入 /tmp/calibrationdata

mv ost.txt ost.ini
rosrun camera_calibration_parsers convert ost.ini head_camera.yaml

mkdir ~/.ros/camera_info

mv head_camera.yaml ~/.ros/camera_info
gedit ~/.ros/camera_info/head_camera.yaml

最后只需要打开head_camera.yaml文件修改一下就能保证该校准参数文件正常使用了:

 

启动文件

<launch>
  <node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen" >
    <param name="video_device" value="/dev/video0" />
    <param name="image_width" value="1280" />
    <param name="image_height" value="720" />
    <param name="pixel_format" value="yuyv" />
    <param name="camera_frame_id" value="usb_cam"/>
    <param name="io_method" value="mmap"/>
    //value 现在写的是固定路径,自行修改
    <param name="camera_info_url" type="string" value="file:///home/robot/crop_line/src/start_camera/calibration_file/head_camera.yaml" />
  </node>

  <node name="image_view" pkg="image_view" type="image_view" respawn="false" output="screen">
    <remap from="image" to="/usb_cam/image_raw"/>
    <param name="autosize" value="true" />
  </node>

</launch>

-------------------------------------------------------------------------------------------------------------------------------------------------------

以上内容属于图像预处理部分的第一部分,图像的畸变矫正

-------------------------------------------------------------------------------------------------------------------------------------------------------

图像处理的流程:

先创建一个节点,然后创建一个cv_bridge object,使用cv_bridge将ROS的图像数据转换为opencv的图像格式,frame = self.bridge.imgmsg_to_cv2(ros_image, "bgr8"),然后调用处理函数对图像进行处理display_image = self.process_image(frame),先后显示处理后的结果。

ROS中HSV颜色提取:

代码:

#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<ros/ros.h>
using namespace cv;
#include<iostream>
#include<string>

#include<cv_bridge/cv_bridge.h>
#include<image_transport/image_transport.h>
#include <sensor_msgs/Image.h>
#include<sensor_msgs/image_encodings.h>
using namespace std;
//输入图像
Mat img;
//灰度值归一化
Mat bgr;
//HSV图像
Mat hsv;
//色相
int hmin = 0;
int hmin_Max = 360;
int hmax = 180;
int hmax_Max = 180;
//饱和度
int smin = 0;
int smin_Max = 255;
int smax = 255;
int smax_Max = 255;
//亮度
int vmin =0;
int vmin_Max = 255;
int vmax = 255;
int vmax_Max = 255;
//显示原图的窗口
string windowName = "src";
//输出图像的显示窗口
string dstName = "dst";
//输出图像
Mat dst;
//回调函数
void callBack(int, void*)
{
  //输出图像分配内存
  dst = Mat::zeros(img.size(), img.type());
  //掩码
  Mat mask;
  inRange(hsv, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask);
  //掩模到原图的转换
  for (int r = 0; r < bgr.rows; r++)
  {
    for (int c = 0; c < bgr.cols; c++)
    {
      if (mask.at<uchar>(r, c) == 255)
      {
        dst.at<Vec3b>(r, c) = bgr.at<Vec3b>(r, c);
      }
    }
  }
  //输出图像
  imshow(dstName, dst);
  //保存图像
  //dst.convertTo(dst, CV_8UC3, 255.0, 0);
  imwrite("HSV_inRange.jpg", dst);
}

void callb(const sensor_msgs::ImageConstPtr& imgPtr)
{
  cv_bridge::CvImagePtr cv_ptr;
  cv_ptr =  cv_bridge::toCvCopy(imgPtr, sensor_msgs::image_encodings::BGR8);
  cv_ptr->image.copyTo(img);
  imshow("img",img);
  bgr = img.clone();
  //颜色空间转换
  cvtColor(bgr, hsv, CV_BGR2HSV);
  //cout << hsv << endl;
  //定义输出图像的显示窗口
  namedWindow(dstName, WINDOW_GUI_EXPANDED);
  callBack(0,0);
  waitKey(1);
}


int main(int argc, char** argv)
{
  ros::init(argc, argv, "tupian_debug");
  ros::NodeHandle nh;
  ros::Subscriber imageSub = nh.subscribe("/zed/rgb/image_raw_color",10,callb);

  //输入图像
  img = imread("/home/wang/Desktop/original_screenshot_14.08.2019.png");
  if (!img.data || img.channels() != 3)
    return -1;
  imshow(windowName, img);
  bgr = img.clone();
  //颜色空间转换
    cvtColor(bgr, hsv, CV_BGR2HSV);
   // cout << hsv << endl;
  //定义输出图像的显示窗口
  namedWindow(dstName, WINDOW_GUI_EXPANDED);
  //调节色相 H
  createTrackbar("hmin", dstName, &hmin, hmin_Max, callBack);
  createTrackbar("hmax", dstName, &hmax, hmax_Max, callBack);
  //调节饱和度 S
  createTrackbar("smin", dstName, &smin, smin_Max, callBack);
  createTrackbar("smax", dstName, &smax, smax_Max, callBack);
  //调节亮度 V
  createTrackbar("vmin", dstName, &vmin, vmin_Max, callBack);
  createTrackbar("vmax", dstName, &vmax, vmax_Max, callBack);
  //callBack(0,0);
  ros::spin();
  return 0;
}

修改:

1、在ROS工作空间修改launch文件以及CMakeLists文件,让其可以运行

2、修改代码中订阅的话题名字,修改为自己相机节点的名字

3、修改“输入图像”图像的位置,换成自己的

4、在调节框中调节所选目标的颜色区域,进行颜色分割,记录H 、S 、V的max以及min值

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

关于cv_bridge 以及  opencv

 cv::Mat img;  /// Input image in opencv matrix format
 cv::Mat img_filt;  /// Filtered image in opencv matrix format
 int dir;  /// Direction message to be published

cv::Mat 是类,它利用了类的特性,将内存管理和数据信息封装在类的内部,用户只需要对Mat类对象进行数据或面向对象操作即可。Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等) 的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)

CvScalar就是一个包含四个元素的结构体变量

cv::inRange 进行阈值处理

下面代码功能是:将一副图像从rgb颜色空间转换到hsv颜色空间,颜色去除白色背景部分

hsv = cv2.cvtColor(rgb_image, cv2.COLOR_BGR2HSV)
然后利用cv2.inRange函数设阈值,去除背景部分
mask = cv2.inRange(hsv, lower_red, upper_red)

函数很简单,参数有三个
第一个参数:hsv指的是原图

第二个参数:lower_red指的是图像中低于这个lower_red的值,图像值变为0

第三个参数:upper_red指的是图像中高于这个upper_red的值,图像值变为0

mask = cv2.inRange(hsv, lower_red, upper_red) #lower20===>0,upper200==>0,lower~upper==>255
就是将低于lower_red和高于upper_red的部分分别变成0,lower_red~upper_red之间的值变成255
 

给机器人的线速度是在contro_robot.cpp中


感兴趣区域(ROI,region of interest)

  机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域,ROI。
  在Halcon、OpenCV、Matlab等机器视觉软件上常用到各种算子(Operator)和函数来求得感兴趣区域ROI,并进行图像的下一步处理。 在图像处理领域,感兴趣区域(ROI) 是从图像中选择的一个图像区域,这个区域是你的图像分析所关注的重点。圈定该区域以便进行进一步处理。使用ROI圈定你想读的目标,可以减少处理时间,增加精度。


提取三个关键点是:

1、图像的预处理

2、作物行定位点提取

3、作物行直线拟合


关于第一点:

进行灰度处理,看用哪一种灰度算法处理 ,4种常用的灰度化方法:G-R、2G-R-B、ExG-ExR、在HSI空间提取S分量

对于作物识别或杂草的识别最常用的灰度化方法为超绿色法: ExG=2G-R-B


将图像分离通道

std::vector<cv::Mat> rgbChannels(3);
split(img, rgbChannels)

1、split—提取R、B、G分量(返回值顺序为:B、G、R)

函数原型:split(m, mv=None)

m:彩图矩阵

mv:默认参数

2、merge—合并R、G、B(参数顺序为:B、G、R)

函数原型:merge(mv, dst=None)

m:B、G、R分量

mv:默认参数


图像灰度化,以及以640*480大小显示图像

/* gray image*/
    cvtColor(img,dst,CV_BGR2GRAY);
    namedWindow("Display gray Image", 0 );
    cvResizeWindow("Display gray Image",640,480);
    imshow("Display gray Image", dst);

二值化

Otsu

利用形态学的方法的方法去噪,然后Hough变换,然后利用最小二乘法进行直线拟合


形态学

开操作- open

先腐蚀后膨胀
可以去掉小的对象,假设对象是前景色,背景是黑色

闭操作- close

先膨胀后腐蚀(bin2)

可以填充小的洞(fill hole),假设对象是前景色,背景是黑色

以上都是图像的预处理


定位点的提取

基于特征点群的作物定位点提取算法,常用角点检测进行角点检测

SUSAN特征角点(SUSAN算子是一种高效的边缘和角点检测算子,并且具有结构保留的降噪功能)边缘检测

然后最小二乘法


 

/*
     vector<vector<Point> > contours;
     vector<Vec4i> hierarchy;
     findContours(close, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //CV_RETR_EXTERNAL只检测外部轮廓,可根据自身需求进行调整
     Mat contoursImage(close.rows, close.cols, CV_8U, Scalar(255));
  
     for (int index = 0; index >= 0; index = hierarchy[index][0]) {
		cv::Scalar color(rand() & 255, rand() & 255, rand() & 255);
		//cv::drawContours(contoursImage, contours, index, Scalar(0), 3, 8, hierarchy);
		Rect rect = boundingRect(contours[index]);//检测外轮廓
		rectangle(contoursImage, rect, Scalar(0,0,255), 3);//对外轮廓加矩形框
      }

    //imwrite("/home/robot/pictures/00.jpg", contoursImage);
    imshow("contour_Image", contoursImage);
*/

 

压缩图象

参考文章

 

ROS图象<->OPENCV相互转换

参考原文

这里是一个节点,监听ROS图像信息话题,将图像转换为cv::Mat并在其上画圆,用opencv显示图像。然后图像将重新在ROS上显示。

#include <ros/ros.h>  
#include <image_transport/image_transport.h>  
#include <cv_bridge/cv_bridge.h>  
#include <sensor_msgs/image_encodings.h>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/highgui/highgui.hpp>  

using namespace cv;
using namespace std;
//static const std::string OPENCV_WINDOW = "Image window";

class ImageConverter  
{  
  ros::NodeHandle nh_;  
  image_transport::ImageTransport it_;  
  image_transport::Subscriber image_sub_;  
  image_transport::Publisher image_pub_;  
public:  
  ImageConverter()  
    : it_(nh_)  
  {  
    // Subscrive to input video feed and publish output video feed  
    image_sub_ = it_.subscribe("/camera/rgb/image_raw", 1,&ImageConverter::imageCb, this);  
    image_pub_ = it_.advertise("/image_converter/output_video", 1);  
  
    //cv::namedWindow(OPENCV_WINDOW);  
  } 

 ~ImageConverter()  
  {  
    //cv::destroyWindow(OPENCV_WINDOW);  
  } 

  void imageCb(const sensor_msgs::ImageConstPtr& msg)  
  {  
    cv_bridge::CvImagePtr cv_ptr;  
    try  
    {  
      cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);  
    }  
    catch (cv_bridge::Exception& e)  
    {  
      ROS_ERROR("cv_bridge exception: %s", e.what());  
      return;  
    }

    cv::Mat output = detectAndDraw(cv_ptr->image);
    cv_ptr->image = output;
       
    // Output modified video stream  
    image_pub_.publish(cv_ptr->toImageMsg());
  
    cv::waitKey(3);
  }  
cv::Mat detectAndDraw(Mat& img){
    if (img.rows > 60 && img.cols > 60)  
         cv::circle(img, cv::Point(200, 200), 100, CV_RGB(255,0,0));  
    
    // Update GUI Window  
    //cv::imshow("crop tracker", img);
    //cv::imshow(OPENCV_WINDOW, img);
    return img;
      
   
}
};

int main(int argc, char** argv)  
{  
  ros::init(argc, argv, "image_converter");  
  ImageConverter ic; 
  ros::spin();  
  return 0;  
}

代码 read_img_send.cpp
功能是订阅相机启动节点的图像,发布经过opencv处理后的图像
目前经过改编之后可以实现,先tx2上处理图像,然后把处理之后的结果发布,然后远程端是可以通过订阅话题看到处理之后的结果的
命令:
roslaunch start_camera uvc_camera.launch
rosrun follow_crop read_img_send

心得:要想成功的在远程端运行,有一点是绝对不能写的,就是不能用imshow(),不能有任何的窗口显示

代码删除没有用到的东西

#include <ros/ros.h>  
#include <image_transport/image_transport.h>  
#include <cv_bridge/cv_bridge.h>  
#include <sensor_msgs/image_encodings.h>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/highgui/highgui.hpp>  

using namespace cv;
using namespace std;

class ImageConverter  
{  
  ros::NodeHandle nh_;  
  image_transport::ImageTransport it_;  
  image_transport::Subscriber image_sub_;  
  image_transport::Publisher image_pub_;  
public:  
  ImageConverter()  
    : it_(nh_)  
  {  
    image_sub_ = it_.subscribe("/camera/rgb/image_raw", 1,&ImageConverter::imageCb, this);  
    image_pub_ = it_.advertise("/image_converter/output_video", 1);  
  } 

 ~ImageConverter()  
  {  
    
  } 

  void imageCb(const sensor_msgs::ImageConstPtr& msg)  
  {  
    cv_bridge::CvImagePtr cv_ptr;  
    try  
    {  
      cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);  
    }  
    catch (cv_bridge::Exception& e)  
    {  
      ROS_ERROR("cv_bridge exception: %s", e.what());  
      return;  
    }

    cv::Mat output = detectAndDraw(cv_ptr->image);
    cv_ptr->image = output;
    image_pub_.publish(cv_ptr->toImageMsg());
    cv::waitKey(1);
  }  
cv::Mat detectAndDraw(Mat& img){
    if (img.rows > 60 && img.cols > 60)  
         cv::circle(img, cv::Point(200, 200), 100, CV_RGB(255,0,0));  
    return img;
}
};

int main(int argc, char** argv)  
{  
  ros::init(argc, argv, "image_converter");  
  ImageConverter ic; 
  ros::spin();  
  return 0;  
}

整合完毕之后,先启动相机,然后启动识别秧苗线的程序,在rqt中查看话题,反馈回来的图象信息

感觉方向信息没有发布成功,之后进行测试。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值