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

Opencv+ROS实现颜色识别应用

目录

一、工具

二、原理

概念

本质

三、实践

 添加发布话题

主要代码

四、成果

五、总结


一、工具

opencv+ros

ubuntu18.04

摄像头

二、原理

概念

彩色图像:RGB(红,绿,蓝)

HSV图像:H(色调)S(饱和度)V(亮度)

色调(H:hue):用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
饱和度(S:saturation):取值范围为0.0~1.0,值越大,颜色越饱和。
亮度(V:value):取值范围为0(黑色)~255(白色)。

但是在opencv中引用的范围有所不同,给出下表。

本质

颜色识别本质就是在图像上提取出你想要的颜色阈值,然后通过降噪优化模型,轮廓检测进行框选。

要点:

  • RGB转HSV
  • 所需颜色阈值(hsv),并二值化
  • 腐蚀操作除噪,Canny算法进行边缘检测
  • 最后通过findContours()函数找出轮廓坐标

三、实践

读取摄像头

    VideoCapture cap(video_device);  //dev/video0

RGB转HSV

cvtColor(frame, imghsv, COLOR_BGR2HSV);

直方图均衡化

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

直方图均衡化是一种简单有效的图像增强技术,用于增强动态范围偏小的图像的对比度

定义颜色阈值,这里选取红色

    Scalar lower_red(156, 43, 46);Scalar upper_red(180, 255, 255); // 定义红色的HSV范围inRange(imghsv, lower_red, upper_red, mask);//二值化红色部分

inRange()函数就是检测imghsv内所有像素是否在lower-upper之间,如果是则设为255,也就是白色。输出的是二值图。

用腐蚀,膨胀操作去噪点

  Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));morphologyEx(mask, mask, MORPH_OPEN, kernel);//开运算morphologyEx(mask, mask, MORPH_CLOSE, kernel);//闭运算

腐蚀,膨胀操作的对象是二值化图像

  • 腐蚀:变精细
  • 膨胀:变粗矿
  • 开运算:先腐蚀后膨胀 消去一个黑图中的很多小白点
  • 闭运算:先膨胀后腐蚀 消去一个白图中的很多小黑点
  • 梯度运算:膨胀-腐蚀

 高斯滤波,Canny边缘检测

    GaussianBlur(mask, mask, Size(3, 3), 0);//高斯滤波Canny(mask, mask, 100, 250);//canny算子边缘检测

 Canny()函数参数表明:

第一个:InputArray类型的image,输入图像
第二个:OutputArray类型的edges,输出的边缘图
第三个:double类型的threshold1,第一个滞后性阈值
第四个:double类型的threshold2,第二个滞后性阈值

 Canny过程为

  1. 高斯滤波获得平滑图像
  2. 计算每个像素点的梯度强度和方向
  3. 应用非极大值抑制,消除边缘检测带来的杂散响应
  4. 双阈值确定真实或潜在的边缘
  5. 抑制弱化边缘完成边缘检测

然后开始找轮廓

findContours()函数

findContours(mask,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE,Point());  

第一个参数:输入图像

第二个参数:所有轮廓

第三个参数:表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号

第四个参数:RETR_EXTERNAL只检测最外围轮廓

第五个参数:CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息

寻找最大轮廓

 vector<double> Area(contours.size());//寻找最大面积的轮廓for (int i = 1; i < contours.size(); i++) {Area[i] = contourArea(contours[i]);if (Area[i] > Area[max]) {max = i;}   }Rect boundRect = boundingRect(Mat(contours[max]));circle(frame, Point(boundRect.x + boundRect.width/2, boundRect.y + boundRect.height/2), 5, Scalar(0,0,255), -1);

boundingRect()函数

表示包围轮廓的最大矩形

返回四个参数

第一个:boundRect.x

第二个:boundRect.y

第三个:boundRect.width

第四个:boundRect.hight

左上角顶点的像素坐标值及矩形边界的宽和高

然后将矩形在原画面画出即可

