PIL+ OpenCV + Python KMeans Color Clusering实现图片压缩+存储图片信息+像素聚类

OpenCV + Python KMeans Color Clusering(图片像素类聚)

1.图片批量压缩(不改变图片大小)

# 压缩图片
def yashuo_img(srcPath, dstPath):
    for filename in os.listdir(srcPath):
        # 如果不存在目的目录则创建一个,保持层级结构
        if not os.path.exists(dstPath):
            os.makedirs(dstPath)

        # 拼接完整的文件或文件夹路径
        srcFile = os.path.join(srcPath, filename)
        dstFile = os.path.join(dstPath, filename)

        # 如果是文件就处理
        if os.path.isfile(srcFile):
            try:
                # 打开原图片缩小后保存,可以用if srcFile.endswith(".jpg")或者split,splitext等函数等针对特定文件压缩
                sImg = Image.open(srcFile)
                w, h = sImg.size
                dImg = sImg.resize((int(w / 2), int(h / 2)), Image.ANTIALIAS)  # 设置压缩尺寸和选项,注意尺寸要用括号
                dImg.save(dstFile)  # 也可以用srcFile原路径保存,或者更改后缀保存,save这个函数后面可以加压缩编码选项JPEG之类的
                print(dstFile + " 成功!")
            except Exception:
                print(dstFile + "失败!")

2.获取图像矩阵转换成像素列表

cv2.imread读取的图片结果是BGR值

image = cv2.imread(dstFile)
# reshape the image to be a list of pixels
image = image.reshape((image.shape[0] * image.shape[1], 3))

3.调用聚类算法实现聚类

KMeans(n_clusters = 8,init =‘k-means ++’,n_init = 10,max_iter = 300,tol = 0.0001,precompute_distances =‘auto’,verbose = 0,random_state = None,copy_x = True,n_jobs = None,algorithm = ‘auto’)
参数:

  1. n_clusters int,默认= 8
    形成的簇数以及生成的质心数
  2. n_init int,默认值为10
    k均值算法将在不同质心种子下运行的次数。就惯性而言,最终结果将是n_init个连续运行的最佳输出
  3. max_iter int,默认为300
    单次运行的k均值算法的最大迭代次数。
  4. tol float,默认= 1e-4
    关于惯性的相对公差以声明收敛。
  5. precompute_distances’auto '或bool,默认=‘auto’
    预计算距离(更快,但占用更多内存)。
    ‘auto’:如果n_samples * n_clusters> 1200万,则不预先计算距离。使用双精度,这相当于每个作业大约100MB的开销。
    正确:始终预先计算距离。
    False:永远不要预先计算距离。
    详细int,默认值= 0
    详细模式。
  6. random_state int,RandomState实例,默认=无
    确定质心初始化的随机数生成。使用整数使随机性具有确定性。请参阅词汇表。
  7. copy_x bool,默认为True
    当预先计算距离时,从数值上更精确地确定数据的中心。如果copy_x为True(默认值),则不修改原始数据,确保X为C连续的。如果为False,则会修改原始数据,并在函数返回之前放回原始数据,但是可能会通过减去然后加上数据均值而引入小的数值差异,在这种情况下,也不会确保数据是C连续的,这可能会导致大幅放缓。
  8. n_jobs int,默认=无
    用于计算的作业数。通过计算每个并行运行的n_init来工作。
    None除非joblib.parallel_backend上下文中,否则表示1 。 -1表示使用所有处理器。有关 更多详细信息,请参见词汇表。
  9. 算法{“ auto”,“ full”,“ elkan”},默认=“ auto”
    使用K均值算法。经典的EM风格算法是“完整”的。通过使用三角形不等式,“ elkan”变体更为有效,但目前不支持稀疏数据。“自动”为密集数据选择“ elkan”,为稀疏数据选择“完整”。
#聚类的类别个数
k = 7
clt = KMeans(n_clusters=k)
clt.fit(image)

4.直方图算法实现

def centroid_histogram(clt):
    # 聚类标签数量
    # 基于分配给每个簇的像素数
    numLabels = np.arange(0, len(np.unique(clt.labels_)) + 1)
    (hist, _) = np.histogram(clt.labels_, bins=numLabels)
    # 将直方图规范化,使其总和为1
    hist = hist.astype("float")
    hist /= hist.sum()

    return hist


