K-means聚类舌苔舌质分离及最终分割

K-means聚类舌苔舌质分离及最终分割

在处理舌苔与舌质分离的图像分割问题时,采用K-means聚类方法可以提供有效的解决方案。本方法的前沿包括几个关键的图像预处理步骤,确保聚类效果的准确性和效率。首先,进行彩色图像的均衡化,这一步骤有助于增强图像的对比度,使隐藏的细节更加明显。接着,转换到Lab颜色空间,并对a通道进行直方图均衡化,此举旨在突出图像的颜色差异,为后续的聚类分析提供更好的基础。图像归一化则是将数据缩放至特定范围内,通常是0到1之间,这有助于标准化输入数据,使模型更加稳定。最后,通过伽马变换调整图像的亮度,进一步优化视觉效果,为K-means聚类提供更均匀的数据分布,从而实现更精确的舌苔与舌质的分离。这一系列的预处理步骤不仅增强了图像的质量,也提高了聚类算法的分割性能,是现代医学图像处理中的重要技术之一。

  1. 彩色图像均衡化
  2. 转到Lab颜色空间,对a通道进行直方图均衡化,
  3. 图像归一化
  4. 伽马变换
def change_color_eH_gamma(img_path, color_pic_path):
    # 彩色图像均衡化
    img = cv2.imread(img_path, 1)

    # Lab
    img_lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)  # 转到Lab颜色空间
    (l, a, b) = cv2.split(img_lab)  # 通道分解
    aH = cv2.equalizeHist(a)  # 直方图均衡化
    result_lab = cv2.merge((l, aH, b), )  # 通道合成
    # 图像归一化
    fi = result_lab / 255.0
    # 伽马变换
    gamma = 1 / 2.2

    out = np.power(fi, gamma)
    # image的数值本应在0-255,但是在保存时的已经被归一化了,设置在(0-1)之间,我们只需要将标准化的值乘上255
    path = img_path.split('/')[-1]
    path = os.path.basename(path)
    save_color_path = os.path.join(color_pic_path, path)
    cv2.imwrite(save_color_path, out * 255)

Kmeans

聚类为3类

def kmeans(X, n):
    kmeans = MiniBatchKMeans(n_clusters=n)
    kmeans.fit(X)
    Y = kmeans.predict(X)
    # cluster_centers = kmeans.cluster_centers_(X)
    return Y
kmeans(X_, 3)

黑白分割颜色反转

舌苔、舌质分离开来

最终代码

import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.cluster import MiniBatchKMeans
from PIL import Image
import PIL.Image as image
import cv2
import numpy as np
import os


def change_color_eH_gamma(img_path, color_pic_path):
    # image = cv2.imread(IMAGE_PATH)
    # # 颜色通道分离
    # (B, G, R) = cv2.split(image)
    # cv2.imwrite('./img/234-1_20220418_tongue_blue.png', B)  # 注意顺序为B、G、R 图片主调颜色为蓝色,所以蓝色通道的图像肯定最亮\
    # cv2.imwrite('./img/234-1_20220418_tongue_green.png', G)
    # cv2.imwrite('./img/234-1_20220418_tongue_red.png', R)  # 图片上就没什么红色,因此红色通道的图像肯定最暗
    # # 观察R,G,B三通道图像的真实色彩
    # zeros = np.zeros(image.shape[:2], dtype='uint8')  # 注意是单通道图像,千万不能写image.shape,那就是三通道图像了
    # actual_B = cv2.merge([B, zeros, zeros])  # 绿色通道,注意B与两个zeros矩阵的顺序噢,一定不能错
    # actual_G = cv2.merge([zeros, G, zeros])
    # actual_R = cv2.merge([zeros, zeros, G])
    # cv2.imwrite('./img/234-1_20220418_tongue_actualb.png', actual_B)
    # cv2.imwrite('./img/234-1_20220418_tongue_actualg.png', actual_G)
    # cv2.imwrite('./img/234-1_20220418_tongue_actualr.png', actual_R)
    # # 色彩空间
    # hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)  # 转到HSV颜色空间
    # cv2.imwrite('./img/234-1_20220418_tongue_hsv.png', hsv)
    # lab = cv2.cvtColor(image, cv2.COLOR_BGR2Lab)  # 转到Lab颜色空间
    # cv2.imwrite('./img/234-1_20220418_tongue_lab.png', lab)
    # yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV)  # 转到YUV颜色空间
    # cv2.imwrite('./img/234-1_20220418_tongueyuv.png', yuv)

    # 彩色图像均衡化
    img = cv2.imread(img_path, 1)

    # Lab
    img_lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)  # 转到Lab颜色空间
    (l, a, b) = cv2.split(img_lab)  # 通道分解
    aH = cv2.equalizeHist(a)  # 直方图均衡化
    result_lab = cv2.merge((l, aH, b), )  # 通道合成
    # 图像归一化
    fi = result_lab / 255.0
    # 伽马变换
    gamma = 1 / 2.2

    out = np.power(fi, gamma)
    # cv2.imshow("img_original", img)
    # cv2.imshow("img_result_gamma_lab", out)
    # image的数值本应在0-255,但是在保存时的已经被归一化了,设置在(0-1)之间,我们只需要将标准化的值乘上255
    path = img_path.split('/')[-1]
    path = os.path.basename(path)
    save_color_path = os.path.join(color_pic_path, path)
    cv2.imwrite(save_color_path, out * 255)
    # cv2.imshow('result_lab', result_lab)
    # cv2.imwrite('img_result_lab.png', result_lab)
    # cv2.waitKey(0)


