如何基于numpy.unique实现可续算的直方图计算以解决大图像数据集内存不足问题
如何基于numpy.unique实现可续算的直方图计算以解决大图像数据集内存不足问题
嗨,这个问题我之前也遇到过——处理大量图像时内存不够真的头疼!其实不用自己从零实现update_unique这种函数,有几个现成的思路可以轻松解决,而且效率还更高:
1. 针对固定范围灰度图(如8位):用直方图累加(最推荐)
如果你的图像是常见的8位灰度图(取值0-255),直接用np.histogram统计单张图的直方图,然后累加总计数就好。这种方法完全不需要把所有图像加载到内存,每次只处理一张,内存占用极低,而且速度比合并np.unique结果快得多:
from os import listdir from os.path import isfile, join import numpy as np import matplotlib.image as img import matplotlib.pyplot as plt work_dir = 'path/to/my/images' # 用join拼接路径更规范,避免手动加斜杠出错 images = [join(work_dir, f) for f in listdir(work_dir) if isfile(join(work_dir, f))] # 初始化总直方图:8位灰度图取值0-255,所以需要256个计数位 # 用int64类型防止计数溢出(图像数量多的话int32可能不够) total_counts = np.zeros(256, dtype=np.int64) # 直方图的bins要设为左闭右开,所以范围是0到256 bins = np.arange(257) for img_path in images: # 读取单张图像 img_data = img.imread(img_path) # 统计当前图像的直方图 counts, _ = np.histogram(img_data, bins=bins) # 累加到总计数 total_counts += counts # 生成对应的灰度值数组 values = np.arange(256) plt.plot(values, total_counts) plt.show()
2. 针对任意取值的图像:用字典累加unique结果
如果你的图像是16位、浮点型或者取值范围不固定的情况,可以用Python字典来逐张累加np.unique的结果,代码量很少,完全满足你的“不想自己复杂实现”的需求:
from os import listdir from os.path import isfile, join import numpy as np import matplotlib.image as img import matplotlib.pyplot as plt work_dir = 'path/to/my/images' images = [join(work_dir, f) for f in listdir(work_dir) if isfile(join(work_dir, f))] # 用字典存储每个灰度值的总计数 count_dict = {} for img_path in images: img_data = img.imread(img_path) # 获取当前图像的unique值和对应计数 vals, cnts = np.unique(img_data, return_counts=True) # 更新字典:存在则累加,不存在则新增 for val, cnt in zip(vals, cnts): if val in count_dict: count_dict[val] += cnt else: count_dict[val] = cnt # 把字典转成排序后的numpy数组(方便画图) values = np.array(sorted(count_dict.keys())) counts = np.array([count_dict[v] for v in values]) plt.plot(values, counts) plt.show()
3. 非Python方案:用系统工具批量处理
如果你完全不想用Python,也可以用ImageMagick这类命令行工具来处理,配合awk做累加,适合超大规模的图像数据集,内存占用几乎可以忽略:
# 第一步:遍历所有图像,统计每张图的直方图到临时文件 for img in path/to/my/images/*.png; do # 用ImageMagick的convert命令生成直方图信息,提取灰度值和计数 convert "$img" -format "%c" histogram:info:- | awk '{print $2, $1}' > "${img}.hist" done # 第二步:累加所有临时文件的计数,生成总直方图 awk '{a[$1] += $2} END{for(k in a) print k, a[k]}' path/to/my/images/*.hist > total_hist.txt
之后你可以把total_hist.txt导入Python画图,或者直接用gnuplot等工具可视化。
备注:内容来源于stack exchange,提问作者ragdollfun
相关产品推荐
相关产品推荐

