目录
一、前言
二、实验目的
三、实验内容
四、实验过程
一、前言
编程语言:Python,编程软件:vscode或pycharm,必备的第三方库:OpenCV,numpy,matplotlib,os等等。
关于OpenCV,numpy,matplotlib,os等第三方库的下载方式如下:
第一步,按住【Windows】和【R】调出运行界面,输入【cmd】,回车打开命令行。
第二步,输入以下安装命令(可以先升级一下pip指令)。
pip升级指令:
python -m pip install --upgrade pip
opencv库的清华源下载:
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
numpy库的清华源下载:
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
matplotlib库的清华源下载:
pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
os库的清华源下载:
pip install os -i https://pypi.tuna.tsinghua.edu.cn/simple
二、实验目的
1.了解不同图像分割算法;
2.基于函式库,透过调用函式,实现图像分割;
3.基于演算法原理,以函数形式,自行实现图像分割;
三、实验内容
1.任选一张彩色图,透过调用函式(库)完成完成课堂教授内容
(1)Otsu:(1)灰度图分割
(2)Clustering:(1)灰度图分割(2)彩色图像分割
2.任选一张彩色图,透过演算法,自行撰写函式完成完成课堂教授内容
(1)Otsu:(1)灰度图分割
(2)Clustering:(1)灰度图分割(2)彩色图像分割
四、实验过程
(1)基于OpenCV库,使用大津法和kmeans聚类解决问题一,代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as pltdef question1_Otsu():# 读取图像img = cv2.imread(r"D:\Image\img1.jpg")# 转换为灰度图像img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 对图像进行二值化处理(OTSU算法)thresh1, result1 = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 对图像进行反向二值化处理(OTSU算法)thresh2, result2 = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# 绘制原始图像、灰度图像、二值化图像、反向二值化图像plt.subplot(2, 2, 1), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title('Original img'), plt.axis('off')plt.subplot(2, 2, 2), plt.imshow(img_gray, cmap = 'gray'), plt.title('Gray img'), plt.axis('off')plt.subplot(2, 2, 3), plt.imshow(result1, cmap = 'gray'), plt.title('Binary img'), plt.axis('off')plt.subplot(2, 2, 4), plt.imshow(result2, cmap = 'gray'), plt.title('Inverse binary img'), plt.axis('off')# 调整图像布局并显示图像plt.tight_layout()plt.show()def question1_Clustering_gray():# 读取图像并转换为灰度图像img = cv2.imread(r"D:\Image\img1.jpg", 0)# 获取图像的高度和宽度height, width = img.shape[:]# 将图像转换为一维数组data = img.reshape((-1, 1))# 将数据转换为浮点型data = np.float32(data)# 设置聚类停止条件criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.1)# 设置聚类中心的初始化方式flags = cv2.KMEANS_RANDOM_CENTERS# 循环不同的聚类数for k in range(1, 10):if k == 1:# 展示原始图像plt.subplot(3, 3, k), plt.imshow(img, cmap = 'gray'), plt.title('Original img'), plt.axis('off')else:# 执行k-means聚类算法compactness, labels, centers = cv2.kmeans(data, k, None, criteria, 10, flags)# 重构聚类结果图像img_k = labels.reshape((height, width))# 展示聚类结果图像plt.subplot(3, 3, k), plt.imshow(img_k, cmap = 'gray'), plt.title(f'Kmeans img (k={k})'), plt.axis('off')# 调整图像布局并显示图像plt.tight_layout()plt.show()def question1_Clustering_color():# 读取图片img = cv2.imread(r"D:\Image\img1.jpg")# 将图片转换为numpy数组,并进行形状变换,转化成3列data = img.reshape((-1, 3))# 转换为浮点型data = np.float32(data)# 设置聚类停止条件criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.1)# 设置聚类中心的初始化方式flags = cv2.KMEANS_RANDOM_CENTERS# 不同的K值列表K_list = [1, 2, 4, 8, 16, 32]# 遍历不同的K值for k in range(len(K_list)):# 第一个K值特殊处理if k == 0:# 显示原始图片plt.subplot(2, 3, k + 1), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title('Original img'), plt.axis('off')else:# k-means聚类compactness, labels, centers = cv2.kmeans(data, K_list[k], None, criteria, 10, flags)# 将中心点转换为整型centers = np.uint8(centers)# 根据中心点和标签得到聚类结果res = centers[labels.flatten()]# 重构聚类结果图像img_k = res.reshape((img.shape))# 显示聚类结果图片plt.subplot(2, 3, k + 1), plt.imshow(cv2.cvtColor(img_k, cv2.COLOR_BGR2RGB)), plt.title(f'Kmeans img (k={K_list[k]})'), plt.axis('off')# 调整图像布局并显示图像plt.tight_layout()plt.show()# 执行相应函数
question1_Otsu()
question1_Clustering_gray()
question1_Clustering_color()
代码的运行效果如下:
基于Otsu的灰度图分割:
基于kmeans的灰度图分割:
基于kmeans的彩色图分割:
(2)不使用OpenCV库,根据otsu和kmeans的原理,编写代码文件,命名为【Methods】,具体代码如下:
import numpy as npdef Otsu(img):# 复制图像数据data = img.copy()# 将数据转换为float32类型data = np.float32(data)# 获取图像的高度和宽度height, width = img.shape[:]# 初始化阈值和最大类间方差threshold_t = 0otsu_max = 0# 遍历255以内的每个灰度值for t in range(256):# 选取像素值小于等于阈值的像素点n0 = data[np.where(data <= t)]# 选取像素值大于阈值的像素点n1 = data[np.where(data > t)]# 计算像素点权重weight0 = len(n0) / (height * width)weight1 = len(n1) / (height * width)# 计算均值u0 = np.mean(n0) if len(n0) > 0 else 0.u1 = np.mean(n1) if len(n1) > 0 else 0.# 计算类间方差otsu = weight0 * weight1 * (u0 - u1) ** 2# 更新最大类间方差和阈值if otsu > otsu_max:otsu_max = otsuthreshold_t = tprint('类间方差最大阈值:', threshold_t)# 将像素值小于等于阈值的像素点设为0data[data <= threshold_t] = 0# 将像素值大于阈值的像素点设为255data[data > threshold_t] = 255# 将数据转换为uint8类型img_result = np.uint8(data)return img_resultdef Kmeans(img, k, iter):# 判断图像是否为灰度图像if len(img.shape) == 2:# 获取图像高度和宽度height, width = img.shape[:]# 将图片转换为numpy数组,并进行形状变换,转化成1列data = img.reshape((-1, 1))else:# 获取图像高度和宽度height, width = img.shape[:2]# 将图片转换为numpy数组,并进行形状变换,转化成3列data = img.reshape((-1, 3))# 将数据转换为浮点型data = np.float32(data)# 创建一个与数据长度相等的全零数组labels = np.zeros((height * width))# 随机选择k个点作为初始簇心cluster_centers_random = np.random.choice(height * width, k, replace = False)cluster_centers = data[cluster_centers_random, :]# 初始化距离数组distance = [ [] for i in range(k)]# 迭代k次for i in range(iter):print("第%d次迭代开始"% (i + 1))# 计算每个数据点到簇心的距离for j in range(k):distance[j] = np.sqrt(np.sum(np.square(data - cluster_centers[j]), axis = 1))# 根据距离最小的簇心标记每个数据点的类别labels = np.argmin(np.array(distance), axis = 0)# 更新簇心为每个簇内数据点的均值for j in range(k):cluster_centers[j] = np.mean(data[labels == j], axis = 0)# 判断图像是否为灰度图像if len(img.shape) == 2:# 重构聚类结果图像img_result = labels.reshape((height, width))else:# 将簇心转换为整型centers = np.uint8(cluster_centers)# 根据簇心和标签得到聚类结果res = centers[labels.flatten()]# 重构聚类结果图像img_result = res.reshape((img.shape))print("K-means聚类完成\n")return img_result
通过调用上述代码,解决问题二,问题二的解决代码如下:
import cv2
import matplotlib.pyplot as plt
from Methods import *def question2_Otsu():# 读取图像img = cv2.imread(r"D:\Image\img1.jpg")# 将彩色图像转为灰度图像img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 使用Otsu算法进行图像二值化img_otsu = Otsu(img_gray)# 复制img_otsu图像,进行反二值化img_otsu_inv = img_otsu.copy()# 反二值化img_otsu_inv = 255 - img_otsu# 绘制原始图像、灰度图像、二值化图像、反向二值化图像plt.subplot(2, 2, 1), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title('Original img'), plt.axis('off')plt.subplot(2, 2, 2), plt.imshow(img_gray, cmap = 'gray'), plt.title('Gray img'), plt.axis('off')plt.subplot(2, 2, 3), plt.imshow(img_otsu, cmap = 'gray'), plt.title('Binary img'), plt.axis('off')plt.subplot(2, 2, 4), plt.imshow(img_otsu_inv, cmap = 'gray'), plt.title('Inverse binary img'), plt.axis('off')# 调整图像布局并显示图像plt.tight_layout()plt.show()def question2_Clustering_Gray():# 读取图片img = cv2.imread(r"D:\Image\img1.jpg", 0)# 循环遍历k值for k in range(1, 10):# 显示原始图像if k == 1:plt.subplot(3, 3, k), plt.imshow(img, cmap = 'gray'), plt.title("Original img"), plt.axis('off')else:# 对图像进行kmeans聚类img_kmeans_gray = Kmeans(img, k, 50)# 显示聚类后的图像plt.subplot(3, 3, k), plt.imshow(img_kmeans_gray, cmap = 'gray'), plt.title(f'Kmeans img (k={k})'), plt.axis('off')# 调整图像布局并显示图像plt.tight_layout()plt.show()def question2_Clustering_color():# 读取图像img = cv2.imread(r"D:\Image\img1.jpg")# 不同的K值列表K_list = [1, 2, 4, 8, 16, 32]# 遍历不同的K值for i in range(len(K_list)):# 第一个K值特殊处理if i == 0:# 显示原始图片plt.subplot(2, 3, i + 1), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original img"), plt.axis('off')else:# 执行Kmeans聚类,并显示聚类后的图像img_kmeans = Kmeans(img, K_list[i], 50)plt.subplot(2, 3, i + 1), plt.imshow(cv2.cvtColor(img_kmeans, cv2.COLOR_BGR2RGB)), plt.title(f"Kmeans img (k={K_list[i]})"), plt.axis('off')# 调整图像布局并显示图像plt.tight_layout()plt.show()# 执行相应函数
question2_Otsu()
question2_Clustering_Gray()
question2_Clustering_color()
代码的运行效果如下:
基于Otsu原理的灰度图分割:
基于kmeans原理的灰度图和彩色图分割:
上述就是使用OpenCV库解决问题一,根据算法原理编写代码文件解决问题二。
都看到最后了,不点个赞吗?