def plot_colors(hist, centroids):
    # 初始化表示相对频率的条形图
    # 每种颜色的
    bar = np.zeros((50, 300, 3), dtype="uint8")
    startX = 0
    # 循环每个簇的百分比和
    # 每个集群
    for (percent, color) in zip(hist, centroids):
        # 绘制每个簇的相对百分比
        endX = startX + (percent * 300)
        cv2.rectangle(bar, (int(startX), 0), (int(endX), 50),
                      color.astype("uint8").tolist(), -1)
        startX = endX

    return bar

5.将数据写入excel(xlsxwriter+openpyxl)

wb = xlsxwriter.Workbook('图片颜色数据.xlsx', {'constant_memory': True})
ws = wb.add_worksheet()
head = ['图片', 'red', 'green', 'blue', 'huers', 'saturation','brightness']
ws.write_row(0, 0, head)
for val in rgblist:
	for j in range(len(val)):
		ws.write_row(m, 0, val)
    m = m + 1
wb.close()

我这里贴的只是如何写表格,rgblist变量没有写出来,rgblist是一个二维数组

6.画散点图和展现图片

def show(image, filename, k):
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    plt.figure()
    plt.title('%s' % filename)
    plt.subplot(221)
    plt.axis("off")
    plt.imshow(image)
    # plt.show()
    # reshape the image to be a list of pixels
    image = image.reshape((image.shape[0] * image.shape[1], 3))
    # print(image)
    plt.subplot(212)
    # # plt.show()
    clt = KMeans(n_clusters=k)
    clt.fit(image)

    coo_X = []  # x坐标列表
    coo_Y = []  # y坐标列表
    coo_Z = []  # z坐标列表
    for i in range(len(image)):
        coo_X.append(image[i][0])
        coo_Y.append(image[i][1])
        coo_Z.append(image[i][2])
    plt.scatter(coo_X, coo_Y, coo_Z, c=clt.labels_, alpha=0.5)

    # build a histogram of clusters and then create a figure
    # representing the number of pixels labeled to each color
    hist = centroid_histogram(clt)
    bar = plot_colors(hist, clt.cluster_centers_)

    # show our color bart
    plt.subplot(222)
    plt.axis("off")
    plt.imshow(bar)
    plt.show()
    print("执行完成")

7.计算图片的RGB均值

# 计算图片的rgb均值
def compute(path):
    img = cv2.imread(path,1)
    r = np.mean(img[:, :, 0])
    g = np.mean(img[:, :, 1])
    b = np.mean(img[:, :, 2])
    return r, g, b

8.将RGB值转换成HSV

RGB --> HSV 转换公式
在这里插入图片描述
代码就是实现公式,看公式就可以了

def rgb2hsv(r, g, b):
    r, g, b = r/255.0, g/255.0, b/255.0
    mx = max(r, g, b)
    mn = min(r, g, b)
    m = mx-mn
    if mx == mn:
        h = 0
    elif mx == r:
        if g >= b:
            h = ((g-b)/m)*60
        else:
            h = ((g-b)/m)*60 + 360
    elif mx == g:
        h = ((b-r)/m)*60 + 120
    elif mx == b:
        h = ((r-g)/m)*60 + 240
    if mx == 0:
        s = 0
    else:
        s = m/mx
    v = mx
    return h, s, v

9.完整代码

import numpy as np
import cv2, os
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import cv2
from openpyxl import Workbook
import xlsxwriter, time
from PIL import Image


def centroid_histogram(clt):
    # 聚类标签数量
    # 基于分配给每个簇的像素数
    numLabels = np.arange(0, len(np.unique(clt.labels_)) + 1)
    (hist, _) = np.histogram(clt.labels_, bins=numLabels)
    # 将直方图规范化,使其总和为1
    hist = hist.astype("float")
    hist /= hist.sum()

    return hist


def plot_colors(hist, centroids):
    # 初始化表示相对频率的条形图
    # 每种颜色的
    bar = np.zeros((50, 300, 3), dtype="uint8")
    startX = 0
    # 循环每个簇的百分比和
    # 每个集群
    for (percent, color) in zip(hist, centroids):
        # 绘制每个簇的相对百分比
        endX = startX + (percent * 300)
        cv2.rectangle(bar, (int(startX), 0), (int(endX), 50),
                      color.astype("uint8").tolist(), -1)
        startX = endX

    return bar

