OPENCV判断图像中目标物位置及多目标物聚类

news/2024/12/21 22:36:46/

文章目录


在最近的项目中,又碰到一个有意思的问题需要通过图像算法来解决。就是显微拍摄的到的医疗图像中,有时候目标物比较偏,也就是在图像的比较偏的位置,需要通过移动样本,将目标物置于视野正中央,然后再次进行拍摄。

就类似于下面的图像:

基于这个需求,在图像上就需要使用图像算法进行判断(没有必要使用深度网络的时候就不要用,太浪费资源了)。

对于上面的图像,基本的处理逻辑是:

  1. 因为目标物是细胞,也就是图中的一个一个的圈圈,需求就是要让尽可能多的细胞位于图像正中央。
  2. 目标物的粘连比较少,所以基于阈值分割的基本逻辑应该是可以将所需要的目标物提取出来(这一块在python的opencv操作记录11——阈值分割这一篇已经讲过了)。
  3. 分割完之后再通过opencv提取轮廓的方法将轮廓提取出来。
  4. 提取完轮廓之后,对每个轮廓求外接矩形。
  5. 利用业务特性对相应的轮廓做一些过滤操作。
  6. 将多个矩形做一个聚类,这里可以有多种聚类方案,可以先聚类再筛选,也可以根据某个逻辑确定一个质心,然后再根据这个质心再做聚类
  7. 然后就是调参工作了。

我自己的代码为:

int getCenter(cv::Mat img, cv::Rect& resultRect)
{cv::cvtColor(img, img, cv::COLOR_RGB2GRAY);// 阈值分割cv::threshold(img, img, 50, 255, cv::THRESH_BINARY);// 提取轮廓std::vector<cv::Mat> contours;cv::findContours(img, contours, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);// 逐步聚类的方法std::vector<float> xs, ys;// 初始化质心float centroid_x = 0.0f, centroid_y = 0.0f;// 找到第一个质心,我这里是使用面积最大的作为第一个质心,代码没有贴上来int maxIndex = 0;float maxSocre = 0.0f;// 迭代计算质心for (int i = 0; i < contours.size(); i++){score = cv::contourArea(contours[i]);// 判断是一个有效区域if (score > threshold_score){cv::Rect rect = cv::boundingRect(contours[i]);// 判断是否离中心比较远, 第一次不做判断if (abs(rect.x + (rect.width / 2) - centroid_x) > centroidThresholdX){continue;}if (abs(rect.y + (rect.height / 2) - centroid_y) > centroidThresholdY){continue;}// 纳入下一次的质心计算xs.push_back(rect.x + rect.width / 2);ys.push_back(rect.y + rect.height / 2);float tempCenterX = 0.0f;for (int x = 0; x < xs.size(); x++){tempCenterX += xs[x];}centroid_x = tempCenterX / xs.size();float tempCenterY = 0.0f;for (int y = 0; y < ys.size(); y++){tempCenterY += ys[y];}centroid_y = tempCenterY / ys.size();}}for(int z = 0; z < xs.size(); z++){ if (xs[z] < minX){minX = xs[z];}if (xs[z] > maxX){maxX = xs[z];}if (ys[z] < minY){minY = ys[z];}if (ys[z] > maxY){maxY = ys[z];}}std::cout << "maxX:" << maxX << "minX:" << minX << "maxY:" << maxY << "minY:" << minY << std::endl;resultRect.x = minX;resultRect.y = minY;resultRect.width = maxX - minX;resultRect.height = maxY - minY;return 0;
}

最后的结果是:

调整的距离就是这个矩形的中央到整个图像的中央坐标了。


http://www.ppmy.cn/news/1534561.html

相关文章

uniapp中uni.request的统一封装 (ts版)

文章目录 前言一、我们为什么要去封装&#xff1f;二、具体实现1.创建一个请求封装文件&#xff1a;2.封装 uni.request&#xff1a;3.如何去使用&#xff1f; 总结 前言 在uniapp中如何去更简洁高效的发送我们的请求&#xff0c;下面就介绍了uni.request()二次封装。 一、我们…

C++引用指针大对比

文章目录 相似之处不同之处**语法上的区别****是否允许重新绑定****空值&#xff08;Null&#xff09;状态****内存地址****初始化要求****与数组的关系** 总结何时使用引用 vs 指针&#xff1f; 相似之处 间接访问对象&#xff1a;引用和指针都可以通过它们来间接访问和操作某…

rabbitMq------连接管理模块

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言管理的字段连接内存管理对象 前言 我们的网络通信框架使用的muduo库&#xff0c;而在mudu库中是已经有了连接的概念&#xff0c;但是我们呢还有一个信道的概念…

02:(寄存器开发)流水灯/按键控制LED

寄存器开发 1、LED流水灯2、按键控制LED 1、LED流水灯 通过第一章的学习&#xff0c;我们已然知晓了LED的点亮和熄灭的方式&#xff0c;下面学习流水灯的制作流程。 流水灯呈现的样子&#xff1a;就是第一个LED灯点亮&#xff0c;延迟一段时间&#xff0c;第一个LED灯熄灭第二…

UE4_Niagara基础实例—5、骨架网格体表面生成粒子及过滤骨骼位置生成粒子

效果图&#xff1a; 步骤&#xff1a; 1、学习了静态网格体位置生成粒子之后这个就比较简单了&#xff0c;把粒子生成位置更改为SkeletalMeshLocation。 2、小白人的骨骼网格体为&#xff1a; 你会发现骨骼的每一个节点处都有粒子产生。 3、我们还可以修改骨骼采样类型 4、我们…

React表单:formik、final-form和react-hook-form

表单无处不在&#xff0c;它是每个网站的必备部分。在用React构建web应用时&#xff0c;处理表单是不可避免的。 你可以选择自己的方式来处理&#xff0c;或者选择社区中现成的库。然而&#xff0c;当你选择一个第三方库时&#xff0c;你会立即面临一个问题&#xff1a;有太多的…

2.4 Spring系列教程4-Spring的数据库编程

数据库用于处理持久化业务产生的数据&#xff0c;应用程序在运行过程中经常要操作数据库。一般情况下&#xff0c;数据库的操作由持久层来实现。作为扩展性较强的一站式开发框架&#xff0c;Spring也提供了持久层Spring JDBC功能&#xff0c;Spring JDBC可以管理数据库连接资源…

黑马程序员pink 教js ,查漏补缺版,耗时4天

JS基础-D1 变量类型 1.js编程语言&#xff0c;html标记语言 2.不用jdk&#xff0c;运行在浏览器 3.交互&#xff0c;用户点击1就数值1 4.服务端编程&#xff0c;nodejs 5.js遵循ecma-script的语法规范 6.js由ecma-s和dom bom组成&#xff0c;或者也可以叫做ecma-s和weba…