【使用OpenCV进行目标分割与计数的代码实例详解】

这篇具有很好参考价值的文章主要介绍了【使用OpenCV进行目标分割与计数的代码实例详解】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概要

在当今数字图像处理领域,图像分割技术是一项至关重要的任务。图像分割旨在将图像中的不同目标或区域准确地分开,为计算机视觉、图像识别和机器学习等领域提供了坚实的基础。在图像分割的广泛应用中,二值化、形态学预处理、距离变换以及分水岭算法等技术被广泛探讨和应用。

首先,二值化技术通过将灰度图像转化为黑白图像,为分割算法提供了清晰的背景和前景。其次,形态学预处理通过腐蚀、膨胀等操作,清除噪声、连接物体,为后续处理提供了更加准确的图像。接着,距离变换技术能够量化地描述图像中各个像素点与目标的距离关系,为图像分析提供了重要依据。最后,分水岭算法则是一种高度智能的分割技术,通过模拟水流形成分割边界,解决了复杂目标重叠和交叉的挑战。

实例一:硬币分割计数

导入必要的库:

from skimage.feature import peak_local_max
from skimage.morphology import watershed
from scipy import ndimage
import numpy as np
import argparse
import imutils
import cv2

加载并预处理图像:

image = cv2.imread("1.jpg")
shifted = cv2.pyrMeanShiftFiltering(image, 21, 51)
cv2.imshow("Input", image)

这里使用了均值迁移滤波(Mean Shift Filtering)来平滑图像,使得图像中的区域更加集中,有助于后续的阈值处理。

将图像转换为灰度图,然后进行二值化处理:

gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("Thresh", thresh)

这里使用了Otsu的阈值处理方法,将灰度图转换为二值图。

计算距离变换并找到峰值:

D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, indices=False, min_distance=10, labels=thresh)

这一步计算了二值化图像的距离变换(Euclidean Distance Transform),然后找到了距离图中的峰值点。

应用分水岭算法进行图像分割:

markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)

这里使用了分水岭算法,通过标记(markers)和掩码(mask)将图像分割成不同的区域。

分割结果的后处理:

for label in np.unique(labels):
    # if the label is zero, we are examining the 'background'
  # so simply ignore it
  if label == 0:
    continue
 
  # otherwise, allocate memory for the label region and draw
  # it on the mask
  mask = np.zeros(gray.shape, dtype="uint8")
  mask[labels == label] = 255
 
  # detect contours in the mask and grab the largest one
  cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
  cnts = imutils.grab_contours(cnts)
  c = max(cnts, key=cv2.contourArea)
 
  # draw a circle enclosing the object
  ((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()
最终,代码将显示带有分割结果的原始图像。

这段代码演示了一个完整的图像分割流程,包括图像预处理、距离变换、分水岭算法的应用,以及对分割结果的后处理和可视化。
全部代码:

# import the necessary packages
from skimage.feature import peak_local_max
from scipy import ndimage
import numpy as np
import argparse
import imutils
import cv2
from skimage.morphology import watershed
# load the image and perform pyramid mean shift filtering
# to aid the thresholding step
image = cv2.imread("img.png")
shifted = cv2.pyrMeanShiftFiltering(image, 21, 51)
cv2.imshow("Input", image)

# convert the mean shift image to grayscale, then apply
# Otsu's thresholding
gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,
                       cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("Thresh", thresh)

# compute the exact Euclidean distance from every binary
# pixel to the nearest zero pixel, then find peaks in this
# distance map
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, indices=False, min_distance=10,
                          labels=thresh)

# perform a connected component analysis on the local peaks,
# using 8-connectivity, then appy the Watershed algorithm
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))

