分水岭算法分割和霍夫变换识别图像中的硬币

首先解释一下第一种分水岭算法:

一、分水岭算法

分水岭算法是一种基于拓扑学的图像分割技术,广泛应用于图像处理和计算机视觉领域。它将图像视为一个拓扑表面,其中亮度值代表高度。算法的目标是通过模拟雨水从山顶流到山谷的过程,将图像分割成若干独立的区域。

分水岭算法的步骤和原理:

  1. 距离变换

    • 首先对图像进行预处理,将图像转化为灰度图,并进行二值化处理(如Otsu算法)。
    • 对二值图像应用距离变换,计算每个前景像素到最近的背景像素的距离,生成距离图。距离变换后的图像可以看作是一幅"地形图",前景像素的距离值越大,代表的高度越高。
  2. 寻找局部极大值

    • 在距离图中找到局部极大值点。这些点通常位于目标物体的中心位置,将作为初始标记。局部极大值点是那些比其邻域像素值更大的点。
  3. 创建标记图

    • 创建一个与原始图像大小相同的标记图,将局部极大值点的位置赋值为不同的标签(从1开始编号),其余区域标记为0。
  4. 应用分水岭算法

    • 将距离图的负值作为输入图像,标记图作为初始标记,应用分水岭算法。分水岭算法通过模拟水从局部极大值点流向低谷的过程,不断合并像素,形成分割区域。
    • 在这个过程中,水从局部极大值点流向低谷,如果两个不同的标签的水流在某处相遇,该处将被标记为边界。
  5. 生成分割结果

    • 分水岭算法最终会将图像分割成多个区域,每个区域对应一个标签。边界区域通常被标记为0。

分水岭算法的优点和缺点:

优点

  • 分水岭算法可以生成闭合的区域边界,适用于目标物体具有明确边界的图像。
  • 算法可以自动确定分割区域的数量,无需事先设定。

缺点

  • 对噪声和边缘模糊敏感,容易产生过分割,即将一个目标物体分割成多个区域。
  • 需要进行预处理以减少噪声和增强边缘(如均值漂移滤波)。

示例代码解释:

# 计算每个二值像素到最近零像素的精确欧几里得距离, 然后找到此距离图中的局部峰值
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, footprint=np.ones((3, 3)), min_distance=40, labels=thresh)# 根据找到的局部峰值创建标记数组, 标记数组的值对应于每个硬币的序号
markers = np.zeros_like(thresh, dtype=np.int32)
markers[tuple(localMax.T)] = np.arange(1, len(localMax) + 1)# 应用分水岭算法, 将图像分割为不同的区域
labels = watershed(-D, markers, mask=thresh)
  1. 计算距离变换ndimage.distance_transform_edt(thresh) 计算每个前景像素到最近背景像素的欧几里得距离,生成距离图 D
  2. 寻找局部极大值peak_local_max(D, footprint=np.ones((3, 3)), min_distance=40, labels=thresh) 在距离图中寻找局部极大值,这些点将作为初始标记。
  3. 创建标记图markers 初始化为全零矩阵,将局部极大值点的位置赋值为不同的标签。
  4. 应用分水岭算法labels = watershed(-D, markers, mask=thresh) 使用分水岭算法对距离图的负值进行分割,生成标签图 labels

通过以上步骤,分水岭算法将输入图像分割成若干独立区域,每个区域代表一个目标物体。

以检测这张图为例子:
在这里插入图片描述

使用分水岭算法流程如下:

  1. 读取图像并应用均值漂移滤波

    • 使用 cv2.imread 读取输入图像。
    • 使用 cv2.pyrMeanShiftFiltering 对图像进行均值漂移滤波,平滑图像并减少噪点。
  2. 转换为灰度图并二值化

    • 使用 cv2.cvtColor 将平滑后的图像转换为灰度图。
    • 使用 cv2.threshold 结合 Otsu 算法进行自动阈值二值化,将图像转换为二值图像。
  3. 计算欧几里得距离并找到局部峰值

    • 使用 ndimage.distance_transform_edt 计算每个二值像素到最近零像素的欧几里得距离,生成距离变换图。
    • 使用 peak_local_max 找到距离图中的局部峰值,这些峰值将作为分水岭算法的初始标记。
  4. 创建标记数组并应用分水岭算法

    • 创建一个与二值图像大小相同的标记数组 markers,将局部峰值的位置赋值为不同的标签。
    • 使用 watershed 函数进行分水岭算法,将图像分割成不同区域,每个区域对应一个硬币。
  5. 遍历分割出的不同区域,绘制轮廓和标签

    • 遍历分割后的标签,跳过背景标签(标签为0)。
    • 为每个硬币创建一个掩码图像,设置对应标签区域为白色,其余区域为黑色。
    • 使用 cv2.findContours 查找掩码图像中的轮廓,并找到最大的轮廓(即硬币区域)。
    • 使用 cv2.minEnclosingCircle 计算最小外接圆的圆心坐标和半径。
    • 在原始图像上绘制圆形轮廓和标签。
  6. 显示最终结果图像

    • 使用 cv2.imshow 显示处理后的图像。
    • 使用 cv2.waitKeycv2.destroyAllWindows 控制显示窗口。