def kmeans(X, n):
    kmeans = MiniBatchKMeans(n_clusters=n)
    kmeans.fit(X)
    Y = kmeans.predict(X)
    # cluster_centers = kmeans.cluster_centers_(X)
    return Y


# def MiniBatchKMeans_main(img_path):
#     # 读取原始图像
#     X = plt.imread(img_path)
#     X = np.array(X)
#     # print(X)
#     X_ = X.reshape(-1, 3)
#     label = MiniBatchKMeans(n_clusters=3)
#     label = label.partial_fit(X_)
#     label = label.predict()
#     print('label: {}'.format(label))

def kmeans_main_cv2(img_path, mask_path):
    img = cv2.imread(img_path)
    X = cv2.imread(img_path, cv2.IMREAD_COLOR)
    X = np.array(X)
    row, col, dim = X.shape
    X_ = X.reshape(-1, 3)  # (将矩阵化为2维,才能使用聚类)

    label = kmeans(X_, 3)
    label = label.reshape(row, col)
    # print('label: {}' .format(label.shape()))
    # print('label:{}\n'.format(label))
    # create a new image to save the result of K-Means
    # pic_new = image.new("RGB", (col, row))  # 定义的是图像大小为y*x*3的图像,这里列在前面行在后面
    pic_new = np.zeros([col, row, 3], np.uint8)
    for i in range(0, col):
        for j in range(0, row):
            # (b, g, r) = img[i, j]
            if label[j][i] == 0:
                img[i, j] = (0, 0, 0)  # 黑色
            elif label[j][i] == 1:
                img[i, j] = (0, 0, 0)  # 黑色
            elif label[j][i] == 2:
                img[i, j] = (255, 255, 255)  # 白色
            pic_new[i, j] = img[i, j]

    # print(pic_new)
    # cv2.imshow("image", pic_new)  # 显示图片,后面会讲解
    img_name = img_path.split('/')[-1]
    img_name = os.path.basename(img_name)
    save_mask_path = os.path.join(mask_path, img_name)
    cv2.imwrite(save_mask_path, pic_new)
    cv2.waitKey(0)  # 等待按键


