大黄脸头像_图像分类算法

大黄脸头像_图像分类算法本篇博客主要借助机器学习中常用的一个库——scikit-learn来实现图像分割

前言

  前面几篇博客已经介绍过了基于距离的聚类算法 ( ( (K-Means、K-Means++和MeanShift ) ) )和基于密度的聚类算法 ( ( (DBSCAN ) ) ),当然,除此之外还有像层次聚类、谱聚类等这些聚类算法还没有学习到,以后若涉及到再做记录。本篇博客就主要借助机器学习中常用的一个库——scikit-learn来实现图像分割,没错,就是我的头像b( ̄▽ ̄)d

在这里插入图片描述
  这张图片 ( 320 ∗ 320 ) (320*320) (320320)是三通道的,相当于数据的维度为3,由此就根据像素值 ( ( (颜色 ) ) )来实现聚类,即分割图像。

1. K-Means分割图像

  为了与前面几篇博客保持一致,先在坐标轴上简单看一下聚类的结果,只不过是将前面的二维坐标变成了三维坐标 ( R , G , B ) (R,G,B) (R,G,B),代码如下:

import numpy as np
from sklearn.cluster import KMeans
import imageio
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


def draw_picture(data_arr, cluster_centers, labels):
    dots1 = data_arr[labels == 0]
    dots2 = data_arr[labels == 1]
    dots3 = data_arr[labels == 2]
    dots4 = data_arr[labels == 3]
    dots5 = data_arr[labels == 4]

    fig = plt.figure()
    ax = Axes3D(fig)

    ax.scatter(dots1[:, 0], dots1[:, 1], dots1[:, 2], marker='o',
               color='blue', alpha=0.7, label='dots1 samples', s=5)
    ax.scatter(dots2[:, 0], dots2[:, 1], dots2[:, 2], marker='o',
               color='green', alpha=0.7, label='dots2 samples', s=5)
    ax.scatter(dots3[:, 0], dots3[:, 1], dots3[:, 2], marker='o',
               color='red', alpha=0.7, label='dots3 samples', s=5)
    ax.scatter(dots4[:, 0], dots4[:, 1], dots4[:, 2], marker='o',
               color='purple', alpha=0.7, label='dots4 samples', s=5)
    ax.scatter(dots5[:, 0], dots5[:, 1], dots5[:, 2], marker='o',
               color='yellow', alpha=0.7, label='dots5 samples', s=5)
    ax.scatter(cluster_centers[:, 0], cluster_centers[:, 1], cluster_centers[:, 2], marker='x',
               color='black', alpha=0.7, label='centroids', s=5)

    ax.set_xlabel('R Channel')
    ax.set_ylabel('G Channel')
    ax.set_zlabel('B Channel')

    plt.savefig('./result_3d_s.png')
    plt.show()


if __name__ == '__main__':
    img = imageio.imread('./touxiang.png')
    img_flatten = img.reshape(-1, 3)

    kmeans = KMeans(n_clusters=5, init='k-means++', n_init=10, max_iter=300,
                    tol=1e4, verbose=0, random_state=1024, n_jobs=1)
    kmeans.fit(X=img_flatten)

    cluster_centers = kmeans.cluster_centers_
    labels = kmeans.labels_

    draw_picture(img_flatten, cluster_centers, labels)
    

  上面的参数在这篇博客中有介绍,在这里就不过多解释了,结果如下:
在这里插入图片描述在这里插入图片描述

  在Pycharm中默认显示的3D图像是不可以旋转的,可以通过如下设置:File − − > –> >Settings − − > –> >Tools − − > –> >Python Scientific − − > –> >Show plots in tool window ( ( (前面的去掉 ) ) ) − − > –> >Apply − − > –> >OK,然后通过旋转就可以看到聚类中心了 ( ( (即图中黑色圆点 ) ) )

  OK,fine,其实图像的结果也和上面一样了,只不过不把它放到坐标轴上,而是以数组的形式存起来,将下面的seg_img函数替换掉上面的draw_picture即可,代码如下:

def seg_img(img, labels):
    labels = labels.reshape(320, 320)
    img_seg = np.array(np.zeros(shape=(320, 320, 3), dtype=np.uint8))
    img_seg[labels == 0] = [250, 128, 114]
    img_seg[labels == 1] = [194, 194, 194]
    img_seg[labels == 2] = [153, 50, 204]
    img_seg[labels == 3] = [255, 255, 255]
    img_seg[labels == 4] = [100, 149, 237]

    plt.subplot(121)
    plt.axis('off')
    plt.imshow(img)

    plt.subplot(122)
    plt.axis('off')
    plt.imshow(img_seg)

    plt.savefig('./result_5k.png')
    plt.show()
    

  如果划分为四个类别,就是这样子的:在这里插入图片描述
  如果划分为五个类别,就是这样子的:在这里插入图片描述

  注:上面的颜色会随机分给各个类别。

