python实现kmeans算法对图片的聚类分割

kmeans算法未调用库,使用基本数据结构实现

 

1.     对于给定的图片IMGP8080.jpg,要求把河流部分划分出来。可以采用以下方法:在该图像中分别在河流部分与非河流部分画出一个窗口,把在这两个窗口中的像素数据作为训练集,用Fisher线性判别方法求得分类器参数,再用该分类器对整幅图进行分类。请用python程序实现。

2.     对于给定的图片IMGP8080.jpg,要求利用聚类方法把图片分成2类,不要求标定。具体聚类算法不限,在实验报告中叙述清楚即可。请用python程序实现。

注:可以使用OpenCV或者其他任何图像处理的框架,但要求自己完成分类或者聚类算法。

 

相关程序GitHub:https://github.com/kevinten10/Image-Processing

 

实验效果图:

 

python算法实现:

 1、主程序

def run():
    """
    主程序
    """
    img = cv2.imread("IMGP8080.JPG")
    arrimg = np.array(img)
    # 获取像素点的集合
    feature = loadDataSet(arrimg)
    # 获取初始聚类中心
    init_cen_1, init_cen_2 = sel_init_cen(feature)
    # 三种方式获得聚类中心
    n = input("请选择function:\n"
              "1-->第五题窗口法\n"
              "2-->第六题kmeans聚类法\n"
              "3-->快速验证(使用计算好的聚类中心)\n")
    cen1, cen2 = sel_function(n, feature, arrimg, init_cen_1, init_cen_2)
    # 打印结果
    print("最终结果:", cen1, cen2)
    # 图片分类及展示图片
    image2k(cen1, cen2)

2、读取图片数据到数组

def loadDataSet(arrimg):
    """
    读取图片数据(三维向量b,g,r) 到 feature(一维列表[r,g,b]) 数据集
    :param arrimg: jpg图片的numpy数组形式
    :return: 特征向量组feature
    """
    row = arrimg.shape[0]
    col = arrimg.shape[1]

    # print("数组行数:",row)
    # print("数组列数:",col)

    # 特征向量集合
    features = []

    print("正在读取图片信息,请稍等......")

    # (行,列):读取像素点rgb数据
    for i in range(0, row):
        for j in range(0, col):
            r = arrimg[i, j, 2]
            g = arrimg[i, j, 1]
            b = arrimg[i, j, 0]
            features.append([r, g, b])

    # 转换成numpy矩阵计算形式,浮点型f
    feature = np.array(features, 'f')

    # print(feature,"以上为像素点集合")
    # print("像素点集合的shape:", feature.shape)

    return feature

3、判断“距离”

def distance(vecA, vecB):
    """
    计算两个向量的距离:三维向量-->一维距离
    :param vecA: 向量A
    :param vecB: 向量B
    :return: 浮点型数据
    """
    return np.sqrt(np.power(vecA[0] - vecB[0], 2) + np.power(vecA[1] - vecB[1], 2) + np.power(vecA[2] - vecB[2], 2))

PS:选取不同的方法进行聚类

def sel_function(n, feature, arrimg, init_cen_1, init_cen_2):
    """
    三选一,获得聚类中心
    :param n: 哪种方式?1,2,3
    :param feature: 特征向量数据集
    :param arrimg: 图片数据集
    :param init_cen_1: 初始聚类中心
    :param init_cen_2: 初始聚类中心
    :return: 聚类中心 cen1 cen2
    """
    if n == 1:
        # 第1种方法 window获得聚类中心
        cen_1, cen_2 = window_get_centor(arrimg)
    elif n == 2:
        # 第2种方法 kmeans获得聚类中心
        cen_1, cen_2 = kmeans_get_centor(feature, init_cen_1, init_cen_2)
    elif n == 3:
        # 第3种方法直接获得计算结果,节省时间
        cen_1 = [95.81982617, 69.23093989, 57.99697231]
        cen_2 = [207.61375807, 152.36148107, 124.72904938]

    else:
        cen_1 = init_cen_1
        cen_2 = init_cen_2
        print("无此方法,请输入1,2,3")

    return cen_1, cen_2

 

 

 

4、选取kmeans初始聚类中心

def sel_init_cen(features):
    """
    随机选择两个初始点
    :param features: 图像的特征向量集,[[r,g,b],[r,g,b]...]
    :return: 初始聚类中心 cen1 cen2
    """
    # 选取随机数
    rand_1 = (int)(np.random.random() * (features.shape[0]))
    rand_2 = (int)(np.random.random() * (features.shape[0]))

    # 选取初始中心
    centor_1 = features[rand_1]
    centor_2 = features[rand_2]

    print("初始聚类中心为:", centor_1, "+", centor_2)

    return centor_1, centor_2

5、kmeans进行聚类

