使用Python+opencv+k-means根据扫描图片计算叶片面积
Posted 空中旋转篮球
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Python+opencv+k-means根据扫描图片计算叶片面积相关的知识,希望对你有一定的参考价值。
1.样本数据
采用扫描仪扫描叶片数据成图。使用该数据计算叶片面积。4片叶子,分成8段。
2.计算环境配置
使用到的库:opencv、numpy、sklearn(scikit-learn)
部分使用到的opencv函数介绍:
序号 | 函数 | 详解 |
1 | cv2.imread(r'02.jpg', flags=1) | 读取图像 |
2 | cv2.pyrDown(img) | 构建金字塔, 高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。 |
3 | cv2.pyrUp(img) | 向上采样 |
4 | cv2.imshow("imagin0", img0) | 窗口显示图像 |
5 | cv2.destroyWindow("imagin0") | 关闭窗口 |
6 | cv2.morphologyEx(src, op, kernel) | 进行各类形态学的变化, 参数说明:src传入的图片、op进行变化的方式、kernel表示方框的大小 |
7 | cv2.morphologyEx(img1, cv2.MORPH_CLOSE, k, iterations=5) | 进行闭运算, 指的是先进行膨胀操作,再进行腐蚀操作 |
8 | cv2.morphologyEx(img2, cv2.MORPH_OPEN, k, iterations=8) | 进行开运算,指的是先进行腐蚀操作,再进行膨胀操作 |
9 | cv2.findContours() | 示例:image,contours,hierarchy = cv2.findContours(contour,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) 计算contours[i]中所包括的点数,contours[i]的长度和面积等 |
10 | cv2.drawContours() | 用来绘制轮廓。第一个参数是一张图片,可以是原图或者其他。第二个参数是轮廓,也可以说是cv2.findContours()找出来的点集,一个列表。第三个参数是对轮廓(第二个参数)的索引,当需要绘制独立轮廓时很有用,若要全部绘制可设为-1。接下来的参数是轮廓的颜色和厚度。opencv官网教程传送门 |
3.完整代码
如下:
import cv2
import numpy as np
from sklearn.cluster import KMeans
def calculateNumber(A, b):
num = 0
for i in range(len(A)):
for j in range(len(A[0])):
if A[i][j] == b:
num += 1
return num
img0 = cv2.imread(r'02.jpg', flags=1)
"""高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。
#这样 操作一次一个 MxN 的图像就变成了一个 M/2 x N/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。这被称为 Octave。
#连续进行这样的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函数 cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。
"""
img0 = cv2.pyrDown(img0)
img0 = cv2.pyrDown(img0)
img0 = cv2.pyrDown(img0)
img0 = img0[1:, 1:, 0] #获取B通道图片,B通道更能区别叶片色彩;且将不必要部分截除,便于处理。
cv2.imshow("imagin0", img0)
cv2.waitKey()
cv2.destroyWindow("imagin0")
r, c = img0.shape
row = np.zeros((c, r), dtype=np.uint8)
col = np.zeros((c, r), dtype=np.uint8)
for i in range(c):
row[i, :] = i
for i in range(r):
col[:, i] = i
feature = []
for i in range(r):
for j in range(c):
feature.append([row[j, i], col[j, i], img0[i, j]])
feature = np.array(feature)
label = KMeans(2).fit_predict(feature)
bool1 = label == 0
bool2 = label == 1
img1 = img0.copy()
img1 = img1.ravel()
img1[bool1] = 0
img1[bool2] = 255
img1 = img1.reshape(r, c)
cv2.imshow("imagin1", img1)
cv2.waitKey()
cv2.destroyWindow("imagin1")#关闭指定窗口
k = np.array([[1, 1], [1, 1]]) #kernal
#进行各类形态学的变化,参数说明:src传入的图片,op进行变化的方式,kernel表示方框的大小
img2 = cv2.morphologyEx(img1, cv2.MORPH_CLOSE, k, iterations=5)#进行闭运算, 指的是先进行膨胀操作,再进行腐蚀操作
img2 = cv2.morphologyEx(img2, cv2.MORPH_OPEN, k, iterations=8)#进行开运算,指的是先进行腐蚀操作,再进行膨胀操作
cv2.imshow("imagin2", img2)
cv2.waitKey()
cv2.destroyWindow("imagin2")
a1 = calculateNumber(img2, 255)
a0 = a1+calculateNumber(img2, 0)
a = a1 * 21.0*29.7 / a0 #原图实际大小为A4大小的情况下
print(a0, a1, a)
4.计算过程和结果
具体如下:
原图很大,显示不全,向下采样,缩小显示。
获取B通道数据显示:
采用K-means聚类方法,由于仅采用像素距离作为聚类特征会产生较大误差,可以采用像素实际位置(横纵坐标)和像素点灰度作为聚类特征依据。将图片像素点聚为2类,分为背景与前景。
背景类用黑色点表示,前景类用白色点表示
上面聚类结果中具有一些零星小图斑,为消除噪声点,选择对背景噪声先腐蚀掉,对前景噪声进行膨胀,为避免对其他地方的影响,可以先使用闭运算去除前景噪声,使用开运算去除背景噪声。
画出叶片轮廓:
面积的计算可以根据以上前景和背景的象元比例计算得到叶片面积。
参考:利用图像处理计算叶片面积
以上是关于使用Python+opencv+k-means根据扫描图片计算叶片面积的主要内容,如果未能解决你的问题,请参考以下文章
使用Python+opencv+k-means根据扫描图片计算叶片面积-续
OpenCV-Python实战(番外篇)——利用 K-Means 聚类进行色彩量化
Python,OpenCV中的K均值聚类——K-Means Cluster
毕业了,在Python中使用 OpenCV 和K-Means 聚类对毕业照进行图像分割