2. Mean Shift分割图像

  实现流程和上述一样,只不过函数变成了MeanShift,这里只贴出改动的部分,代码如下:

  MeanShift函数的部分参数已注释,更详细的说明,请参考官方文档。

from sklearn.cluster import MeanShift


if __name__ == '__main__':
    img = imageio.imread('./touxiang.png')
    img_flatten = img.reshape(-1, 3)

	# bandwidth: 半径(或带宽), float型, 默认None
    # 如果没有给出, 则使用sklearn.cluster.estimate_bandwidth计算出半径(带宽)(可选)
    # seeds: 圆心(或种子), 数组类型, 即初始化的圆心, 默认None(可选)
    # 如果未设置, 则通过clustering.get_bin_seeds计算种子, 并使用带宽作为网格大小以及其他参数的默认值
    # bin_seeding: 布尔值. 如果为真, 初始内核位置不是所有点的位置, 而是点的离散版本的位置, 其中点被分类到其粗糙度对应于带宽的网格上
    # 将此选项设置为True将加速算法, 因为较少的种子将被初始化. 默认值: False, 如果种子参数(seeds)不为None则忽略
    # n_jobs: 任务使用的CPU数量
    # 如果bandwidth不设置, 代码运行会消耗较多时间
    meanshift = MeanShift(bandwidth=20, seeds=None, bin_seeding=True,
                          min_bin_freq=10, cluster_all=True, n_jobs=1)
    meanshift.fit(X=img_flatten)

    cluster_centers = meanshift.cluster_centers_
    labels = meanshift.labels_

    seg_img(img, labels)
    

  不同的半径会有不同的结果,可以去尝试不同的设置,部分结果如下:
在这里插入图片描述

  搞错了,再来(づ。◕ᴗᴗ◕。)づ(感觉还是蛮像的!哈哈哈哈哈哈哈哈哈)
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

3. DBSCAN分割图像

  实现流程和上述一样,只不过函数变成了DBSCAN,这里只贴出改动的部分,代码如下:

  DBSCAN函数的部分参数已注释,更详细的说明,请参考官方文档。

from sklearn.cluster import DBSCAN


if __name__ == '__main__':
    img = imageio.imread('./touxiang.png')
    img_flatten = img.reshape(-1, 3)

    # eps: 两个样本之间的最大距离, 即半径, 默认为0.5
    # min_samples: 作为核心点的邻域(即以其为圆心, eps为半径的圆, 含圆上的点)中的最小样本数(包括点本身)
    # 即MinPts, 默认为5
    # 其他参数可参考官方文档
    dbscan = DBSCAN(eps=0.5, min_samples=5)
    dbscan.fit(X=img_flatten)

    labels = dbscan.labels_

    seg_img(img, labels)
    

  运行结果如下:在这里插入图片描述

  对于图片来说,运行较占内存,可能上面的参数还要再配置一下。然后我又多尝试了几次,结果MemoryError了∑(っ°Д°;)っ卧槽,无情。官方是这样说的:
  大样本量的内存消耗
  默认情况下,此实现的内存效率不高,因为它在无法使用kd树或球树的情况下 ( ( (例如,稀疏矩阵 ) ) )构造了完整的成对相似度矩阵。该矩阵将消耗 n 2 n^2 n2个浮点数。解决此问题的几种机制是:

  • 将OPTICS聚类与该extract_dbscan方法结合使用 。OPTICS集群还可以计算完整的成对矩阵,但是一次只能在内存中保留一行 ( ( (内存复杂度 n ) n) n)
  • 可以用内存有效的方式预先计算稀疏半径邻域图 ( ( (假定缺少的条目不在eps之内 ) ) ),而dbscan可以使用metric =’precomputed’在其上运行。
  • 可以压缩数据集,方法是删除精确重复项 ( ( (如果数据中出现重复项 ) ) ),或者使用BIRCH。这样,对于大量的点,就只有相对较少的代表。然后,可以在拟合DBSCAN时提供一个sample_weight。

  我尝试用官方的方法去设置,然而并没有有效解决,然后受到上面第三条的启发,我就把图像缩放到了 128 ∗ 128 128*128 128128,问题得以解决。
  为了方便调参,将数据进行了归一化处理,修正代码如下:

	img_flatten = img.reshape(-1, 3) / 255.0

  调整后的运行结果如下:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

  eps越大,聚类的类别就越少;MinPts越大,聚类的类别也越少。根据经验,最好将MinPts设置为数据中特征的数量,eps使用小值通常是首选。

结束语

  本篇博客在使用DBSCAN时出了一些问题,图像的尺寸有些大,处理不了,然后就将图像进行放缩了。另外,由此也可以看出DBSCAN算法的弊端,就是参数需要不断去调整,相对来说还是较麻烦的,不过我看网上有说可以借助k-distance图来找最佳的eps,当然了官方也说有优化的方法,这些还有待探索。继续加油ヾ(◍°∇°◍)ノ゙

今天的文章大黄脸头像_图像分类算法分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/67422.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注