魏老师学生——Cecil:学习OpenCV-机器视觉之旅
T恤大小问题
- 案例分析:服装厂要生产T恤,需要获得尺寸数据,所以收集一批身高体重信息并且绘在坐标系上。
- 为了便于生产,需要将数据分类。K值聚类可以把所有数据分为N组。
工作原理
把图中数据分为两组。
第一步:随机选取两重心点C1、C2.
第二步:计算每个点到两重心点距离。距离C1近标为0,距离C2近标为1.属于0的标为红色,属于1的标为蓝色。
第三步:重新计算所有蓝色和红色点的重心,以两点更新重心点的位置。
重复第二步,更新点的标记。不断迭代,直到两重心点位置稳定。此时这些点到相应重心的距离之和最小。
K值聚类改进方向:如何选取好的起始重心点,怎样加速迭代过程。
OpenCV中的K值聚类
解释函数参数—— cv2.kmeans()
输入参数:
- samples:np.float32类型数据,每个特征放在一列。
- nclusters(K):聚类的最终数目。
- criteria:终止迭代的条件。条件满足,迭代终止。含三成员(typw,max_iter,epsilon)的元组。
——type终止的三种类型:
cv2.TERM_CRITERIA_EPS 只有精确度epsilon满足时停止迭代
cv2.TERM_CRITERIA_MAX_ITER 当迭代次数超过阈值时停止迭代
cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER 上面一个条件满足就停止迭代
——max_iter 最大迭代次数
——epsilon 精确度阈值 - attempts:使用不同的起始标记来执行算法次数。算法返回紧密度最好的标记,紧密度也作为输出被返回。
- flags:设置如何选择起始重心。cv2.KMEANS_PP_CENTERS 或 cv2.KMEANS_RANDOM_CENTERS
输出参数: - compactness:紧密度,返回每个点到相应重心的距离的平方和。
- labels:标志数组,将成员标记为0,1。
- centers:由聚类中心组成的数组。
仅有一个特征的数据
- 对一组只有一个特征的数据,先产生随机数据,使用Matplotlib绘制。
- 将长度为50、取值范围是0-255的向量Z进行重排,变成列向量。将数据类型转换为np.float32。得到下图:
- 设置好终止条件:算法执行10次迭代或者精确度为1.0,使用KMeans函数。返回值:紧密度compactness、标志和中心。
- A组数据用红色表示,B组数据用蓝色表示,重心用黄色表示。结果下图:
代码演示
#coding=utf-8
import numpy as np
import cv2
from matplotlib import pyplot as plt
x=np.random.randint(25,100,25)
y=np.random.randint(175,255,25)
z=np.hstack((x,y))
z=z.reshape((50,1))
z=np.float32(z)
criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,10,1.0)
flags=cv2.KMEANS_RANDOM_CENTERS
compactness,labels,centers=cv2.kmeans(z,2,None,criteria,10,flags)
A=z[labels==0]
B=z[labels==1]
plt.hist(A,256,[0,256],color='r')
plt.hist(B,256,[0,256],color='b')
plt.hist(centers,32,[0,256],color='y')
plt.show()
含有多个特征的数据
有n个特征就使用n列向量。每一行对应每一个元素。
代码演示
#coding=utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
X=np.random.randint(25,50,(25,2))
Y=np.random.randint(60,85,(25,2))
Z=np.vstack((X,Y))
Z=np.float32(Z)
criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,10,1.0)
ret,label,center=cv2.kmeans(Z,2,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
A=Z[label.ravel()==0]
B=Z[label.ravel()==1]
plt.scatter(A[:,0],A[:,1])
plt.scatter(B[:,0],B[:,1],c='r')
plt.scatter(center[:,0],center[:,1],s=80,c='y',marker='s')
plt.xlabel('Height')
plt.ylabel('Weight')
plt.show()
颜色量化
- 减少图片中颜色数目的一个过程。为了减少内存消耗。
- K值聚类的方法来进行颜色量化。
- 3个特征:R、G、B,把图片数据变形成M(图片中像素点数目)×3的向量。
- 聚类完成后,用聚类中心值替换与其同组的像素值,保证结果图片只含有指定数目的颜色。
代码演示
#coding=utf-8
import cv2
import numpy as np
img=cv2.imread('./image2/mario.jpg')
Z=img.reshape((-1,3))
Z=np.float32(Z)#转换数据类型
criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,10,1.0)
K=8
ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
center=np.uint8(center)
res=center[label.flatten()]
res2=res.reshape((img.shape))
cv2.imshow('res2',res2)
cv2.waitKey(0)
cv2.destroyAllWindows()