此篇文章会持续更新,不断进行算法的优化和功能完善,敬请期待。

一、任务目的

在监控等生活场景中,拍下的照片往往分辨率较低,对于人脸识别等用途具有较大的困难。所以本篇文章想要设计简单算法初步实现低分辨率的超分,以实现模糊图像的清晰化,作为本系列文章迭代的第一篇。

二、解决方案

1.处理训练集图像

我们需要通过训练批量高低分辨率对应的图像,已达到最终由低分辨率图像生成超分辨率图像的目的。然而,如何训练呢?

首先,我们要去对应的网站下载其提供的数据集,比如博主下载的就是div2k中的数据集,如下图所示。
在这里插入图片描述
其中画红线的包含train的就是我们所需要的数据集(高分辨率图像和对应下采样3倍的低分辨率头像),包含valid的就是验证集,用于完成代码之后验证代码的有效性。本小节里只需要关注train训练集。

训练集下载好了,我们如何对其进行数据处理?

大家通过阅读图像超分有关论文可以发现,其中之一的方法就是分别将训练集中的高低分辨率图像划分成若干个块(patches),比如一个分辨率为300300的图像,想将它划分为33的小块,就可以划分100*100个小块。

其python代码如下:

# 从图像中提取补丁
def extract_patches_from_image(img, patch_size):
    patches = []
    for i in range(0, img.shape[0] - patch_size + 1, patch_size):
        for j in range(0, img.shape[1] - patch_size + 1, patch_size):
            patch = img[i:i + patch_size, j:j + patch_size]
            patches.append(patch)
    return np.array(patches)

2.对处理好的数据进行训练

在第一步中我们已经获取了许多小块,这一小节中就要解决如何处理这些小块,小块也叫补丁。

在本算法中,我们使用K近邻(K-Nearest Neighbors, KNN)模型用来寻找低分辨率(LR)补丁与高分辨率(HR)补丁之间的对应关系。构建KNN模型的关键步骤包括:

  • 特征向量化:将每个补丁展平为一维数组,这样就可以作为KNN模型的输入特征。例如,一个尺寸为3x3的彩色补丁会被转换成长度为3x3x3=27的一维数组。

  • 创建并训练KNN模型:使用LR补丁的一维表示来训练KNN模型。这个模型将会学习到如何根据LR补丁找到最相似的几个HR补丁。

可以通过NearestNeighbors函数实现上述步骤,它能用于查找低分辨率(LR)补丁的最近邻,当输入待验证的低分辨率图像补丁时,通过查找其最近邻对应的高分辨率(HR)补丁,便可实现低分辨率补丁的超分,将这些超分辨率补丁拼在一起,便可实现整体的超分。

然而,如果我的n_neighbors属性设为5,如何衡量这5个最近邻的权重,使他们可以很好的拟合成最合适的补丁呢?

方法有很多种,这里选择最简单的计算权重方法,逆距离加权法。公式为w=1 / distance + 1e-5 (1e-5是为了避免除以0, distance为到最近邻的距离)

代码如下:

# 查找邻居并计算权重
def find_nearest_patches_with_weights(patch, nbrs):
    distances, indices = nbrs.kneighbors(patch.reshape(1, -1))
    weights = 1 / (distances + 1e-5)  # 避免除以0
    weights = weights / np.sum(weights)  # 归一化权重
    return indices, weights

# 使用多邻居和权重重建高分辨率图像
def super_resolve_image(low_res_img, nbrs, high_res_patches, patch_size = low_path_size):
    patches = extract_patches_from_image(low_res_img, patch_size)
    scale_factor = factor#高低分辨率图像之间的倍数
    high_res_img = np.zeros((low_res_img.shape[0] * scale_factor, low_res_img.shape[1] * scale_factor, 3),
                            dtype=np.uint8)

    for i in range(0, high_res_img.shape[0] - patch_size * scale_factor + 1, patch_size * scale_factor):
        for j in range(0, high_res_img.shape[1] - patch_size * scale_factor + 1, patch_size * scale_factor):
            idx = (i // (patch_size * scale_factor)) * (high_res_img.shape[1] // (patch_size * scale_factor)) + (
                        j // (patch_size * scale_factor))
            if idx >= len(patches):  # 如果已经处理完所有的补丁,提前跳出循环
                break
            nearest_indices, weights = find_nearest_patches_with_weights(patches[idx], nbrs)
            high_res_patch = np.sum(
                [weights[0, k] * high_res_patches[nearest_indices[0, k]] for k in range(len(weights[0]))], axis=0)

            # 确保补丁大小与目标区域大小匹配
            end_i = min(i + patch_size * scale_factor, high_res_img.shape[0])
            end_j = min(j + patch_size * scale_factor, high_res_img.shape[1])
            high_res_img[i:end_i, j:end_j] = high_res_patch[:end_i - i, :end_j - j]

    return high_res_img

三、不足之处

上面就是算法的核心代码了,如果需要观测超分图像与对应高分图像之间的差距,可以使用RMS值进行验证。上述代码的不足之处仍有很多,我们会在接下来的文章中继续优化,这里先列举几点。

1.权重计算算法

该算法虽然简单易懂,但是对噪声数据非常敏感,可能会影响最终的合成结果,除此之外,还有许多缺点,故本算法待改进。

2.图片不光滑

由于本算法是将一个一个补丁没有经过处理就拼接在一起,故而会导致补丁与补丁的连接处不平滑,如下图所示。
在这里插入图片描述
显而易见超分辨率图像不够平滑。

总结

本篇文章讲解了如何实现对低分辨率图像的超分,由于写的匆忙,一些细节的概念没有说的很详尽,有时间会编辑更新,下一篇会对本片的算法进行优化,敬请期待~~~~

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