上述流程通过图像平滑、二值化、距离变换、局部峰值检测和分水岭算法,实现了对硬币图像的分割,并在分割后的图像上绘制了硬币的轮廓和编号标签。
完整代码如下:

import numpy as np
import cv2
from skimage.feature import peak_local_max
from skimage.segmentation import watershed
from scipy import ndimage
import imutils# 读取图像并应用均值漂移滤波来平滑图像,减少噪点
image = cv2.imread('/coins/1.jpg')
shifted = cv2.pyrMeanShiftFiltering(image, 21, 51)# 将图像转换为灰度图,然后使用Otsu算法自动确定阈值进行二值化
gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]# 计算每个二值像素到最近零像素的精确欧几里得距离,然后找到此距离图中的局部峰值
# 这些峰值将作为分水岭算法的初始标记
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, footprint=np.ones((3, 3)), min_distance=40, labels=thresh)# 根据找到的局部峰值创建标记数组,标记数组的值对应于每个硬币的序号
markers = np.zeros_like(thresh, dtype=np.int32)
markers[tuple(localMax.T)] = np.arange(1, len(localMax) + 1)# 应用分水岭算法,将图像分割为不同的区域
labels = watershed(-D, markers, mask=thresh)# 遍历分割出的不同区域,绘制出每个硬币的轮廓和标签
for label in np.unique(labels):if label == 0:continue# 创建一个掩码图像,将当前标签对应的区域设置为白色,其他区域设置为黑色mask = np.zeros(gray.shape, dtype="uint8")mask[labels == label] = 255# 查找掩码图像中的轮廓,并找到最大的轮廓(即硬币区域)cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)c = max(cnts, key=cv2.contourArea)# 计算最小外接圆的圆心坐标和半径((x, y), r) = cv2.minEnclosingCircle(c)# 在原始图像上绘制圆形轮廓和标签cv2.circle(image, (int(x), int(y)), int(r), (0, 255, 0), 2)cv2.putText(image, "{}".format(label), (int(x) - 10, int(y)),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)# 显示最终的结果图像
cv2.imshow("Output", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

分割结果如下:
在这里插入图片描述

二、 霍夫变换

霍夫变换(Hough Transform)是图像处理中的一种重要技术,用于检测图像中的几何形状。霍夫圆检测(Hough Circle Transform)是霍夫变换的一个具体应用,用于检测图像中的圆形物体。

霍夫圆检测的原理和步骤:

  1. 边缘检测

    • 首先对图像进行边缘检测,常用的方法是Canny边缘检测。边缘检测可以提取出图像中的显著边缘,减少数据量并突出目标物体的轮廓。
  2. 参数空间定义

    • 在检测圆的过程中,需要定义圆的参数空间。一个圆由三个参数定义:圆心坐标 (x, y) 和半径 r。霍夫圆检测将在参数空间中搜索圆的可能位置和大小。
  3. 投票累加

    • 在边缘检测后的二值图像中,每个边缘点 (x, y) 都会在参数空间中投票支持可能的圆心和半径组合。具体而言,对于每个边缘点 (x, y) 和每个可能的半径 r,可以根据圆的方程计算圆心坐标 (a, b):
      [
a = x - r \cdot \cos(\theta)
]
[
b = y - r \cdot \sin(\theta)
]

    • 在参数空间中累加 (a, b) 的投票次数。

  4. 检测局部最大值

    • 在参数空间中,投票次数最多的位置即为最可能的圆心和半径组合。通过检测参数空间中的局部最大值,确定圆的存在和位置。
  5. 绘制检测到的圆

    • 根据检测到的圆心坐标和半径,在原始图像上绘制圆形轮廓。

示例代码:

以下是一个使用OpenCV进行霍夫圆检测的示例代码:

import cv2
import numpy as np# 读取图像
image = cv2.imread('image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 应用高斯模糊,减少噪声
blurred = cv2.GaussianBlur(gray, (9, 9), 2)# 使用霍夫圆检测
circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=20,param1=50, param2=30, minRadius=15, maxRadius=30)# 如果检测到圆
if circles is not None:circles = np.round(circles[0, :]).astype("int")for (x, y, r) in circles:# 绘制圆的轮廓cv2.circle(image, (x, y), r, (0, 255, 0), 4)# 绘制圆心cv2.rectangle(image, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)# 显示结果图像
cv2.imshow("output", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

代码详解:

  1. 读取图像并转换为灰度图

    image = cv2.imread('image.jpg')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
  2. 应用高斯模糊

    • 使用高斯模糊(Gaussian Blur)来平滑图像,减少噪声。
    blurred = cv2.GaussianBlur(gray, (9, 9), 2)
    
  3. 使用霍夫圆检测

    • 调用 cv2.HoughCircles 函数进行霍夫圆检测。参数解释如下:
      • blurred:输入的灰度图像。
      • cv2.HOUGH_GRADIENT:检测方法,使用梯度信息。
      • dp=1.2:累加器分辨率与图像分辨率的反比关系。
      • minDist=20:检测到的圆之间的最小距离。
      • param1=50:Canny边缘检测的高阈值。
      • param2=30:累加器阈值,用于检测圆的阈值,越小越容易检测到不明显的圆。
      • minRadius=15maxRadius=30:检测圆的半径范围。
    circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=20,param1=50, param2=30, minRadius=15, maxRadius=30)
    
  4. 绘制检测到的圆

    • 如果检测到圆,将其绘制在原始图像上。
    if circles is not None:circles = np.round(circles[0, :]).astype("int")for (x, y, r) in circles:cv2.circle(image, (x, y), r, (0, 255, 0), 4)cv2.rectangle(image, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
    
  5. 显示结果图像

    • 显示绘制了圆的结果图像。
    cv2.imshow("output", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

通过上述步骤和代码,霍夫圆检测可以在图像中自动识别和绘制圆形目标。
识别图中硬币的完整代码如下:

import cv2
import numpy as np# 读取图像并转换为灰度图像
image = cv2.imread('/coins/1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 应用高斯模糊
gray = cv2.GaussianBlur(gray, (15, 15), 0)# 使用霍夫圆变换检测圆
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1.2, minDist=50, param1=50, param2=30, minRadius=20,maxRadius=60)# 确保至少检测到一个圆
if circles is not None:circles = np.round(circles[0, :]).astype("int")for (i, (x, y, r)) in enumerate(circles):# 绘制圆圈和中心点cv2.circle(image, (x, y), r, (0, 255, 0), 2)cv2.putText(image, str(i + 1), (x - 10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)# 显示最终结果图像
cv2.imshow("Detected Coins", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

检测结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/343561.html

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

相关文章

代码解读 | Hybrid Transformers for Music Source Separation[03]

一、背景 接着上一篇代码解读 | Hybrid Transformers for Music Source Separation[02]文章,继续对Hybrid Transformer Demucs 代码进行解读。 解读目标:明确数据从进入算法,在算法内部,以及在算法输出 这三个阶段中 数据的大小是…

如何执行VMware P2V迁移|VMware Converter和替代方案

VMware中的P2V是什么? 我们常说的VMware P2V其实指的就是“物理到虚拟”,将工作负载从物理机器转换或迁移到虚拟机(VM)的过程,能够使您无需从头开始费力地创建和配置新虚拟机。 就像您可以使用Disk2vhd执行Hyper-V物理…

如何在virtualbox上安装Linux系统(centerOS)

提示:共同学习 注意:一定要在BIOS中的虚拟化打开。 文章目录 第一步: 第一步: 启动 、显示开启 centos基础安装 ​ ​

九大微服务监控工具详解

Prometheus Prometheus 是一个开源的系统监控、和报警工具包,Prometheus 被设计用来监控“微服务架构”。 主要解决: 监控和告警:Prometheus 可以对系统、和应用程序进行实时监控,并在出现问题时发送告警;数据收集和…

超详细的java Comparable,Comparator接口解析

前言 Hello大家好呀,在java中我们常常涉及到对象的比较,不同于基本数据类型,对于我们的自定义对象,需要我们自己去建立比较标准,例如我们自定义一个People类,这个类有name和age两个属性,那么问…

Bev 车道标注方案及复杂车道线解决

文章目录 1. 数据采集方案1.1 传感器方案1.2 数据同步2. 标注方案2.1 标注注意项2.2 4d 标注(时序)2.2.1 4d标签制作2.2.2 时序融合的作用2.2.2.1 时序融合方式2.2.2.2 时序融合难点2.2.2.2 时序实际应用情况3. 复杂车道线解决3.1 split 和merge车道线的解决3.2 大曲率或U形车道…

自然语言处理(NLP)—— 语言检测器

1. 文章概述 1.1 目的 在本篇文章中,我们将构建一个语言检测器,这是一个能够识别文本语言的简单分类器。这是一个能够识别文本是用哪种语言写的程序。想象一下,你给这个程序一段文字,它就能告诉你这是英语、法语还是其他语言。 …

C语言过度C++语法补充(面向对象之前语法)

目录 1. C相较于C语言新增的语法 0. C 中的输入输出 1. 命名空间 1. 我们如何定义一个命名空间? 2. 如何使用一个命名空间 3. 命名空间中可以定义什么? 4. 在 相同或者不同 的文件中如果出现 同名的命名空间 会如何? 5. 总结~~撒花~~…

优维「Easy分析」:一款故障根因分析小神器

背 景 随着微服务架构的普及,现代企业的IT基础设施已经变得越来越复杂。单一的服务可能有多个下游依赖,而这些依赖又可能有自己的子依赖,和主机资源的依赖。在这样的环境中,当某个服务发生故障,确定具体的原因变得尤为…

【Linux】The server quit without updating PID file的几种解决方案

😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 🤓 同时欢迎大家关注其他专栏,我将分享Web前后端开发、人工智能、机器学习、深…

微服务架构-微服务实施

目录 一、概述 二、微服务拆分 2.1 概述 2.2 拆分原则 2.3 拆分方法 2.3.1 以数据为维度进行拆分 2.3.2 按照使用场景拆分 2.3.3 重要和非重要的拆分 2.3.4 变和不变的拆分 三、微服务通信 3.1 概述 3.2 微服务通信方式选择 3.3 微服务编排 3.4 API接口设计 3.5 …

C++基础与深度解析 | 类与面向对象编程 | 数据成员 | 成员函数 | 访问限定符与友元 | 构造、析构成员函数 | 字面值类、成员指针与bind交互

文章目录 一、结构体与对象聚合二、成员函数(方法)三、访问限定符与友元1.访问限定符2.友元(慎用) 四、构造、析构与复制成员函数1.构造函数2.析构函数3.补充 五、字面值类,成员指针与bind交互1.字面值类2.成员指针3.b…

【MATLAB源码-第224期】基于matlab的快跳频系统仿真采用4FSK,模拟了单音干扰,宽带干扰以及部分频带干扰,输出误码率曲线以及各节点图像。

操作环境: MATLAB 2022a 1、算法描述 跳频通信系统概述 跳频通信系统是一种通过快速切换载波频率来进行信息传输的无线通信技术。它在军事和商业通信中广泛应用,具有较强的抗干扰和抗截获能力。系统设计主要包括信号调制、跳频序列生成、信道模拟以及…

Java 初识

Java 的发展历程 Sun 公司。 Oracle 公司。 普通版本,也叫过渡版本。 正式版本,也叫长期支持版本(LTS)。 Java SE,Java EE,Java ME Java 技术体系分为三个平台:Java SE,Java EE&a…

G5 - Pix2Pix理论与实战

🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 目录 理论知识图像翻译CGANU-NetPix2Pix损失函数模型结构生成器差别器 模型效果总结与心得体会 理论知识 前面已经学习了GAN与CGAN,这节开始学习P…

记一次Linux下Docker镜像服务器磁盘空间清理

我们开发环境Jenkins构建项目时报服务器磁盘空间不足,导致项目自动化构建部署失败, Docker镜像服务器磁盘空间清理我们做了多次了,之前在清理Docker镜像服务器时走了不少弯路,查了不少Docker镜像服务器空间清理,都大同…

AI大数据处理与分析实战--体育问卷分析

AI大数据处理与分析实战–体育问卷分析 前言:前一段时间接了一个需求,使用AI进行数据分析与处理,遂整理了一下大致过程和大致简要结果(更详细就不方便放了)。 文章目录 AI大数据处理与分析实战--体育问卷分析一、数据…

部署kubesphere报错

安装kubesphere报错命名空间terminted [rootk8smaster ~]# kubectl apply -f kubesphere-installer.yaml Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16, unavailable in v1.22; use apiextensions.k8s.io/v1 CustomResourceDefini…

LabVIEW阀性能试验台测控系统

本项目开发的阀性能试验台测控系统是为满足国家和企业相关标准而设计的,主要用于汽车气压制动系统控制装置和调节装置等产品的综合性能测试。系统采用工控机控制,配置电器控制柜,实现运动控制、开关量控制及传感器信号采集,具备数…

【数据结构初阶】--- 顺序表

顺序表,好像学C语言时从来没听过,实际上就是给数组穿了层衣服,本质是一模一样的。 这里的顺序表实际是定义了一个结构体,设计各种函数来实现它的功能,比如说数组中的增删改查插入,这些基本操作其实平时就会…