将图像转换为ASCII字符画的Python程序——Python练习1

    将图像转换为ASCII字符画的Python程序。使用了OpenCV库来处理图像,并使用K-means聚类算法来确定每个像素的颜色类别。然后根据颜色类别在输出的ASCII字符画中显示相应的字符。

一、代码详细讲解

#将图像转换为ASCII字符画的Python程序。
# 它使用了OpenCV库来处理图像,
# 并使用K-means聚类算法来确定每个像素的颜色类别。
# 然后根据颜色类别在输出的ASCII字符画中显示相应的字符。

import cv2   #图像处理
import random   #用于生成随机数
import numpy as np   #用于数组操作

#定义了一个名为img2strimg的函数,该函数接受一个图像帧和一个可选参数K(默认值为5),并返回一个ASCII字符画。
def img2strimg(frame, K=5):   
    if type(frame) != np.ndarray:   #检查输入的frame是否为NumPy数组类型,如果不是,则将其转换为NumPy数组。
        frame = np.array(frame)
    height, width, *_ = frame.shape  #获取图像的高度、宽度和其他信息
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)   #将图像从BGR颜色空间转换为灰度图像。
    # 将输入的彩色图像(BGR颜色空间)转换为灰度图像。cv2.cvtColor()函数用于执行颜色空间转换,其中frame是输入的彩色图像,
    # cv2.COLOR_BGR2GRAY指定了转换类型为从BGR到灰度。转换后的灰度图像存储在frame_gray变量中。
    frame_array = np.float32(frame_gray.reshape(-1))   #将灰度图像展平为一维数组,并将其转换为浮点数类型
    # 将灰度图像转换为一个一维的浮点数数组。首先,frame_gray.reshape(-1)将灰度图像重塑为一个一维数组,其中-1表示自动计算数组的长度。
    # 然后,np.float32()将该一维数组的数据类型转换为浮点数类型。
    # 最终,转换后的一维浮点数数组存储在frame_array变量中。
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)   #定义K-means聚类的终止条件和标志。
    #criteria:这是一个元组,用于指定K-means聚类的终止条件。
    # 它由两个参数组成:cv2.TERM_CRITERIA_EPS和cv2.TERM_CRITERIA_MAX_ITER。
    # 这两个参数分别表示迭代次数和误差阈值。在这个例子中,终止条件是当迭代次数达到10次或误差小于1.0时停止迭代。

    flags = cv2.KMEANS_RANDOM_CENTERS
    #flags:这是一个标志,用于指定K - means聚类算法的行为。
    # 在这个例子中,使用了cv2.KMEANS_RANDOM_CENTERS标志,表示初始中心点是随机选择的。

    # 得到 labels(类别)、centroids(矩心)
    #使用K-means聚类算法对图像进行聚类,得到标签(类别)、矩心(质心)。
    compactness, labels, centroids = cv2.kmeans(frame_array, K, None, criteria, 10, flags)
    #cv2.kmeans: 这是OpenCV库中的一个函数,用于执行K均值聚类算法。它接受以下参数:
#frame_array: 输入的图像数据,通常是一个二维或三维的NumPy数组。#K: 聚类的簇数,即要分成多少个类别。
#None: 初始质心的位置,这里设置为None表示让函数自动选择初始质心。#criteria: 停止迭代的条件,可以是一个包含两个元素的元组,第一个元素是指定最大迭代次数,第二个元素是指定误差阈值。
#10: 随机种子,用于初始化质心的位置。#flags: 其他标志位,用于控制算法的行为。
#该函数返回三个值:
#compactness: 紧密度,表示每个样本到其所属簇中心的距离之和。
#labels: 标签数组,每个元素对应于输入图像的一个像素,表示该像素属于哪个簇。
#centroids: 质心数组,每个元素表示一个簇的中心位置。
    centroids = np.uint8(centroids)   #将矩心转换为无符号整数类型。
    # labels 的数个矩心以随机顺序排列,所以需要简单处理矩心
    #对矩心进行排序,并根据排序结果计算不同矩心的明暗程度。
    centroids = centroids.flatten()
    #将"centroids"数组扁平化为一维数组。
    # 这意味着如果"centroids"是一个多维数组,那么它会被转换为一个一维数组,其中所有元素都按顺序排列。
    centroids_sorted = sorted(centroids)
    #sorted(centroids)对扁平化后的"centroids"数组进行排序,返回一个已排序的新列表,并将其赋值给变量"centroids_sorted"。
    # 获得不同 centroids 的明暗程度,0 为最暗
    #根据明暗程度确定阴影边界和明亮边界
    centroids_index = np.array([centroids_sorted.index(value) for value in centroids])
    #创建了一个名为"centroids_index"的NumPy数组,其中每个元素都是对应于"centroids"数组中元素的索引值。
    # 它通过遍历"centroids"数组中的每个元素,
    # 并使用centroids_sorted.index(value)来获取该元素在已排序的"centroids_sorted"列表中的索引位置。
    bright = [abs((3 * i - 2 * K) / (3 * K)) for i in range(1, 1 + K)]
    bright_bound = bright.index(np.min(bright))
    shadow = [abs((3 * i - K) / (3 * K)) for i in range(1, 1 + K)]
    shadow_bound = shadow.index(np.min(shadow))#函数找到列表中的最小值,并使用index()方法获取该最小值在列表中的索引。
    #创建了两个列表bright和shadow,分别表示亮度和阴影的值。
    # 找到了这两个列表中最小值的索引,分别存储在bright_bound和shadow_bound变量中。
    labels = labels.flatten()
    # 将 labels 转变为实际的明暗程度列表
    labels = centroids_index[labels]
    # 解析列表 将每行的像素值映射到对应的ASCII字符。
    labels_picked = [labels[rows * width:(rows + 1) * width:2] for rows in range(0, height, 2)]
    #rows * width: (rows + 1) * width:2,是一个切片操作,用于从labels列表中提取元素。
    #rows * width表示起始索引,即当前行的第一个元素的索引。
    #(rows + 1) * width表示结束索引,即下一行的第一个元素的索引。
    #2表示步长,表示每隔一个元素进行提取。
    #for rows in range(0, height, 2) 是一个循环语句,用于遍历height范围内的偶数行。
    #因此,该行代码的意思是从labels列表中每隔一个元素提取特定位置的元素,并将这些元素存储在labels_picked列表中。


    canvas = np.zeros((3 * height, 3 * width, 3), np.uint8)
# 创建长宽为原图三倍的白色画布
    canvas.fill(255)   #将画布填充为白色
    y = 8   #设置起始的纵坐标为8。
    #遍历解析后的列表,根据明暗程度在画布上绘制相应的ASCII字符。
    for rows in labels_picked:    #遍历labels_picked列表中的每一行元素
        x = 0   #设置起始的横坐标为0
        for cols in rows:   #遍历当前行中的每个元素
            if cols <= shadow_bound:   #如果当前元素的值小于等于阴影边界,则在画布上绘制一个随机的ASCII字符。
                cv2.putText(canvas, str(random.randint(2, 9)),
                            (x, y), cv2.FONT_HERSHEY_PLAIN, 0.45, 1)   #使用OpenCV库的putText函数在画布上绘制随机的ASCII字符。
            elif cols <= bright_bound:    #如果当前元素的值小于等于亮度边界,则在画布上绘制一个"-"字符。
                cv2.putText(canvas, "-", (x, y),
                            cv2.FONT_HERSHEY_PLAIN, 0.4, 0, 1)   #使用OpenCV库的putText函数在画布上绘制"-"字符。
            x += 6   #更新横坐标,每次增加6个像素
        y += 6   #更新纵坐标,每次增加6个像素
    return canvas   #返回绘制完成的画布




if __name__ == '__main__':
    fp = r"D:/static/static1.jpg"
    img = cv2.imread(fp)
    str_img = img2strimg(img)
    cv2.imwrite("D:/static/static1_ascll.jpg", str_img)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值