def kmeans(node, centor1, centor2, class1, class2):
    """
    kmeans方法迭代计算聚类中心
    :param node: 待判断数据[r,g,b]
    :param centor1: 当前聚类中心
    :param centor2: 当前聚类中心
    :param class1: 属于类1的数据集
    :param class2: 属于类2的数据集
    :return: 新的聚类中心 cen1 cen2
    """
    dist1 = distance(node, centor1)
    dist2 = distance(node, centor2)

    # 判断新数据和两个聚类中心的距离
    if dist1 < dist2:
        print(node, "添加到class1")
        class1.append(node)
        centor1 = np.mean(class1, axis=0)

    elif dist2 < dist1:
        class2.append(node)
        print(node, "添加到class2")
        centor2 = np.mean(class2, axis=0)

    else:
        class1.append(node)
        class2.append(node)
        print(node, "添加到c1和c2")
        centor1 = np.mean(class1, axis=0)
        centor2 = np.mean(class2, axis=0)

    print("mean-class1", centor1)
    print("mean-class2", centor2)

    return centor1, centor2

PS:窗口法进行分类:

def window_get_centor(arrimg):
    """
    第1种方式:window-->fisher判别方法获得聚类中心
    1、获得数据集类1,类2
    2、计算均值向量 mean1 mean2
    3、计算类内离散度矩阵 sw_1 sw_2
    4、计算总类内离散度矩阵 sw=sw_1+sw_2
    5、获得sw的逆矩阵 sw.I
    6、计算w=

    :param arrimg: 图片数据集
    :return: 结果聚类中心 cen1 cen2
    """
    # 图片长宽
    length = arrimg.shape[1]
    width = arrimg.shape[0]
    # 类1 的窗口
    cl1_x_str = (int)(0.44 * length)
    cl1_x_end = (int)(0.55 * length)
    cl1_y_str = (int)(0.44 * width)
    cl1_y_end = (int)(0.55 * width)
    # 类2 的窗口
    cl2_x_str = (int)(0.77 * length)
    cl2_x_end = (int)(0.88 * length)
    cl2_y_str = (int)(0.44 * width)
    cl2_y_end = (int)(0.55 * width)

    class1 = []
    class2 = []

    # 获取类1
    for row1 in range(cl1_x_str, cl1_x_end):
        for col1 in range(cl1_y_str, cl1_y_end):
            class1.append(arrimg[col1][row1])
    # 获取类2
    for row2 in range(cl2_x_str, cl2_x_end):
        for col2 in range(cl2_y_str, cl2_y_end):
            class2.append(arrimg[col2][row2])

    feature1 = np.array(class1, 'f')
    feature2 = np.array(class2, 'f')
    cen_1 = np.mean(feature1, axis=0)
    cen_2 = np.mean(feature2, axis=0)

    print("window计算类1中心为:", cen_1)
    print("window计算类2中心为:", cen_2)

    return cen_1, cen_2

6、获取聚类中心

def kmeans_get_centor(feature, cen_1, cen_2):
    """
    第2种方式:kmeans方法获得聚类中心
    :param feature: 数据集
    :param cen_1: 初始聚类中心
    :param cen_2: 初始聚类中心
    :return: 结果聚类中心 cen1 cen2
    """
    # 建立两个聚类的空集合,注意:引入更正数据[0,0,0],防止数据过大
    class1 = []
    class2 = []
    class1.append([0, 0, 0])
    class2.append([0, 0, 0])

    # 第一种方式:设置大步长,减少计算时间
    for i in range(0, feature.shape[0] - 1, 100):
        print("当前为第", i, "轮")
        # 使用kmeans计算方法
        centor1, centor2 = kmeans(feature[i], cen_1, cen_2, class1, class2)
        cen_1 = centor1
        cen_2 = centor2

        # 第二种方式:计算两次迭代之间的均方差---->当均方差<0.0001时,停止迭代
        pass

    return cen_1, cen_2

7、显示聚类图像

def image2k(centor1, centor2):
    """
    根据聚类中心进行图像二分类
    :param centor1: 结果聚类中心
    :param centor2: 结果聚类中心
    :return: 显示图像
    """
    img2 = cv2.imread("IMGP8080.JPG")
    print(img2.shape)
    row = img2.shape[0]
    col = img2.shape[1]

    # (行,列):设置像素点bgr数据
    for i in range(0, row):
        for j in range(0, col):
            print("图像分类已进行到: 第", i, "行+", j, "列")
            # 类1 黑色 类型[b,g,r]
            if distance(img2[i][j], centor1) < distance(img2[i][j], centor2):
                img2[i][j] = [0, 0, 0]
            # 类2 红色 类型[b,g,r]
            else:
                img2[i][j] = [0, 0, 255]

    # 窗口,调整图像大小
    win = cv2.namedWindow('img win', flags=0)
    cv2.imshow('img win', img2)
    cv2.waitKey(0)
  • 10
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值