概念介绍

  首先我想先介绍下有关的一些概念。

第一个概念:分辨率

  图像分辨率指图像中存储的信息量,指的是每英寸图像内有多少个像素点,分辨率的单位为PPI(Pixels Per Inch),通常叫做像素每英寸。一般情况下,图像分辨率越高,图像中包含的细节就越多,信息量也越大。图像分辨率分为空间分辨率和时间分辨率。通常,分辨率被表示成每一个方向上的像素数量,例如64*64的二维图像。但分辨率的高低其实并不等同于像素数量的多少,例如一个通过插值放大了5倍的图像并不表示它包含的细节增加了多少。图像超分辨率重建关注的是恢复图像中丢失的细节,即高频信息。 在大量的电子图像应用领域,人们经常期望得到高分辨率(简称HR)图像。但由于设备、传感器等原因,我们得到的图像往往是低分辨率图像(LR)。增加空间分辨率最直接的解决方法就是通过传感器制造技术减少像素尺寸(例如增加每单元面积的像素数量);另外一个增加空间分辨率的方法是增加芯片的尺寸,从而增加图像的容量。因为很难提高大容量的偶合转换率,所以这种方法一般不认为是有效的,因此,引出了图像超分辨率技术。

第二个概念:图像超分辨率

  图像超分辨率(Image Super Resolution)是指由一幅低分辨率图像或图像序列恢复出高分辨率图像。图像超分辨率技术分为超分辨率复原和超分辨率重建。目前, 图像超分辨率研究可分为 3个主要范畴: 基于插值(例如:双线性三次插值等)、 基于重建和基于学习的方法。
  超分辨率(Super-Resolution)即通过硬件或软件的方法提高原有图像的分辨率,通过一系列低分辨率的图像来得到一幅高分辨率的图像过程就是超分辨率重建。超分辨率重建的核心思想就是用时间带宽(获取同一场景的多帧图像序列)换取空间分辨率,实现时间分辨率向空间分辨率的转换。

第三个概念:与其他图像处理技术的关系

  这一部分里,我主要想要进行介绍的是:与“图像超分辨技术”能够产生相似效果的相关技术的内容对比。

图像修复与图像超分辨率之间的关系

  图像修复的目标是恢复一个被模糊或者噪声破坏的图像,但是它不改变图像的尺寸。事实上图像修复和SR复原在理论是完全相关的,超分辨率技术可以看作是第二代图像修复技术,主要区别是图像修复技术在处理后图像中的像素数并不增加。图像修复的有关内容可以查看我之前写过的有关文章,点击进行跳转

图像插值与图像超分辨率之间的关系

  图像插值,即增加单幅图像的尺寸。一般的插值并不能恢复LR采样过程中丢失的高频信息,但是图像超分辨率可以,因此图像插值方法不能被认作是SR技术。关于插值技术,其比较流行的是双三次线性插值算法,感兴趣的同学可以去进行有关的了解,其本质是关于像素点的方程组求解问题。

图像锐化与图像超分辨率之间的关系

  图像锐化可以提升高频信息,但仅增强已有的高频成分;超分辨率技术能估计出原始图像中没有表现出来的高分辨率细节。关于图像锐化技术,比较常见的方法有使用拉普拉斯算子、Sobel算子等,这两种都是非常常见的方法。

实现说明

  首先需要大家下载好OpenCV-Contrib,且版本大于4.2.0,大家可以使用如下指令进行安装。

pip install opencv-contrib-python

  之后我们需要使用到的是该库下的dnn_superres模块。该模块我在pycharm中使用的时候会出现报错红线,如下图所示。

  但这不影响其程序的运行,无视就好。
  这里我主要想要代码实现的算法有4种,分别是:双线性插值算法bilinear、双线性三次插值算法bicubic、以及在OpenCV中实现的EDSR和FSRCNN算法。
  bilinear以及bicubic算法属于图像处理中的经典算法,此处就不再进行额外的介绍了,感兴趣的读者可以自行查阅有关资料进行了解。
  EDSR可以提供2倍、3倍、4倍的训练模型,其优点在于其精度很高,但是模型本身的运行速度较慢。
  FSRCNN同样可以提供2倍、3倍、4倍的训练模型,其优点在于模型小巧且运行速度快,缺点在于其不够准确。
  bilinear以及bicubic算法不需要额外进行下载,因为其本质是一种对图像的数学运算;而EDSR以及FSRCNN则需要额外进行模型的下载,想要下载的,可以点击此处进行下载,提取码为:1234。分别对应着EDSR和FSRCNN两个的模型。

代码实现

  在这一部分中,我主要想要进行进行介绍的是有关代码的实现,内容如下所示。

import cv2
from cv2 import dnn_superres


def main():
    img_path = "3.png"
    # 可选择算法,bilinear, bicubic, edsr, fsrcnn
    algorithm = "bilinear"
    # algorithm = "edsr"
    # 放大比例,可输入值2,3,4
    scale = 4
    # 模型路径
    path = "EDSR_x4.pb"

    # 载入图像
    img = cv2.imread(img_path)
    # 如果输入的图像为空
    if img is None:
        print("Couldn't load image: " + str(img_path))
        return

    # 创建模型
    sr = dnn_superres.DnnSuperResImpl_create()

    if algorithm == "bilinear":
        img_new = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR)
    elif algorithm == "bicubic":
        img_new = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_CUBIC)
    elif algorithm == "edsr" or algorithm == "fsrcnn":
        # 读取模型
        sr.readModel(path)
        #  设定算法和放大比例
        sr.setModel(algorithm, scale)
        # 放大图像
        img_new = sr.upsample(img)
    else:
        print("Algorithm not recognized")

    # 如果失败
    if img_new is None:
        print("Upsampling failed")

    print("Upsampling succeeded. \n")

    # 展示图片
    cv2.namedWindow("Initial Image", cv2.WINDOW_AUTOSIZE)
    # 初始化图片
    cv2.imshow("Initial Image", img_new)
    cv2.imwrite("./saved.jpg", img_new)
    cv2.waitKey(0)


if __name__ == '__main__':
    main()

  此处我们未经过处理的原图如下所示:

  之后我们对其进行bilinear操作,算法的变更可以通过修改上述代码中的第8行、第13行来进行修改,如果使用的是bilinear或者是bicubic算法,只需要修改第8行即可,因为其不需要使用模型。bilinear操作结果如下所示。

  可以发现的是,其结果并没有发生太多的变化,之后我们进行bicubic算法的运行,其结果如下所示。

  可以发现的是,其相比较之前,细节部分有了一定的提升。接下来进行FSRCNN的执行,其结果如下所示。

  可以发现的是,其结果已经相比较之前,有了较为明显的进步,最后使用EDSR算法来进行处理,其结果如下所示。

  可以注意到的是,EDSR的代码执行速度最慢,但是他的结果是这几个里面最好的。

总结

  对于不同的场合,可以使用不同的方法,对于比较简陋的硬件设施、或者对实时性要求比较高的任务,可以使用例如FSRCNN的方法;如果是对实时性要求不高的任务且硬件设施较好的话,则使用EDSR会比较好一些。
  本文到此结束,谢谢大家!