分水岭算法分割和霍夫变换识别图像中的硬币
首先解释一下第一种分水岭算法:
一、分水岭算法
分水岭算法是一种基于拓扑学的图像分割技术,广泛应用于图像处理和计算机视觉领域。它将图像视为一个拓扑表面,其中亮度值代表高度。算法的目标是通过模拟雨水从山顶流到山谷的过程,将图像分割成若干独立的区域。
分水岭算法的步骤和原理:
-
距离变换:
- 首先对图像进行预处理,将图像转化为灰度图,并进行二值化处理(如Otsu算法)。
- 对二值图像应用距离变换,计算每个前景像素到最近的背景像素的距离,生成距离图。距离变换后的图像可以看作是一幅"地形图",前景像素的距离值越大,代表的高度越高。
-
寻找局部极大值:
- 在距离图中找到局部极大值点。这些点通常位于目标物体的中心位置,将作为初始标记。局部极大值点是那些比其邻域像素值更大的点。
-
创建标记图:
- 创建一个与原始图像大小相同的标记图,将局部极大值点的位置赋值为不同的标签(从1开始编号),其余区域标记为0。
-
应用分水岭算法:
- 将距离图的负值作为输入图像,标记图作为初始标记,应用分水岭算法。分水岭算法通过模拟水从局部极大值点流向低谷的过程,不断合并像素,形成分割区域。
- 在这个过程中,水从局部极大值点流向低谷,如果两个不同的标签的水流在某处相遇,该处将被标记为边界。
-
生成分割结果:
- 分水岭算法最终会将图像分割成多个区域,每个区域对应一个标签。边界区域通常被标记为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)
- 计算距离变换:
ndimage.distance_transform_edt(thresh)计算每个前景像素到最近背景像素的欧几里得距离,生成距离图D。 - 寻找局部极大值:
peak_local_max(D, footprint=np.ones((3, 3)), min_distance=40, labels=thresh)在距离图中寻找局部极大值,这些点将作为初始标记。 - 创建标记图:
markers初始化为全零矩阵,将局部极大值点的位置赋值为不同的标签。 - 应用分水岭算法:
labels = watershed(-D, markers, mask=thresh)使用分水岭算法对距离图的负值进行分割,生成标签图labels。
通过以上步骤,分水岭算法将输入图像分割成若干独立区域,每个区域代表一个目标物体。
以检测这张图为例子:

