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.mzph.cn/diannao/62032.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

scala模式匹配

object test47 {def main(args: Array[String]): Unit {val id"445646546548858548648"//取出id前两位val provinceid.substring(0,2) // println(province) // if (province"42"){ // println("湖北") // }else if(province&quo…

AI加持,华为全屋智能品牌升级为“鸿蒙智家”

1.传统智能家居的困境&#xff1a;从便利到繁琐 近年来&#xff0c;智能家居因其便捷性和科技感受到消费者的青睐。然而&#xff0c;随着用户需求的多样化&#xff0c;传统智能家居的弊端逐渐显现&#xff1a; 设备连接复杂&#xff0c;品牌间兼容性不足&#xff0c;用户不得不…

string类部分(C++)

目录 1. string类 1.1 auto和范围for auto关键词&#xff1a; 范围for&#xff1a; 1.2 string类的常用接口说明 a&#xff09;string类对象的常见构造 b&#xff09; string类对象的容量操作 size与length&#xff1a; capacity: empty: clear: reserve: 1.reserve&am…

大厂也在用的分布式链路追踪:TraceIdFilter + MDC + Skywalking

痛点 查线上日志时&#xff0c;同一个 Pod 内多线程日志交错&#xff0c;很难追踪每个请求对应的日志信息。 日志收集工具将多个 Pod 的日志收集到同一个数据库中后&#xff0c;情况就更加混乱不堪了。 解决 TraceId MDC 前端每次请求时&#xff0c;添加 X-App-Trace-Id 请…

Dashboard Tactics

1&#xff1a;相关链接Dashboard Tactics :: OpenCPN Dashboard Tactics Plugin rgleason/dashboard_tactics_pi: OpenCPN dashboard built-in plugin merger with external tactics_pi plugin NMEAconverter :: OpenCPN 2&#xff1a;显示样式 3&#xff1a;代码 这个插件…

【leetcode】动态规划

31. 873. 最长的斐波那契子序列的长度 题目&#xff1a; 如果序列 X_1, X_2, ..., X_n 满足下列条件&#xff0c;就说它是 斐波那契式 的&#xff1a; n > 3对于所有 i 2 < n&#xff0c;都有 X_i X_{i1} X_{i2} 给定一个严格递增的正整数数组形成序列 arr &#xff0…

24.11.26 Mybatis2

resultMap 中的标签和属性 如果是主键列 一般用id标签对应 propertyjava对象的属性 column 数据库中的列( javaType实体类数据类型 jdbcType数据库列的数据类型 ) 不需要配置 <id property"empno" column"empno" />如果是普通列 一般用result对…

第六届国际科技创新学术交流大会暨新能源科学与电力工程国际(NESEE 2024)

重要信息 会议官网&#xff1a;nesee.iaecst.org 会议时间&#xff1a;2024年12月6-8日 会议地点&#xff1a; 中国-广州&#xff08;越秀国际会议中心) 大会简介 新能源科学与电力工程国际学术会议&#xff08;NESEE 2024&#xff09;作为第六届国际科技创新学术交流大会分…

【es6】原生js在页面上画矩形添加选中状态高亮及显示调整大小控制框(三)

接上篇文章&#xff0c;这篇实现下选中当前元素显示调整大小的控制框&#xff0c;点击document取消元素的选中高亮状态效果。 实现效果 代码逻辑 动态生成控制按钮矩形,并设置响应的css // 动态添加一个调整位置的按钮addScaleBtn(target) {const w target.offsetWidth;con…

文心一言与千帆大模型平台的区别:探索百度AI生态的双子星

随着人工智能技术的迅猛发展&#xff0c;越来越多的公司开始投入资源开发自己的AI解决方案。在中国&#xff0c;百度作为互联网巨头之一&#xff0c;不仅在搜索引擎领域占据重要位置&#xff0c;还在AI领域取得了显著成就。其中&#xff0c;“文心一言”和“千帆大模型平台”便…

【西瓜书】神经网络-MP神经元、感知机和多层网络

神经网络&#xff08;neural networks&#xff09;的定义&#xff1a;神经网络是由具有适应性的简单单元组成的广泛并行互联的网络&#xff0c;它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应。&#xff08;T. Kohonen 1988年在Neural Networks创刊号上给出的定义…

《基于FPGA的便携式PWM方波信号发生器》论文分析(三)——数码管稳定显示与系统调试

一、论文概述 基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器&#xff0c;旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编…

一个专为云原生环境设计的高性能分布式文件系统

大家好&#xff0c;今天给大家分享一款开源创新的分布式 POSIX 文件系统JuiceFS&#xff0c;旨在解决海量云存储与各类应用平台&#xff08;如大数据、机器学习、人工智能等&#xff09;之间高效对接的问题。 项目介绍 JuiceFS 是一款面向云原生设计的高性能分布式文件系统&am…

【JavaScript】图解JS中的字符串方法

&#x1f4af; 欢迎光临清清ww的博客小天地&#x1f4af; &#x1f525; 个人主页:【清清ww】&#x1f525; &#x1f4da; 系列专栏:vue3 | TypeScript &#x1f4da; &#x1f31f; 学习本无底&#xff0c;前进莫徬徨。&#x1f31f; 目录 一.字符串查找 1.length属性 2. i…

ffmpeg视频滤镜:替换部分帧-freezeframes

滤镜描述 freezeframes 官网地址 > FFmpeg Filters Documentation 这个滤镜接收两个输入&#xff0c;然后会将第一个视频中的部分帧替换为第二个视频的某一帧。 滤镜使用 参数 freezeframes AVOptions:first <int64> ..FV....... set first fra…

云计算-华为HCIA-学习笔记

笔者今年7月底考取了华为云计算方向的HCIE认证&#xff0c;回顾从IA到IE的学习和项目实战&#xff0c;想整合和分享自己的学习历程&#xff0c;欢迎志同道合的朋友们一起讨论&#xff01; 第三章&#xff1a;常见设备 交换机 二层交换机和三层交换机&#xff0c;所谓二层交换机…

问题记录-Java后端

问题记录 目录 问题记录1.多数据源使用事务注意事项&#xff1f;2.mybatis执行MySQL的存储过程&#xff1f;3.springBoot加载不到nacos配置中心的配置问题4.服务器产生大量close_wait情况 1.多数据源使用事务注意事项&#xff1f; 问题&#xff1a;在springBoot项目中多表处理数…

瑞派宠物医生 | 热爱与实践交织,专注宠物口腔健康

热爱与实践交织的兽医梦 瑞派上海乔登宠物医院院长陈德举自小便与赛鸽结下了不解之缘&#xff0c;家族中饲养赛鸽的传统不仅让他对鸟类产生了浓厚的兴趣&#xff0c;更在心中埋下了成为一名兽医的种子。在面临高考这一人生重要抉择时&#xff0c;他毫不犹豫地选择了兽医专业&am…

【AIGC】如何准确引导ChatGPT,实现精细化GPTs指令生成

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | 提示词Prompt应用实例 文章目录 &#x1f4af;前言&#x1f4af;准确引导ChatGPT创建爆款小红书文案GPTs指令案例&#x1f4af; 高效开发GPTs应用的核心原则明确应用场景和目标受众构建多样化风格模板提问与引…

json格式数据集转换成yolo的txt格式数据集

这个代码是参考了两个博客 我是感觉第一篇博客可能有问题&#xff0c;然后自己做了改进&#xff0c;如果我是错误的或者正确的&#xff0c;请各位评论区说一下&#xff0c;感谢 Json格式的数据集标签转化为有效的txt格式(data_coco)_train.json-CSDN博客 COCO&#xff08;.j…