使用OpenCV-python提取图片中的硬币

本文介绍了如何使用OpenCV-Python从图片中提取硬币。首先对图片进行二值化和高斯滤波处理,接着通过边缘检测找到硬币边缘,利用边缘坐标确定硬币所在的矩形并创建蒙版,最后进行图像裁切,得到只包含硬币的图像。整个过程在Jupyter Notebook中完成。

大致思路如下

  1. 对图片做降噪滤波处理
  2. 寻找硬币的边缘
  3. 使用硬币边缘打造蒙版,并切割出图像

对应的方法如下

  1. 对图片进行二值化COLOR_BGR2GRAY处理,高斯滤波GaussianBlur处理。
  2. 使用canny算子进行边缘查找,并使用findContours方法提取边缘坐标点。
  3. 使用boundingRect方法找出硬币所在的矩形进行裁切,使用minEnclosingCircle找出包络圆作为蒙版,并使用bitwise_and隐藏背景。

首先导入必要的库,测试一下是否加载成功,注意cv2.waitKey(0)一定不要忘记!

import cv2 
import numpy as np

image = cv2.imread("coins.png")
cv2.imshow("if imread successfully",image)
cv2.waitKey(0)

在这里插入图片描述
接着进行灰度处理和模糊处理,在这之前需要关掉第一张图像

gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray,(11,11),0)
cv2.imshow("blurred",blurred)
cv2.waitKey(
<think>嗯,用户想用OpenCVPython来识别图像中的硬币并测量直径。首先,我需要理清楚整个流程应该是什么样的。根据之前的引用资料,特别是引用4提到的,测量物体大小通常需要找一个参照物,比如已知直径的硬币,通过计算像素与实际尺寸的比例来测量其他物体。所以用户的问题应该需要类似的步骤。 首先,可能需要图像预处理,比如灰度化、模糊处理,减少噪声。然后进行边缘检测,比如Canny边缘检测,或者用阈值分割来分离硬币和背景。接下来,可能需要形态学操作,比如开运算或闭运算,来去除小的噪声或填充孔洞,这样可以更准确地找到硬币的轮廓。 找到轮廓之后,需要用轮廓检测算法,比如findContours函数,获取每个硬币的轮廓。然后,对于每个轮廓,计算最小外接圆或者拟合椭圆,从而得到直径。不过需要确保轮廓是圆形的,可能还需要过滤掉一些非圆形的轮廓,比如通过面积或圆度来判断。 接下来是测量直径的关键步骤。根据引用4,需要有一个参照物,比如已知直径的硬币,假设在图像中存在这样的参照物,可以通过计算它的像素直径,然后得到每个像素对应的实际长度,从而用这个比例来测量其他硬币的实际直径。例如,如果参照物在图像中的像素直径是100像素,实际直径是25mm,那么每个像素对应0.25mm。其他硬币的像素直径乘以这个比例就是实际直径。 然后,代码实现方面,可能需要用到OpenCV的函数,比如cv2.imread读取图片,cv2.cvtColor转灰度,cv2.GaussianBlur进行模糊,cv2.Canny边缘检测,或者cv2.threshold阈值处理。然后cv2.findContours找轮廓,cv2.minEnclosingCircle获取最小外接圆。计算直径后,再根据参照物的比例转换实际尺寸。 不过需要注意几点:首先,如何确保参照物被正确识别,可能需要用户将参照物单独放置或者通过某种方式标记。其次,图像可能存在透视变形,如果拍摄角度不是垂直的话,可能会影响直径的测量,这时候可能需要校正。但用户的问题可能假设图像是正面拍摄,没有明显变形。 另外,在代码中可能需要处理多个硬币的情况,遍历每个轮廓,排除过小或过大的区域,避免误检。比如通过面积过滤,或者使用轮廓的圆度(比如比较周长和面积,判断是否为圆形)。 可能的步骤总结如下: 1. 读取图像,转换为灰度图。 2. 应用高斯模糊减少噪声。 3. 使用阈值分割或边缘检测来突出硬币区域。 4. 形态学操作(如闭运算)连接边缘或去除噪声。 5. 查找轮廓。 6. 过滤轮廓,保留符合硬币特征的轮廓(面积、圆度)。 7. 找到参照物的轮廓,计算其像素直径,确定比例。 8. 对其他硬币轮廓计算像素直径,转换为实际尺寸。 9. 在图像上标注结果。 现在需要检查这些步骤是否在引用中有支持。引用4提到使用参照物的宽度计算pixelPerMetric,这应该对应步骤7和8。引用3中的代码示例展示了轮廓处理和Mat的使用,但用户需要Python代码,所以可能需要参考引用1和4中的Python示例。比如引用1中的硬币检测代码用了开闭运算,腐蚀膨胀,这可能在预处理步骤有帮助。 可能的代码结构包括: - 读取图像,预处理。 - 检测所有硬币的轮廓。 - 确定参照物,可能是最大的硬币或者用户指定位置的硬币- 计算比例,应用到其他硬币。 需要注意的是,如何自动确定参照物。可能需要假设参照物是图像中的第一个检测到的硬币,或者用户需要手动输入其实际尺寸。如果图像中有多个硬币,可能需要用户指定哪个是参照物,或者在代码中假设某个特定位置,比如最左边的硬币,如引用4中的例子。 另外,在测量直径时,使用最小外接圆的直径可能更准确,或者使用轮廓的面积来反推半径。例如,面积A=πr²,得到r=√(A/π),直径就是2r。这可能更准确,尤其是当硬币轮廓不完全圆的时候,但前提是假设硬币是正圆形。 此外,显示结果时,需要在图像上绘制轮廓和标注直径,这样用户可以看到检测结果是否正确。 现在,编写代码的步骤可能如下: 1. 导入必要的库,如cv2和numpy。 2. 读取图像,创建副本。 3. 转换为灰度图像。 4. 高斯模糊。 5. 应用阈值或边缘检测。 6. 形态学操作闭合小孔或断开区域。 7. 查找轮廓。 8. 遍历轮廓,过滤掉小的区域。 9. 确定参照物的像素尺寸。 10. 计算pixel_per_metric比例。 11. 对其他硬币计算实际直径。 12. 在图像上绘制轮廓和文本。 13. 显示结果。 可能的代码示例可能如下: 读取图像,灰度转换,模糊处理: img = cv2.imread("coins.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (7,7), 0) 应用阈值或边缘检测: # 使用阈值 _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 或者使用Canny # edges = cv2.Canny(blurred, 50, 150) 形态学操作: kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) 查找轮廓: contours, _ = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 过滤轮廓: min_area = 500 # 根据图像调整 filtered_contours = [c for c in contours if cv2.contourArea(c) > min_area] 假设第一个轮廓是参照物,或者找到最大的轮廓作为参照物: ref_contour = max(filtered_contours, key=cv2.contourArea) (x, y), radius = cv2.minEnclosingCircle(ref_contour) diameter_pixels_ref = 2 * radius # 假设参照物实际直径是25mm actual_diameter_ref = 25.0 pixel_per_metric = diameter_pixels_ref / actual_diameter_ref 然后遍历所有轮廓,计算每个的直径: for contour in filtered_contours: (x, y), radius = cv2.minEnclosingCircle(contour) diameter_pixels = 2 * radius actual_diameter = diameter_pixels / pixel_per_metric # 绘制圆和文本 cv2.circle(img, (int(x), int(y)), int(radius), (0,255,0), 2) cv2.putText(img, f"{actual_diameter:.1f}mm", (int(x)-50, int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 2) 最后显示图像。 但需要注意,可能参照物需要手动指定,或者确保图像中只有一种类型的硬币作为参照物。如果图像中有多个不同大小的硬币,可能需要更复杂的处理。 此外,用户可能需要处理不同光照条件下的图像,可能需要自适应阈值处理,如cv2.adaptiveThreshold,或者使用Otsu's方法。 测试时可能需要调整参数,如高斯模糊的核大小、形态学操作的核大小、面积阈值等。 现在,根据上述思路,整理回答的结构,确保步骤清晰,代码正确,并且参考了引用中的方法。</think>以下是使用OpenCVPython实现硬币识别及直径测量的分步教程: --- ### 一、实现思路 1. **预处理**:灰度化、降噪、边缘强化 2. **分割检测**:阈值分割、形态学操作提取目标 3. **轮廓分析**:查找硬币轮廓、过滤干扰项 4. **尺寸标定**:通过参照物建立像素-实际尺寸比例[^4] 5. **测量计算**:根据轮廓几何特征计算直径 --- ### 二、完整代码实现 ```python import cv2 import numpy as np # 读取图像 image = cv2.imread("coins.jpg") img = image.copy() # 预处理流程 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (7,7), 0) _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) # 形态学操作 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) # 轮廓检测 contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 标定参数(已知参照物直径25mm) ref_diameter_mm = 25.0 ref_contour = max(contours, key=cv2.contourArea) # 取最大轮廓作为参照 (x,y), ref_radius = cv2.minEnclosingCircle(ref_contour) pixel_per_metric = (ref_radius*2) / ref_diameter_mm # 像素/毫米比 # 测量所有硬币 for cnt in contours: area = cv2.contourArea(cnt) if area < 500: continue # 过滤噪声 # 计算几何特征 (x,y), radius = cv2.minEnclosingCircle(cnt) diameter_pixel = radius*2 diameter_mm = diameter_pixel / pixel_per_metric # 绘制结果 cv2.circle(img, (int(x),int(y)), int(radius), (0,255,0), 2) cv2.putText(img, f"{diameter_mm:.1f}mm", (int(x)-40,int(y)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 2) # 显示结果 cv2.imshow("Result", img) cv2.waitKey(0) ``` --- ### 三、关键步骤解析 1. **Otsu阈值分割**:自动确定最佳分割阈值[^1] $$ \text{阈值} = \arg\max_t [\sigma_b^2(t)] $$ 其中$\sigma_b^2$为类间方差 2. **形态学闭运算**: $$ \text{闭运算} = \text{膨胀} \circ \text{腐蚀} $$ 用于填充内部空洞、连接邻近区域[^3] 3. **尺寸标定公式**: $$ \text{实际直径} = \frac{\text{像素直径}}{\text{参照物像素直径}} \times \text{参照物实际直径} $$ 该比例关系基于相似性原理[^4] --- ### 四、效果优化建议 1. **光照归一化**:使用CLAHE算法增强对比度 2. **轮廓筛选**:增加圆度判断 $$ \text{圆度} = \frac{4\pi \times \text{面积}}{\text{周长}^2} $$ 接近1表示更接近标准圆 3. **多参照物校准**:取多个参照物测量取平均值 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值