# loop over the unique labels returned by the Watershed
# algorithm
for label in np.unique(labels):
    # if the label is zero, we are examining the 'background'
    # so simply ignore it
    if label == 0:
        continue

    # otherwise, allocate memory for the label region and draw
    # it on the mask
    mask = np.zeros(gray.shape, dtype="uint8")
    mask[labels == label] = 255

    # detect contours in the mask and grab the largest one
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    c = max(cnts, key=cv2.contourArea)

    # draw a circle enclosing the object
    ((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)

# show the output image
cv2.imshow("Output", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

使用时候将图片放在同级目录,修改文件名字即可:
img.png,11行修改即可。
硬币图片自己随便找,复制图像截屏使用都可以:
【使用OpenCV进行目标分割与计数的代码实例详解】,# 学习笔记,python深度学习,人工智能,opencv,计算机视觉,人工智能,python,数据分析,信息可视化

【使用OpenCV进行目标分割与计数的代码实例详解】,# 学习笔记,python深度学习,人工智能,opencv,计算机视觉,人工智能,python,数据分析,信息可视化

使用结果:
三张图片:
【使用OpenCV进行目标分割与计数的代码实例详解】,# 学习笔记,python深度学习,人工智能,opencv,计算机视觉,人工智能,python,数据分析,信息可视化
注意:
导入库函数的部分,这个skimage库函数的没有,需要下载全部名字。
在环境下载库函数

pip install scikit-image -i https://pypi.tuna.tsinghua.edu.cn/simple

如果导入成功,但是运行报错:

D:\anaconda\envs\yolov5\python.exe E:\yolo项目\Opencv-project-main\Opencv-project-main\CVZone\光流\11.py 
Traceback (most recent call last):
  File "E:\yolo项目\Opencv-project-main\Opencv-project-main\CVZone\光流\11.py", line 26, in <module>
    localMax = peak_local_max(D, indices=False, min_distance=10,
TypeError: peak_local_max() got an unexpected keyword argument 'indices'

Process finished with exit code 1

说明使用的peak_local_max函数的参数中含有indices,但该函数在较新的版本中已经没有该参数了。

这可能是由于scikit-image库版本过高导致的。检查scikit-image库版本是否为0.17.2或更高版本,如果是,可以将该库回退到0.16.2版本:

pip install scikit-image==0.16.2 -i https://pypi.tuna.tsinghua.edu.cn/simple

如果依然想要使用最新的scikit-image库,将indices参数删除并改用默认值即可,例如:

localMax = peak_local_max(D, min_distance=10,
                          threshold_abs=threshold)

这样可以避免indices参数引起的错误。

实例二:玉米粒分割计数

导入必要的库:

import numpy as np
import cv2
from matplotlib import pyplot as plt

读取图像并进行灰度化处理:

img = cv2.imread('5.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

二值化处理:

ret, thresh = cv2.threshold(gray, 245, 255, cv2.THRESH_BINARY)

这一步将灰度图像转换为二值图像,其中灰度值大于等于245的像素被设为255(白色),小于245的像素被设为0(黑色)。

图像膨胀:

k = cv2.getStructuringElement(cv2.MORPH_RECT, (13, 13))
dilate = cv2.dilate(thresh, k, iterations=3)

通过膨胀操作,将二值图像中的物体区域扩大,便于后续处理。

距离变换:

cv2.bitwise_not(dilate, dilate)
dist_transform = cv2.distanceTransform(dilate, cv2.DIST_L2, 3)
dist = cv2.normalize(dist_transform, dist_transform, 0, 1.0, cv2.NORM_MINMAX)

这一步计算了图像中每个像素点到最近的背景像素的距离,得到了距离变换图。在这个图像中,物体的中心部分距离背景较远,而边缘部分距离背景较近。

二值化距离变换图:

dist = cv2.convertScaleAbs(dist)
ret2, morph = cv2.threshold(dist, 0.99, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

这一步将距离变换图二值化,得到了分割后的图像。

形态学开运算:

k2 = cv2.getStructuringElement(cv2.MORPH_RECT, (11, 5))
sure_fg = cv2.morphologyEx(morph, cv2.MORPH_OPEN, k2, iterations=1)

这一步通过形态学开运算去除小的噪点,保留大的物体区域。

寻找轮廓并标注:

thresh, contours, hierarchy = cv2.findContours(sure_fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i in range(0, len(contours)):
    (x, y, w, h) = cv2.boundingRect(contours[i])
    cv2.circle(img, (x + int(w / 2), y + int(h / 2)), 20, (0, 0, 255), -1, cv2.LINE_AA)
    cv2.putText(img, str(i + 1), (x + int(w / 2) - 15, y + int(h / 2) + 5), font, 0.8, (0, 255, 0), 2)

这一步使用cv2.findContours函数找到图像中的轮廓,然后绘制圆圈和文本标注在图像上,表示找到的物体区域。

显示和保存结果:

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

最后,通过cv2.imshow显示处理后的图像。

全部代码:

import numpy as np
import cv2
from matplotlib import pyplot as plt

font = cv2.FONT_HERSHEY_SIMPLEX

img = cv2.imread('img_2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 245, 255, cv2.THRESH_BINARY)
cv2.imshow("threshold", thresh)

k = cv2.getStructuringElement(cv2.MORPH_RECT, (13, 13))
dilate = cv2.dilate(thresh, k, iterations=3)
cv2.imshow("dilate", dilate)

cv2.bitwise_not(dilate, dilate)
dist_transform = cv2.distanceTransform(dilate, cv2.DIST_L2, 3)
dist = cv2.normalize(dist_transform, dist_transform, 0, 1.0, cv2.NORM_MINMAX)
cv2.imshow("distance", dist)
cv2.imwrite("dis.jpg", dist)

# dist = np.uint8(dist)
dist = cv2.convertScaleAbs(dist)
ret2, morph = cv2.threshold(dist, 0.99, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# ret2, morph = cv2.threshold(dist,0,255,cv2.THRESH_BINARY_INV)
cv2.imshow("morph", morph)

k2 = cv2.getStructuringElement(cv2.MORPH_RECT, (11, 5))
sure_fg = cv2.morphologyEx(morph, cv2.MORPH_OPEN, k2, iterations=1)  # 形态开运算

cv2.imshow("result", sure_fg)

thresh, contours, hierarchy = cv2.findContours(sure_fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i in range(0, len(contours)):
    (x, y, w, h) = cv2.boundingRect(contours[i])
    # cv2.drawContours(img,contours,i,(0,255,0),5)
    cv2.circle(img, (x + int(w / 2), y + int(h / 2)), 20, (0, 0, 255), -1, cv2.LINE_AA)
    cv2.putText(img, str(i + 1), (x + int(w / 2) - 15, y + int(h / 2) + 5), font, 0.8, (0, 255, 0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

原图:
【使用OpenCV进行目标分割与计数的代码实例详解】,# 学习笔记,python深度学习,人工智能,opencv,计算机视觉,人工智能,python,数据分析,信息可视化
结果:

【使用OpenCV进行目标分割与计数的代码实例详解】,# 学习笔记,python深度学习,人工智能,opencv,计算机视觉,人工智能,python,数据分析,信息可视化
opencv版本不适配可能报错:

D:\anaconda\envs\yolov5\python.exe E:\yolo项目\Opencv-project-main\Opencv-project-main\CVZone\光流\22.py 
Traceback (most recent call last):
  File "E:\yolo项目\Opencv-project-main\Opencv-project-main\CVZone\光流\22.py", line 33, in <module>
    thresh, contours, hierarchy = cv2.findContours(sure_fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)

Process finished with exit code 1

解决办法:
降低版本参考:
降低版本参考:
替换:

contours, _ = cv2.findContours(sure_fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

替换:【使用OpenCV进行目标分割与计数的代码实例详解】,# 学习笔记,python深度学习,人工智能,opencv,计算机视觉,人工智能,python,数据分析,信息可视化文章来源地址https://www.toymoban.com/news/detail-758216.html

到了这里,关于【使用OpenCV进行目标分割与计数的代码实例详解】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV与AI深度学习 | 实战 | 基于YOLOv9+SAM实现动态目标检测和分割(步骤 + 代码)

    本文来源公众号 “OpenCV与AI深度学习” ,仅用于学术分享,侵权删,干货满满。 原文链接:实战 | 基于YOLOv9+SAM实现动态目标检测和分割(步骤 + 代码)     本文主要介绍基于YOLOv9+SAM实现动态目标检测和分割,并给出详细步骤和代码。     在本文中,我们使用YOLOv9+SAM在

    2024年04月22日
    浏览(72)
  • 【opencv】示例-grabcut.cpp 使用OpenCV库的GrabCut算法进行图像分割

    left mouse button - set rectangle SHIFT+left mouse button - set GC_FGD pixels CTRL+left mouse button - set GC_BGD pixels 这段代码是一个 使用OpenCV库的GrabCut算法进行图像分割 的C++程序。它允许用户通过交互式方式选择图像中的一个区域,并利用GrabCut算法尝试将其分割出来。代码中包含用户操作指南、

    2024年04月13日
    浏览(45)
  • 深度学习中语义分割、实例分割、目标检测和图像分类区别

    语义分割 实例分割 目标检测 语义分割:需要判断每个像素属于哪一个类别,属于像素级别分类标注 实例分割:相较于语义分割 会将同一类别的不同物体进行分离标注   目标检测:输入图像通常包含多个物体,对物体的位置与类别进行标注  图像分类:输入图像通常包含一

    2024年02月08日
    浏览(57)
  • 实战 | OpenCV两种不同方法实现粘连大米粒分割计数(步骤 + 源码)

    导  读     本文主要介绍基于OpenCV的两种不同方法实现粘连大米分割计数,并给详细步骤和源码。 源码和图片素材见文末。 背景介绍     测试图如下,图中有个别米粒相互粘连,本文主要演示如何使用OpenCV用两种不同方法将其分割并计数。        方法一:基于分水岭算

    2024年01月21日
    浏览(114)
  • OpenCV项目开发实战--进行人脸变形 原理—并附实例Python/C++代码实现

    文末附基于Python和C++两种方式实现的测试代码下载链接 在本教程中,我们将学习如何使用 OpenCV 将一张脸变成另一张脸。 在我之前的文章中,我介绍了面部关键点检测和Delaunay 三角测量。最好查看这些帖子以更好地理解这篇文章。 图像变形首先在电影 Willow 中广泛使用,使用

    2024年02月09日
    浏览(70)
  • 使用爬虫代码获得深度学习目标检测或者语义分割中的图片。

    问题描述:目标检测或者图像分割需要大量的数据,如果手动从网上找的话会比较慢,这时候,我们可以从网上爬虫下来,然后自己筛选即可。 代码如下(不要忘记安装代码依赖的库): 这里以搜索明星的图片为例,运行代码,然后根据提示输入搜索图片的名字→搜索图片

    2024年02月10日
    浏览(53)
  • Fast SAM与YOLOV8检测模型一起使用实现实例分割以及指定物体分割(有代码)

    Fast SAM与YOLOV8检测模型一起使用 VX 搜索”晓理紫“ 关注并回复yolov8+fastsam获取核心代码 晓理紫 实例分割数据集的获取要比检测数据的获取更加困难,在已有检测模型不想从新标注分割数据进行训练但是又想获取相关物体的mask信息以便从像素级别对物体进行操作,这时就可以

    2024年02月13日
    浏览(32)
  • yolov8+多算法多目标追踪+实例分割+目标检测+姿态估计

    YOLOv8是一种先进的目标检测算法,结合多种算法实现多目标追踪、实例分割和姿态估计功能。该算法在计算机视觉领域具有广泛的应用。 首先,YOLOv8算法采用了You Only Look Once(YOLO)的思想,通过单次前向传递将目标检测问题转化为回归问题。它使用了深度卷积神经网络,能

    2024年02月20日
    浏览(47)
  • 使用Python+OpenCV2进行图片中的文字分割(支持竖版)

    把图片中的文字,识别出来,并将每个字的图片抠出来; 原图片: 分割后文件夹: 可见此时文件都还是数字为文件名称,那么接下来要利用OCR自动给每个文字图片文件命名 我们使用UMIOCR , UMI-OCR的安装建议去GITHUB上查,windows上部署还是很方便的; 这里使用本机安装好的

    2024年02月20日
    浏览(39)
  • 【目标检测】YOLOv5-7.0:加入实例分割

    前段时间,YOLOv5推出7.0版本,主要更新点是在目标检测的同时引入了实例分割。 目前,YOLOv5团队已经转向了YOLOv8的更新,因此,7.0版本大概率是YOLOv5的最终稳定版。 官方公告中给出了YOLOv5-7.0的更新要点: 推出了基于coco-seg的实例分割预训练模型 支持Paddle Paddle模型导出 自动

    2024年02月11日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包