Python下opencv使用笔记(十二)(k均值算法之图像分割)

k均值(kmeans)聚类是一种最为简单的聚类方法,直接根据数据点之间的距离(欧氏距离,几何距离等等)来划分数据是属于哪一类的,当所有数据点所属的类别不在变化的时候,聚类也就完成了。详细原理可索引下面一个博客:

聚类分析笔记-K均值matlab算法(一)

关于kmeans再谈几点认识:

  1. 重要的一点:聚类数目的问题。有的聚类、分类问题已经限制好了要聚类成几类,也就是聚类数目一定,那么这种聚类通常简单些,直接规定聚类数就好了。而有的聚类问题不知道分成几类才好,这个时候怎么办?那么就需要找到一种评价指标去评价聚类成多少类是最好的。比如说当聚类完了以后,可以计算一下类间的中心点的距离以及类内所有数据之间的距离和等等,作为判断标准,像DBI分类评价指标就是建立在这种基础上的。还有一种分类:减聚类分类,这也是在不知道分类数的时候进行的分类。
  2. 关于初始聚类中心的确定。Kmeans分类其实是具有收敛性的,所以初始聚类中心对其影响并不是很大,只要开始不相同就可以。因为在每次迭代完成以后,新的聚类中心是根据新划分类的所有点取平均而来的,所以不再受制于初始聚类中心。只是说聚类中心会影响迭代的次数,以当前计算机的速度,这点影响带来的耗时是可以不计的。
  3. 关于迭代终止条件。迭代终止条件可以有很多种,但是核心就是如何判定分类基本上已经收敛了,或者非常接近最优解,收敛不动了。一般情况下,可以设定迭代次数作为终止条件,还可以设定所有聚类中心在上下两次迭代过程中不发生变化时认为收敛,或者前后两次迭代的类中心之间的距离差小于某一个小的常数时认为收敛

关于opencv下的kmean算法,函数为cv2.kmeans()
函数的格式为:kmeans(data, K, bestLabels, criteria, attempts, flags)
(1)data: 分类数据,最好是np.float32的数据,每个特征放一列。之所以是np.float32原因是这种数据类型运算速度快,同样的数据下如果是uint型数据将会慢死你。
(2) K: 分类数,opencv2的kmeans分类是需要已知分类数的。
(3) bestLabels:预设的分类标签:没有的话 None
(4) criteria:迭代停止的模式选择,这是一个含有三个元素的元组型数。格式为(type,max_iter,epsilon)
其中,type又有两种选择:
—–cv2.TERM_CRITERIA_EPS :精确度(误差)满足epsilon停止。
—- cv2.TERM_CRITERIA_MAX_ITER:迭代次数超过max_iter停止。
—-cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,两者合体,任意一个满足结束。
(5)attempts:重复试验kmeans算法次数,将会返回最好的一次结果
(6)flags:初始类中心选择,两种方法
cv2.KMEANS_PP_CENTERS ; cv2.KMEANS_RANDOM_CENTERS

下面使用这个函数对灰度图像进行分类。首先需要明白的一点是输入数据变换到一维。因为我们是对整个图像进行聚类,所以他们的灰度值都属于一个特征(维度)内的,而图像属于二维的,所以不能直接当data输入进去,需要将图像转化为一个长条或者长链的一维数据。我们说data结束数据,每一个特征放一列,灰度图像聚类的灰度值就是一个特征。若果说是彩色图像聚类,那么这个时候需要分别把RGB三个通道转化为一维才行。最后把分类结果以图像的形式显示出来的时候,需要把长条或者长链的标签再变回来才行。详细代码如下:

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

img = cv2.imread('woman.jpg',0)#image read be 'gray'
plt.subplot(121),plt.imshow(img,'gray'),plt.title('original')
plt.xticks([]),plt.yticks([])

#change img(2D) to 1D
img1 = img.reshape((img.shape[0]*img.shape[1],1))
img1 = np.float32(img1)

#define criteria = (type,max_iter,epsilon)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,10,1.0)

#set flags: hou to choose the initial center
#---cv2.KMEANS_PP_CENTERS ; cv2.KMEANS_RANDOM_CENTERS
flags = cv2.KMEANS_RANDOM_CENTERS
# apply kmenas
compactness,labels,centers = cv2.kmeans(img1,4,None,criteria,10,flags)

img2 = labels.reshape((img.shape[0],img.shape[1]))
plt.subplot(122),plt.imshow(img2,'gray'),plt.title('kmeans')
plt.xticks([]),plt.yticks([])

这里写图片描述

这就是设置分成4类的结果。

  • 11
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
基于分水岭算法图像分割是一种常用的图像处理技术,可以将图像分割成多个区域,每个区域内的像素具有相似的特征。在 OpenCV 中,可以使用 cv2.watershed() 函数实现基于分水岭算法图像分割。 下面是一个简单的 Python 示例,演示如何使用基于分水岭算法图像分割: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('image.jpg') # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 阈值分割 ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) # 形态学操作 kernel = np.ones((3,3),np.uint8) opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=2) # 距离变换 dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.1*dist_transform.max(),255,0) # 背景区域 sure_bg = cv2.dilate(opening,kernel,iterations=3) # 不确定区域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg,sure_fg) # 标记连通区域 ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown==255] = 0 # 应用分水岭算法 markers = cv2.watershed(img,markers) img[markers == -1] = [255,0,0] # 显示结果 cv2.imshow('image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的示例中,首先读取一张图像,并将其转换为灰度图像。然后使用阈值分割算法将图像二值化。接下来,进行形态学操作,以去除图像中的噪声。然后使用距离变换算法计算前景区域,并将其阈值化。接着,使用形态学操作计算背景区域。最后,使用 cv2.connectedComponents() 函数计算不确定区域,并使用标记连通区域的方法生成分水岭算法的输入标记图像。最后,应用 cv2.watershed() 函数进行图像分割,并在窗口中显示结果。 需要注意的是,分水岭算法的结果依赖于输入标记图像的质量,因此需要根据具体情况进行调整,比如阈值分割的参数、形态学操作的参数、距离变换的参数等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值