You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过瓦片对比实现图像瓦片列表的缩减?

问题描述

我有一批图像,希望通过生成瓦片列表并对图像建立索引的方式简化图像。目前正以单张图像进行测试,试图找到合适的瓦片对比算法,甚至可能推翻现有方案重新实现。

当前编写了如下代码用于生成瓦片:

def tileize(img):
    tile_list = []
    new_img = np.zeros((int(IMGX/TILESIZE),int(IMGY/TILESIZE),0))
    i = 0
    ri = 0
    for r in range(0,img.shape[0],TILESIZE):
        cj = 0
        for c in range(0,img.shape[1],TILESIZE):
            t1 = img[r:r+TILESIZE, c:c+TILESIZE,:]
            new_img[ri,cj] = i
            tile = Tile(t1)
            tile_list.append(tile)
            i+=1
            cj +=1
        ri +=1
    return tile_list,new_img

为了缩减tile_list,我创建了Tile类,期望通过set()去重:

class Tile(object): 
    def __init__(self, mat):
        self.mat = mat
        self.hist = cv2.calcHist([mat],[0],None,[256],[0,256])
    def __eq__(self, other):
        res = cv2.compareHist(self.hist,other.hist,cv2.HISTCMP_CORREL)
        if res > 0.95:
            return True
        return False
    def __hash__(self):
        return hash(self.hist.flatten())

但该方案无法生效,原因是hist为数组类型,直接对比Tile对象无法得到更短的列表。请问实现瓦片列表缩减的最佳方法是什么?


解决方案

你的方案失效核心原因是哈希值和相等判断逻辑不匹配:__hash__用的是直方图数组的哈希,但__eq__用的是相关性阈值判断,这违反了Python哈希表的规则——如果两个对象a == b为真,那么hash(a)必须等于hash(b)。现在的逻辑里,两个被判定为相等的Tile,哈希值几乎不可能相同,所以set()根本识别不出它们是重复项。

针对瓦片去重/缩减,推荐以下几种可行方案:

1. 修正哈希与相等判断的一致性

如果坚持用set()或字典去重,必须让相等的Tile拥有相同哈希值。可以把直方图做离散化处理,比如:

  • 将直方图归一化后,按阈值(比如0.01)把小值置0,保留关键特征
  • 将直方图数组转成不可变类型(如元组),再计算哈希,或者直接用离散后的特征作为哈希依据

修改后的Tile类示例:

class Tile(object): 
    def __init__(self, mat):
        self.mat = mat
        # 计算直方图并归一化,离散化处理
        self.hist = cv2.calcHist([mat],[0],None,[256],[0,256])
        self.hist = cv2.normalize(self.hist, self.hist).flatten()
        # 离散化:把小于阈值的置0,保留显著特征
        self.discrete_hist = tuple(v if v > 0.01 else 0 for v in self.hist)
    
    def __eq__(self, other):
        res = cv2.compareHist(self.hist, other.hist, cv2.HISTCMP_CORREL)
        return res > 0.95
    
    def __hash__(self):
        # 用离散后的直方图元组计算哈希
        return hash(self.discrete_hist)

这种方法能让相似的Tile更可能拥有相同哈希,配合__eq__的阈值判断,set()就能正确去重。

2. 聚类分组缩减列表

如果瓦片相似性是连续的(不是非黑即白的相等),聚类算法更合适:

  • 提取所有瓦片的特征(直方图、均值/方差、甚至SIFT特征)
  • 用K-Means、DBSCAN等算法将相似瓦片归为一类
  • 每个类别只保留一个代表瓦片,实现列表缩减

示例代码思路:

from sklearn.cluster import KMeans

# 提取所有瓦片的直方图特征
features = np.array([tile.hist.flatten() for tile in tile_list])
# K-Means聚类,假设分成N类(可根据需求调整)
kmeans = KMeans(n_clusters=50, random_state=42).fit(features)
# 按聚类标签分组,保留每组第一个瓦片
reduced_tiles = []
seen_labels = set()
for tile, label in zip(tile_list, kmeans.labels_):
    if label not in seen_labels:
        seen_labels.add(label)
        reduced_tiles.append(tile)

这种方法比单纯去重更灵活,能根据相似程度批量缩减,适合大规模瓦片处理。

3. 基于特征哈希的快速去重

如果追求效率,可以用**感知哈希(Perceptual Hash)**替代直方图:

  • 将瓦片缩放到小尺寸(如8x8),转灰度图
  • 计算均值,生成二进制哈希值
  • 哈希值相同的瓦片视为相似,直接去重

这种方法计算速度快,哈希值稳定,适合高吞吐量场景。

额外优化建议

  • 你的tileize函数里,new_img的形状定义有问题:np.zeros((int(IMGX/TILESIZE),int(IMGY/TILESIZE),0))最后一维是0,应该改成适合存储索引的类型,比如np.zeros((int(img.shape[0]/TILESIZE), int(img.shape[1]/TILESIZE)), dtype=np.int32),避免后续赋值出错。
  • 如果是彩色图像,当前直方图只计算了第0通道(BGR的B通道),应该考虑计算全通道直方图或者转为灰度图后计算,避免丢失颜色信息。

内容的提问来源于stack exchange,提问作者maugch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 12:45:49