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

news/2024/10/3 17:14:29 标签: opencv, 聚类, 人工智能, 图像处理

文章目录


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

就类似于下面的图像:

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

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

  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.niftyadmin.cn/n/5688739.html

相关文章

DolphinScheduler 资源中心无法上传大文件

服务&#xff1a;dolphinscheduler 版本&#xff1a;v3.16 问题描述&#xff1a;资源中心-文件管理中使用文件上传是出现中断或上传失败 排除思路&#xff1a; 测试小文件或其他类型文件时是否正常&#xff1b;F12查看接口调用成功以及失败时的对比&#xff0c;发现接口调用…

几个十六进制位表示一个字节

在计算机中一个二进制位表示一个bite位&#xff0c;bite就是二进制中最小的一位。那么什么是一字节呢&#xff1f;一个字节就是8个bite位 二进制位 顾名思义&#xff0c;二进制位就只能用1和0进行表示&#xff0c;假如我要存放数字2&#xff0c;并用二进制位进行表示&#xff…

简单介绍Wiki和历史

Wiki 是一种基于网络的协作工具&#xff0c;它允许多个用户创建、编辑和分享信息。Wiki 的特点是页面内容可以由用户自由修改&#xff0c;并且这些修改会立即生效&#xff0c;促进了集体协作和知识共享。Wiki 的本质是一种内容管理系统&#xff0c;支持版本控制&#xff0c;使得…

Kotlin 处理字符串和正则表达式(二十一)

导读大纲 1.1 处理字符串和正则表达式1.1.1 分割字符串1.1.2 正则表达式和三引号字符串1.1.3 多行三引号字符串IntelliJ IDEA 和 Android Studio 中三重引号字符串内部的语法高亮显示 1.1 处理字符串和正则表达式 Kotlin 字符串与 Java 字符串完全相同 可以将 Kotlin 代码中创建…

Microsoft 解釋修改後的 Recall 將如何保障隱私與安全

Microsoft 為 Copilot AI 電腦推出的 Recall 功能&#xff0c;本意是藉由定期進行螢幕截圖&#xff0c;並分析上面的資訊&#xff0c;來協助用戶找到查看過的網頁、工作過的文件等各種資訊。然而雖然立意很好&#xff0c;但 Microsoft 推出之初似乎完全沒有考慮到用戶的隱私安全…

RTSP作为客户端 推流 拉流的过程分析

之前写过一个 rtsp server 作为服务端的简单demo 这次分析下 rtsp作为客户端 推流和拉流时候的过 A.作为客户端拉流 TCP方式 1.Client发送OPTIONS方法 Server回应告诉支持的方法 2.Client发送DESCRIPE方法 这里是从海康摄像机拉流并且设置了用户名密码 Server回复未认证 3.客…

ISA-95制造业中企业和控制系统的集成的国际标准-(5)

ISA-95 文章目录 ISA-95ISA-95与工业互联网一、工业互联网在哪里&#xff1f;二、维护自动化金字塔 ISA-95与工业互联网 ISA95作为指导性原则&#xff0c;自动化的阶段构建了以人和业务流程为中心的生产组织方式&#xff0c;极大的提高了生产的效率和灵活性&#xff0c;也满足…

MongoDB伪分布式部署(mac M2)

1. 序言 本博客是上一博客的进阶版&#xff1a;mac M2安装单机版 MongoDB 7.x&#xff0c;上一博客可以看做是单机、单节点部署MongoDB本博客将介绍单机、多服务部署MongoDB&#xff0c;实际就是伪分布式部署 2. 副本集(Replica Set)方式部署 2.1 什么是副本集&#xff1f; …