def kmeans_main(img_path, mask_path):
    # 读取原始图像
    X = plt.imread(img_path)
    X = np.array(X)
    # print(X.shape)
    row, col, dim = X.shape
    X_ = X.reshape(-1, 3)  # (将矩阵化为2维,才能使用聚类)

    label = kmeans(X_, 3)

    # print("label.shape=", label.shape)
    # get the label of each pixel
    label = label.reshape(row, col)
    # print("label.shape=", label.shape)
    # create a new image to save the result of K-Means
    pic_new = image.new("RGB", (col, row))  # 定义的是图像大小为y*x*3的图像,这里列在前面行在后面
    # print(pic_new)
    for i in range(col):
        for j in range(row):
            if label[j][i] == 0:
                pic_new.putpixel((i, j), (0, 0, 0))  # 填写的是位置为(j,i)位置的像素,列和行也是反的
            elif label[j][i] == 1:
                pic_new.putpixel((i, j), (0, 0, 0))  # putpixel(self, xy, color)
            elif label[j][i] == 2:
                pic_new.putpixel((i, j), (255, 255, 255))  # 白色
    # print(pic_new)
    # pic_new.save()
    # pic_new = pic_new.convert('RBG')
    # fig = plt.gcf()
    # fig.set_size_inches(row / 300, col / 300)  # dpi = 300, output = 700*700 pixels
    # plt.figure(figsize=(col / 300, row / 300))  # 设置画板大小
    plt.imshow(pic_new)
    # plt.gca().xaxis.set_major_locator(plt.NullLocator())
    # plt.gca().yaxis.set_major_locator(plt.NullLocator())
    # plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
    # plt.margins(0, 0)
    plt.axis('off')  # 关掉坐标轴为 off
    path = img_path.split('/')[-1]
    path = os.path.basename(path)
    save_mask_path = os.path.join(mask_path, path)
    pic_new.save(save_mask_path)
    # plt.savefig('img/7_2_tongue_1.png',dpi=500,bbox_inches = 'tight')
    # eps = 0.003333
    # plt.figure(figsize=(row * eps, col * eps))

    # plt.savefig(save_mask_path, transparent=True, dpi=300)
    # plt.xticks([])
    # plt.yticks([])

    # plt.show()


def add_mask2image_binary(images_path, masks_path, masked_path):
    # Add binary masks to images
    for img_item in os.listdir(images_path):
        print(img_item)
        img_path = os.path.join(images_path, img_item)
        img = cv2.imread(img_path)  # 1是以彩色图方式去读
        jpg_img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
        mask_path = os.path.join(masks_path, img_item[:-4] + '.png')  # mask是.png格式的,image是.jpg格式的
        # mask_path = cv2.imread(mask_path, 1)  # 1是以彩色图方式去读
        # jpg_img = cv2.cvtColor(mask_path, cv2.COLOR_BGRA2BGR)
        # mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
        mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)  # 将彩色mask以二值图像形式读取
        masked = cv2.add(img, np.zeros(np.shape(img), dtype=np.uint8), mask=mask)  # 将image的相素值和mask像素值相加得到结果
        cv2.imwrite(os.path.join(masked_path, img_item), masked)


def picture(path, newpath):
    files = os.listdir(path)
    for i in files:
        # print(i)
        files = os.path.join(path, i)
        img = Image.open(files).convert('RGB')  # deep 从36位(4*8位像素, 多一位透明通道)转为24位(3*8位像素)
        # print(img)
        dirpath = newpath
        file_name, file_extend = os.path.splitext(i)
        dst = os.path.join(os.path.abspath(dirpath), file_name + '.png')
        img.save(dst)


if __name__ == '__main__':
    images_path = 'origin_02'  # 原始文件 cv2.imread()不支持中文路径
    color_pic_path = 'Lab_a_gamm_02'
    # save_36_mask_path = 'gt_36'
    save_24_mask_path = 'gt_fur_02'
    masked_path = 'fur_02'  # save image
    i = 0
    for img_item in os.listdir(images_path):
        i = i + 1
        print(img_item)
        img_path = os.path.join(images_path, img_item)
        change_color_eH_gamma(img_path, color_pic_path)
        mask_pic_path = os.path.join(color_pic_path, img_item)
        kmeans_main(mask_pic_path, save_24_mask_path)  # MiniBatchKMeans_main(img_path)
        # kmeans_main_cv2(mask_pic_path, save_24_mask_path)
        print('finish: ', i)
    # convert2jpg(masks_path, save_24_mask_path)
    add_mask2image_binary(images_path, save_24_mask_path, masked_path)

最终结果示例

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进阶媛小吴

规则简单易懂,粗暴却完美!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值