ROS_INFO("x:%d,y:%d",boundRect.x+ boundRect.width/2, boundRect.y + boundRect.height/2);
rectangle(frame, Point(boundRect.x, boundRect.y), Point(boundRect.x + boundRect.width, boundRect.y + boundRect.height), Scalar( 0, 0, 255), 2);

 添加发布话题

毕竟是在ros下编写的,我们要把像素坐标发布出去,这里自定义一个消息类型

boundingbox.msg

用来表示类和坐标值

主要代码

 while (ros::ok()) {  cap >> frame;  //摄像头画面赋给frameif(!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()));vector<double> Area(contours.size());if(contours.size() > 0 ){//寻找最大面积的轮廓for (int i = 1; i < contours.size(); i++) {Area[i] = contourArea(contours[i]);if (Area[i] > Area[max]) {max = i;}   }Rect boundRect = boundingRect(Mat(contours[max]));circle(frame, Point(boundRect.x + boundRect.width/2, boundRect.y + boundRect.height/2), 5, Scalar(0,0,255), -1);ROS_INFO("x:%d,y:%d",boundRect.x+ boundRect.width/2, boundRect.y + boundRect.height/2);rectangle(frame, Point(boundRect.x, boundRect.y), Point(boundRect.x + boundRect.width, boundRect.y + boundRect.height), Scalar( 0, 0, 255), 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;}

四、成果

运行画面

 查看话题

这里识别画面内所有红色区域

五、总结

写代码过程中还是遇到很多问题的,不知道是opencv版本不兼容的问题还是哪里我编写不细致,节点总是挂掉。

但还是能完成基本需求。

这里把报错留下,希望有大佬能帮帮我

OpenCV Error: Assertion failed (npoints >= 0 && (depth == CV_32F || depth == CV_32S)) in pointSetBoundingRect, file /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/imgproc/src/shapedescr.cpp, line 466
terminate called after throwing an instance of 'cv::Exception'
  what():  /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/imgproc/src/shapedescr.cpp:466: error: (-215) npoints >= 0 && (depth == CV_32F || depth == CV_32S) in function pointSetBoundingRect

应该是boundingRect()函数的问题,但不知道问题在哪

欢迎评论区指正。

http://www.lryc.cn/news/491966.html

相关文章:

  • 蓝桥杯c++算法秒杀【6】之动态规划【下】(数字三角形、砝码称重(背包问题)、括号序列、异或三角:::非常典型的必刷例题!!!)
  • C++设计模式(单例模式)
  • 前端---CSS(部分用法)
  • 2024年最新版Java八股文复习
  • 计算机毕业设计Hadoop+Spark音乐推荐系统 音乐预测系统 音乐可视化大屏 音乐爬虫 HDFS hive数据仓库 机器学习 深度学习 大数据毕业设计
  • MyBatis高级扩展
  • 代码美学2:MATLAB制作渐变色
  • 浅谈- “ 变量中 无符号 与 有符号 的 值转换 ”
  • 【AI绘画】Midjourney进阶:色调详解(上)
  • 代码管理之Gitlab
  • 防御网络攻击的创新策略
  • C++软件设计模式之组合模式概述
  • 利用HTML5和CSS来实现一个漂亮的表格样式
  • Vivado程序固化到Flash
  • HCIA笔记3--TCP-UDP-交换机工作原理
  • 计算机网络的功能
  • Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)
  • 多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测
  • windows安全中心,永久卸载工具分享
  • 《安富莱嵌入式周报》第346期:开源2GHz带宽,12bit分辨率,3.2Gsps采样率示波,开源固件安全分析器, 开源口袋电源,开源健康测量,FreeCAD
  • Apache OFBiz xmlrpc XXE漏洞(CVE-2018-8033)
  • 【论文复现】融入模糊规则的宽度神经网络结构
  • sql server 获取当前日期的时间戳
  • LLM PPT Translator
  • 铲屎官进,2024年宠物空气净化器十大排行,看看哪款吸毛最佳?
  • python 中常用的定积分求解方法
  • 音视频相关的一些基本概念
  • pikachu文件上传漏洞通关详解
  • 【拥抱AI】向量数据库有哪些常见的检索算法?
  • Webpack前端工程化进阶系列(二) —— HMR热模块更新(图文+代码)