【python+opencv】实现数出细胞/硬币数量

1. 细胞原图/硬币原图:

(矩形作为干扰项)

 aa317d479a194caf9414552705ae1859.png

2. 运行结果图:

(不同的图 实现结果可能会有差异 可能需要修改参数等 此代码仅以例图为例)

5ef1ddc3fd4b417cad345bcee8837b70.png

3. 数细胞完整代码:

import cv2
import numpy as np

# (1)输出细胞个数;
# (2)画出每个细胞的编号;

# 读取图像
color_image = cv2.imread('img5.png')
gray_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2GRAY)

# 高斯模糊,可能需要调整核大小
gray_image = cv2.GaussianBlur(gray_image, (23, 23), 0)

# 二值化处理
ret, thresh = cv2.threshold(gray_image, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

thresh = cv2.adaptiveThreshold(gray_image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, blockSize=33, C=22)

# 改用膨胀处理提高轮廓识别
kernel = np.ones((1, 1), np.uint8)
dilated_img = cv2.erode(thresh, kernel, iterations=2)

dilated_img = cv2.GaussianBlur(dilated_img, (13, 13), 0)

dilated_img = cv2.Canny(dilated_img, 50, 120)

# 查找并绘制轮廓
dilated_img = np.uint8(dilated_img)
contours, _ = cv2.findContours(dilated_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cell_count = 0
marked_image = color_image.copy()


# 引入圆度计算函数
def circularity(cnt):
    perimeter = cv2.arcLength(cnt, True)
    area = cv2.contourArea(cnt)
    if perimeter == 0:  # 避免除以零错误
        return 0
    return 4 * np.pi * (area / (perimeter ** 2))


area_threshold = 50

# 圆度阈值
circularity_threshold = 0.7

for cnt in contours:
    area = cv2.contourArea(cnt)
    # 计算当前轮廓的圆度
    circle_ratio = circularity(cnt)
    # 只有当轮廓面积大于给定阈值且圆度足够高时才认为是cell
    if circle_ratio > circularity_threshold and area > area_threshold:
        cell_count += 1
        x, y, w, h = cv2.boundingRect(cnt)
        cv2.rectangle(marked_image, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.putText(marked_image, str(cell_count), (x + 7, y + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)

print("细胞的数量为:", cell_count)
cv2.putText(marked_image, f"Cell Count: {cell_count}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
cv2.imshow('Cell Count', marked_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

AI对该代码的解释:

这段代码使用了OpenCV库和NumPy来处理图像并识别其中的细胞,主要步骤如下:
1. 导入必要的库

  • cv2:OpenCV的Python接口。
  • numpy as np:用于数值计算和数组操作。

2. 读取图像

  • 使用cv2.imread()读取名为img5.png的图像。
  • 转换彩色图像到灰度图像gray_image使用cv2.cvtColor()。

3. 高斯模糊

  • 应用高斯模糊cv2.GaussianBlur()来减少噪声,核大小为(23, 23)。

4. 二值化处理

  • 使用cv2.threshold()进行全局阈值处理,选择Otsu's二值化方法cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU。
  • 同时尝试使用自适应阈值处理cv2.adaptiveThreshold(),以适应图像中的不同光照条件。

5. 形态学操作

  • 使用cv2.erode()进行腐蚀操作,核为np.ones((1, 1), np.uint8),迭代次数为2。
  • 再次应用高斯模糊cv2.GaussianBlur(),核大小为(13, 13)。
  • 使用cv2.Canny()边缘检测算法找到边缘。

6. 查找轮廓

  • 将图像转换为np.uint8格式。
  • 使用cv2.findContours()找到所有外部轮廓。

7. 轮廓筛选

  • 定义一个函数circularity()来计算轮廓的圆度。
  • 设定面积阈值area_threshold和圆度阈值circularity_threshold。
  • 遍历所有轮廓,只保留面积大于阈值且圆度高于阈值的轮廓。

8. 标记细胞

  • 对于每个满足条件的轮廓,增加cell_count计数器。
  • 使用cv2.rectangle()和cv2.putText()在原图上标记细胞的位置和编号。

9. 输出结果

  • 打印细胞总数。
  • 在图像上添加总细胞计数的文字标签。
  • 使用cv2.imshow()显示标记后的图像。
  • 等待按键事件cv2.waitKey(0),然后关闭所有窗口cv2.destroyAllWindows()。

这个流程可以自动识别和计数图像中的细胞,通过调整参数(如模糊核大小、阈值、圆度阈值等)可以优化识别效果。

4. 数硬币完整代码:

import math
import imutils
from imutils import perspective
from imutils import contours
import numpy as np
import cv2


def midpoint(ptA, ptB):
    return (ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5


def DistEuclidean(ptA, ptB):
    return math.sqrt(math.pow((ptA[0] - ptB[0]), 2) + math.pow((ptA[1] - ptB[1]), 2))


def is_coin(c):
    # 计算轮廓的周长
    peri = cv2.arcLength(c, True)
    # 获取轮廓的近似多边形,这里使用3%的周长容差
    approx = cv2.approxPolyDP(c, 0.03 * peri, True)

    # 检查近似后的顶点数是否接近圆形(对于较小的误差容忍,顶点数应接近于1)
    circularity = 4 * math.pi * cv2.contourArea(c) / (peri * peri)
    # 这里假设圆形轮廓的圆度大于0.8
    return 8 <= len(approx) <= 12 and circularity > 0.8


# image = cv2.imread('img.png')
image = cv2.imread('coin.png')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (11, 11), 0)

edged = cv2.Canny(gray, 50, 100)
# cv2.imshow("Canny", edged)

edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

(cnts, _) = contours.sort_contours(cnts)
pixelsPerMetric = 1

coin_count = 0
orig = image.copy()
for c in cnts:
    # 检查轮廓是否可能是硬币
    if not is_coin(c):
        continue
    if cv2.contourArea(c) < 200:
        continue
    print("area:", cv2.contourArea(c))

    coin_count += 1

    x, y, w, h = cv2.boundingRect(c)
    cv2.rectangle(orig, (x, y), (x + w, y + h), (0, 255, 0))
    cv2.putText(orig, str(coin_count), (x + 7, y + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
    

print("Total number of Coins:", coin_count)
cv2.putText(orig, f"Coin Count: {coin_count}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow("Image", orig)
cv2.waitKey(0)

AI对该代码的解释:

这段代码使用了OpenCV和imutils库来检测和识别图像中的硬币,并计算它们的数量。以下是代码的详细解释:
1. 导入库

  • math:用于数学运算。
  • imutils:提供了实用的图像处理工具,如透视校正和轮廓排序。
  • numpy as np:用于数值计算和数组操作。
  • cv2:OpenCV库,用于图像处理和计算机视觉任务。

2. 定义辅助函数

  • midpoint():计算两个点的中点。
  • DistEuclidean():计算两点之间的欧几里得距离。
  • is_coin(c):检查轮廓是否可能是硬币,通过计算轮廓的周长和近似多边形的顶点数,以及轮廓的圆度。

3. 读取图像

  • 使用cv2.imread()读取图像coin.png。

4. 预处理图像

  • 转换图像为灰度图cv2.cvtColor()。
  • 应用高斯模糊cv2.GaussianBlur()减少噪声。

5. 边缘检测

  • 使用Canny边缘检测cv2.Canny()。
  • 进行膨胀和腐蚀操作cv2.dilate()和cv2.erode()以增强边缘。

6. 查找轮廓

  • 使用cv2.findContours()找到图像中的所有轮廓。
  • 调整轮廓顺序imutils.grab_contours()。

7. 轮廓筛选和标记

  • 遍历所有轮廓,使用is_coin()函数筛选可能是硬币的轮廓。
  • 排除面积过小的轮廓。
  • 绘制矩形框cv2.rectangle()并标注硬币编号cv2.putText()。

8. 统计硬币数量

  • 每当检测到一个硬币轮廓时,增加coin_count计数器。

9. 输出结果

  • 打印总的硬币数量。
  • 在图像上添加硬币总数的文字标签cv2.putText()。
  • 显示最终图像cv2.imshow(),等待按键事件cv2.waitKey(0),然后关闭所有窗口。

二者代码差别不大,我就是互相改的,可能会有coin的代码中出现cell的单词哈哈哈哈哈哈

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青鱼鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值