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.yamlmkdir ~/.ros/camera_infomv head_camera.yaml ~/.ros/camera_info
gedit ~/.ros/camera_info/head_camera.yaml

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

 

启动文件

//value 现在写的是固定路径,自行修改

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

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

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

图像处理的流程:

先创建一个节点,然后创建一个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
#include
#include
#include
using namespace cv;
#include
#include#include
#include
#include 
#include
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(r, c) == 255){dst.at(r, c) = bgr.at(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);//调节色相 HcreateTrackbar("hmin", dstName, &hmin, hmin_Max, callBack);createTrackbar("hmax", dstName, &hmax, hmax_Max, callBack);//调节饱和度 ScreateTrackbar("smin", dstName, &smin, smin_Max, callBack);createTrackbar("smax", dstName, &smax, smax_Max, callBack);//调节亮度 VcreateTrackbar("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 formatcv::Mat img_filt;  /// Filtered image in opencv matrix formatint 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 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 > contours;vector 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   
#include   
#include   
#include   
#include   
#include   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   
#include   
#include   
#include   
#include   
#include   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中查看话题,反馈回来的图象信息

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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部