# 压缩图片
def yashuo_img(srcPath, dstPath):
    for filename in os.listdir(srcPath):
        # 如果不存在目的目录则创建一个,保持层级结构
        if not os.path.exists(dstPath):
            os.makedirs(dstPath)

        # 拼接完整的文件或文件夹路径
        srcFile = os.path.join(srcPath, filename)
        dstFile = os.path.join(dstPath, filename)

        # 如果是文件就处理
        if os.path.isfile(srcFile):
            try:
                # 打开原图片缩小后保存,可以用if srcFile.endswith(".jpg")或者split,splitext等函数等针对特定文件压缩
                sImg = Image.open(srcFile)
                w, h = sImg.size
                dImg = sImg.resize((int(w / 2), int(h / 2)), Image.ANTIALIAS)  # 设置压缩尺寸和选项,注意尺寸要用括号
                dImg.save(dstFile)  # 也可以用srcFile原路径保存,或者更改后缀保存,save这个函数后面可以加压缩编码选项JPEG之类的
                print(dstFile + " 成功!")
            except Exception:
                print(dstFile + "失败!")

# 计算图片的rgb均值
def compute(path):
    img = cv2.imread(path,1)
    r = np.mean(img[:, :, 0])
    g = np.mean(img[:, :, 1])
    b = np.mean(img[:, :, 2])
    return r, g, b


def rgb2hsv(r, g, b):
    r, g, b = r/255.0, g/255.0, b/255.0
    mx = max(r, g, b)
    mn = min(r, g, b)
    m = mx-mn
    if mx == mn:
        h = 0
    elif mx == r:
        if g >= b:
            h = ((g-b)/m)*60
        else:
            h = ((g-b)/m)*60 + 360
    elif mx == g:
        h = ((b-r)/m)*60 + 120
    elif mx == b:
        h = ((r-g)/m)*60 + 240
    if mx == 0:
        s = 0
    else:
        s = m/mx
    v = mx
    return h, s, v

def show(image, filename, k):
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    plt.figure()
    plt.title('%s' % filename)
    plt.subplot(221)
    plt.axis("off")
    plt.imshow(image)
    # plt.show()
    # reshape the image to be a list of pixels
    image = image.reshape((image.shape[0] * image.shape[1], 3))
    # print(image)
    plt.subplot(212)
    # # plt.show()
    clt = KMeans(n_clusters=k)
    clt.fit(image)

    coo_X = []  # x坐标列表
    coo_Y = []  # y坐标列表
    coo_Z = []  # z坐标列表
    for i in range(len(image)):
        coo_X.append(image[i][0])
        coo_Y.append(image[i][1])
        coo_Z.append(image[i][2])
    plt.scatter(coo_X, coo_Y, coo_Z, c=clt.labels_, alpha=0.5)

    # build a histogram of clusters and then create a figure
    # representing the number of pixels labeled to each color
    hist = centroid_histogram(clt)
    bar = plot_colors(hist, clt.cluster_centers_)

    # show our color bart
    plt.subplot(222)
    plt.axis("off")
    plt.imshow(bar)
    plt.show()
    print("执行完成")

if __name__ == '__main__':
    start_time = time.time()
    # 指定要压缩的文件夹
    srcPath = 'C:/Users/AdminUser/Desktop/grls'
    # 压缩后文件夹
    dstPath = 'C:/Users/AdminUser/Desktop/ComperssImg'
    m = 1
    k = 7
    a = 1
    # 图片压缩
    yashuo_img(srcPath, dstPath)
    wb = xlsxwriter.Workbook('图片颜色数据.xlsx', {'constant_memory': True})
    ws = wb.add_worksheet()
    head = ['图片', 'red', 'green', 'blue', 'huers', 'saturation','brightness']
    ws.write_row(0, 0, head)
    rgblist = []
    for filename in os.listdir(dstPath):
        print("。。。。。")
        dstFile = os.path.join(dstPath, filename)
        result = []
        result.append(filename)
        if os.path.isfile(dstFile):
            rgb = r,g,b = compute(dstFile)
            hsv = h,s,v = rgb2hsv(r,g,b)
            rgbs = list(rgb)
            hsvs = list(hsv)
            result.extend(rgbs)
            result.extend(hsvs)
            print('开始处理第%s张图片' % a)
            image = cv2.imread(dstFile)
            show(image, filename, k)
            a = a + 1
        rgblist.append(result)
    # 写入表格
    for val in rgblist:
        for j in range(len(val)):
            ws.write_row(m, 0, val)
        m = m + 1
    wb.close()
    end_time = time.time()
    print('本次运行共耗时%s秒' % (end_time - start_time))

10.运行截图

在这里插入图片描述
在这里插入图片描述
由于图片太多,就提取两张图片可是化结果
在这里插入图片描述

最后贴上我学习:sklearn.cluster学习网站

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值