使用分水岭算法流程如下:
-
读取图像并应用均值漂移滤波:
- 使用
cv2.imread读取输入图像。 - 使用
cv2.pyrMeanShiftFiltering对图像进行均值漂移滤波,平滑图像并减少噪点。
- 使用
-
转换为灰度图并二值化:
- 使用
cv2.cvtColor将平滑后的图像转换为灰度图。 - 使用
cv2.threshold结合 Otsu 算法进行自动阈值二值化,将图像转换为二值图像。
- 使用
-
计算欧几里得距离并找到局部峰值:
- 使用
ndimage.distance_transform_edt计算每个二值像素到最近零像素的欧几里得距离,生成距离变换图。 - 使用
peak_local_max找到距离图中的局部峰值,这些峰值将作为分水岭算法的初始标记。
- 使用
-
创建标记数组并应用分水岭算法:
- 创建一个与二值图像大小相同的标记数组
markers,将局部峰值的位置赋值为不同的标签。 - 使用
watershed函数进行分水岭算法,将图像分割成不同区域,每个区域对应一个硬币。
- 创建一个与二值图像大小相同的标记数组
-
遍历分割出的不同区域,绘制轮廓和标签:
- 遍历分割后的标签,跳过背景标签(标签为0)。
- 为每个硬币创建一个掩码图像,设置对应标签区域为白色,其余区域为黑色。
- 使用
cv2.findContours查找掩码图像中的轮廓,并找到最大的轮廓(即硬币区域)。 - 使用
cv2.minEnclosingCircle计算最小外接圆的圆心坐标和半径。 - 在原始图像上绘制圆形轮廓和标签。
-
显示最终结果图像:
- 使用
cv2.imshow显示处理后的图像。 - 使用
cv2.waitKey和cv2.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)是霍夫变换的一个具体应用,用于检测图像中的圆形物体。
霍夫圆检测的原理和步骤:
-
边缘检测:
- 首先对图像进行边缘检测,常用的方法是Canny边缘检测。边缘检测可以提取出图像中的显著边缘,减少数据量并突出目标物体的轮廓。
-
参数空间定义:
- 在检测圆的过程中,需要定义圆的参数空间。一个圆由三个参数定义:圆心坐标 (x, y) 和半径 r。霍夫圆检测将在参数空间中搜索圆的可能位置和大小。
-
投票累加:
-
在边缘检测后的二值图像中,每个边缘点 (x, y) 都会在参数空间中投票支持可能的圆心和半径组合。具体而言,对于每个边缘点 (x, y) 和每个可能的半径 r,可以根据圆的方程计算圆心坐标 (a, b):
![[
a = x - r \cdot \cos(\theta)
]
[
b = y - r \cdot \sin(\theta)
]](https://img-blog.csdnimg.cn/direct/aa07b43e88904dd28b68c0d80898ff28.png)
-
在参数空间中累加 (a, b) 的投票次数。
-
-
检测局部最大值:
- 在参数空间中,投票次数最多的位置即为最可能的圆心和半径组合。通过检测参数空间中的局部最大值,确定圆的存在和位置。
-
绘制检测到的圆:
- 根据检测到的圆心坐标和半径,在原始图像上绘制圆形轮廓。
示例代码:
以下是一个使用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()
代码详解:
-
读取图像并转换为灰度图:
image = cv2.imread('image.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) -
应用高斯模糊:
- 使用高斯模糊(Gaussian Blur)来平滑图像,减少噪声。
blurred = cv2.GaussianBlur(gray, (9, 9), 2) -
使用霍夫圆检测:
- 调用
cv2.HoughCircles函数进行霍夫圆检测。参数解释如下:blurred:输入的灰度图像。cv2.HOUGH_GRADIENT:检测方法,使用梯度信息。dp=1.2:累加器分辨率与图像分辨率的反比关系。minDist=20:检测到的圆之间的最小距离。param1=50:Canny边缘检测的高阈值。param2=30:累加器阈值,用于检测圆的阈值,越小越容易检测到不明显的圆。minRadius=15和maxRadius=30:检测圆的半径范围。
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()
通过上述步骤和代码,霍夫圆检测可以在图像中自动识别和绘制圆形目标。
识别图中硬币的完整代码如下:
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()
检测结果如下:

相关文章:
分水岭算法分割和霍夫变换识别图像中的硬币
首先解释一下第一种分水岭算法: 一、分水岭算法 分水岭算法是一种基于拓扑学的图像分割技术,广泛应用于图像处理和计算机视觉领域。它将图像视为一个拓扑表面,其中亮度值代表高度。算法的目标是通过模拟雨水从山顶流到山谷的过程࿰…...
什么是AVIEXP提前发货通知?
EDI(电子数据交换)报文是一种用于电子商务和供应链管理的标准化信息传输格式。AVIEXP 是一种特定类型的 EDI 报文,用于传输提前发货通知信息。 AVIEXP 报文简介 AVIEXP 是指 Advanced Shipping Notification提前发货通知报文,用…...
Python 之SQLAlchemy使用详细说明
目录 1、SQLAlchemy 1.1、ORM概述 1.2、SQLAlchemy概述 1.3、SQLAlchemy的组成部分 1.4、SQLAlchemy的使用 1.4.1、安装 1.4.2、创建数据库连接 1.4.3、执行原生SQL语句 1.4.4、映射已存在的表 1.4.5、创建表 1.4.5.1、创建表的两种方式 1、使用 Table 类直接创建表…...
就业班 第四阶段(docker) 2401--5.29 day3 Dockerfile+前后段项目若依ruoyi
通过Dockerfile创建镜像 Docker 提供了一种更便捷的方式,叫作 Dockerfile docker build命令用于根据给定的Dockerfile构建Docker镜像。docker build语法: # docker build [OPTIONS] <PATH | URL | ->1. 常用选项说明 --build-arg,设…...
【运维项目经历|026】Redis智能集群构建与性能优化工程
🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 🏅阿里云ACE认证高级工程师 🏅阿里云开发者社区专家博主 💊交流社区:CSDN云计算交流社区欢迎您的加入! 目…...
Linux编程for、while循环if判断以及case语句用法
简介 语法描述if条件语句if else条件判断语句if else-if else多条件判断语句for循环执行命令while循环执行命令until直到条件为真时停止循环case ... esac多选择语句break跳出循环continue跳出当前循环 1. for 循环 for语句,定量循环,可以遍历一个列表…...
docker命令 docker ps -l (latest)命令在 Docker 中用于列出最近一次创建的容器
文章目录 12345 1 docker ps -l 命令在 Docker 中用于列出最近一次创建的容器。具体来说: docker ps:这个命令用于列出当前正在运行的容器。-l 或 --latest:这个选项告诉 docker ps 命令只显示最近一次创建的容器,不论该容器当前…...
inflight 守恒和带宽资源守恒的有效性
接着昨天的问题,inflight 守恒的模型一定存在稳定点吗?并不是。如果相互抑制强度大于自我抑制强度,系统也会跑飞: 模拟结果如下: 所以一定要记得 a < b。 比对前两个图和后两个图的 a,b 参数关系&am…...
短视频直播教学课程小程序的作用是什么
只要短视频/直播做的好,营收通常都不在话下,近些年,线上自媒体行业热度非常高,每条细分赛道都有着博主/账号,其各种优势条件下也吸引着其他普通人冲入。 然无论老玩家还是新玩家,面对平台不断变化的规则和…...
Open AI又出王炸GPT-4,目测一大波人的饭碗要碎了...
前言 在科技的惊涛骇浪中,每一次技术的飞跃都预示着新时代的曙光。近日,Open AI公司再次震撼业界,推出了其最新力作——GPT-4,这款被誉为“王炸”的语言模型,以其前所未有的智能水平和创造力,不仅在技术圈…...
8086 汇编笔记(八):转移指令的原理
一、操作符 offset 操作符offset在汇编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址 codesg segmentstart: mov ax,offset start ;相当于 mv ax,0s: mov ax,offset s ;相当于 mv ax,3codesg endsend start 二、jmp 指令 jmp为无条件…...
win 系统 cmd 命令从私库上传,下载jar包
1. 确保maven环境变量或者maven安装无误; 2.私库下载 命令 mvn dependency:get -DgroupId<your_group_id> -DartifactId<your_artifact_id> -Dversion<your_version> -Dpackagingjar -Dfile<path_to_your_jar_file> -Durl<your_privat…...
dots_image 增强图像中的圆点特征
dots_image 增强图像中的圆点特征 1. dot_image 有什么用途?2. 点状字符的特征增强3. Halcon代码 1. dot_image 有什么用途? Enhance circular dots in an image. 这个算子可以增强图像中的圆点特征,例如下面的例子。 2. 点状字符的特征增强…...
代码随想录算法训练营第十五天| 110.平衡二叉树、 257. 二叉树的所有路径、404.左叶子之和
110.平衡二叉树 题目链接:110.平衡二叉树 文档讲讲:代码随想录 状态:还可以 思路:计算左右子树的深度差,递归判断左右子树是否符合平衡条件 题解: public boolean isBalanced(TreeNode root) {if (root n…...
MSP430单片机控制流水灯,Proteus仿真
作品功能 本项目利用MSP430单片机控制一个简单的流水灯,通过按键切换流水灯的模式。用户可以通过按键控制LED灯的方向,从左向右或从右向左依次点亮。 作品的硬件材料 MSP430单片机 具体型号:MSP430G2553 LED灯 数量:8个类型&…...
出售iPhone前的必做步骤:完全擦除个人数据的方法
当您准备在闲鱼上转售旧 iPhone、将其捐赠、送给朋友或通过 Apple 回收之前,您可能会选择执行“恢复”操作来擦除您的数据。但请注意,这一操作并不能真正删除设备中的数据。被“删除”或“格式化”的数据实际上仍存在于 iPhone 中,只是被系统…...
npm yarn 更换国内源以及node历史版本下载地址
npm 更换国内源 npm config set registryhttps://registry.npmmirror.com npm config set electron_mirrorhttps://registry.npmmirror.com/electron/yarn 更换国内源 yarn config set registry https://registry.npmmirror.comnode历史版本下载地址 https://nodejs.org/dow…...
微信小程序手机号码授权登录
文章目录 一、微信小程序开发二、使用步骤1.前端代码2.后台配置3.后台代码 总结 一、微信小程序开发 目前个人的小程序无法使用手机号码授权登录,可以使用测试号进行开发 二、使用步骤 1.前端代码 代码如下(示例): <butto…...
【网络编程开发】1.网络结构 2.IP地址与端口号 3.字节序
网络编程开发 两台计算机要互相传送文件需解决很多问题: 必须有一条传送数据的通路。发起方必须激活通路。要告诉网络如何识别接收方。发起方要清楚对方是否已开机,且与网络连接正常。发起方要清楚对方是否准备好接收和存储文件。若文件格式不兼容&…...
读取文件
自学python如何成为大佬(目录):自学python如何成为大佬(目录)_利用python语言智能手机的默认语言实战一-CSDN博客 在Python中打开文件后,除了可以向其写入或追加内容,还可以读取文件中的内容。读取文件内容主要分为以下几种情况: 1 读取指…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
