图像缩放_图像缩放原理 - CSDN
精华内容
参与话题
  • 图像缩放变换

    千次阅读 2018-03-24 19:34:37
    在日常工作中,我们经常需要对图像进行缩放(放大、缩小),旋转、平移等各种操作,这类操作统称为图像的几何变换。相对于前面提到的灰度变换,几何变换是改变了原图像像素点在新图像中的空间位置。 我们首先来看看...

    在日常工作中,我们经常需要对图像进行缩放(放大、缩小),旋转平移等各种操作,这类操作统称为图像的几何变换。相对于前面提到的灰度变换,几何变换是改变了原图像像素点在新图像中的空间位置。

    我们首先来看看图像缩放操作。假设一幅图像是100×100像素大小,放大一倍后是200×200大小。图像中的每一个像素点位置可以看作是一个点,也可以看作是二维平面上的一个矢量。图像缩放,本质上就是将每个像素点的矢量进行缩放,也就是将矢量x方向和y方向的坐标值缩放。也就是[x, y]变成了[kxx,kyy],一般情况下kx=ky,但是很多时候也不相同,例如将100×100的图像变成400×300的图像。学过线性代数的同学很快就能知道,这可以表示成矩阵乘法的形式:

    (5)[uv]=[kx00ky][xy]

    通过上述矩阵乘法的形式,我们就把原图像上的每一个像素点映射到新图像上相应的像素点了,这称为前向映射

    但是,我们很快注意到,原始图像有100×100=10000个像素点,而变换后的图像是200×200=40000个像素点。纵使把原始图像的10000个像素点全部映射到新图像上的对应点上,新图像上仍然有40000-10000=30000个点没有与原图像进行对应,那这30000个像素点的灰度值从何而来呢?

    我们把上面的矩阵表达式稍微转换下,两边乘以放大矩阵的逆矩阵:

    (6)[kx00ky]1[uv]=[xy]

    通过上面的式子,我们可以将新图像中的每一个像素点[u, v]与原图像中的一个像素点[x, y]对应起来了。这称为后向映射。显然后向映射比前向映射更有效。

    import cv2
    import numpy as np
    
    lenna100 = cv2.imread("lenna100.png", 0)
    row, col = lenna100.shape
    kx, ky = 2, 2
    A = np.mat([[kx, 0], [0, ky]])
    lenna200 = np.zeros((kx * row, ky * col))
    
    for r in range(kx * row):
        for l in range(ky * col):
            v = np.dot(A.I, np.array([r, l]).T)
            lenna200[r, l] = lenna100[int(v[0, 0]), int(v[0, 1])]
    
    cv2.imshow("lenna100", lenna100)
    cv2.imshow("lenna200", lenna200.astype("uint8"))
    cv2.waitKey()

    这里写图片描述

    展开全文
  • 图像缩放的三种方法

    千次阅读 2004-11-29 11:41:00
    用线性插值算法实现图像缩放 在Windows中做过图像方面程序的人应该都知道Windows的GDI有一个API函数:StretchBlt,对应在VCL中是TCanvas类的StretchDraw方法。它可以很简单地实现图像缩放操作。但问题是它是用了...
    用线性插值算法实现图像缩放  
    在Windows中做过图像方面程序的人应该都知道Windows的GDI有一个API函数:StretchBlt,对应在VCL中是TCanvas类的StretchDraw方法。它可以很简单地实现图像的缩放操作。但问题是它是用了速度最快,最简单但效果也是最差的“最近邻域法”,虽然在大多数情况下,它也够用了,但对于要求较高的情况就不行了。

    不久前我做了一个小玩意儿(见《人个信息助理之我的相册》),用于管理我用DC拍的一堆照片,其中有一个插件提供了缩放功能,目前的版本就是用了StretchDraw,有时效果不能令人满意,我一直想加入两个更好的:线性插值法和三次样条法。经过研究发现三次样条法的计算量实在太大,不太实用,所以决定就只做线性插值法的版本了。

    从数字图像处理的基本理论,我们可以知道:图像的变形变换就是源图像到目标图像的坐标变换。简单的想法就是把源图像的每个点坐标通过变形运算转为目标图像的相应点的新坐标,但是这样会导致一个问题就是目标点的坐标通常不会是整数,而且像放大操作会导致目标图像中没有被源图像的点映射到,这是所谓“向前映射”方法的缺点。所以一般都是采用“逆向映射”法。

    但是逆向映射法同样会出现映射到源图像坐标时不是整数的问题。这里就需要“重采样滤波器”。这个术语看起来很专业,其实不过是因为它借用了电子信号处理中的惯用说法(在大多数情况下,它的功能类似于电子信号处理中的带通滤波器),理解起来也不复杂,就是如何确定这个非整数坐标处的点应该是什么颜色的问题。前面说到的三种方法:最近邻域法,线性插值法和三次样条法都是所谓的“重采样滤波器”。

    所谓“最近邻域法”就是把这个非整数坐标作一个四舍五入,取最近的整数点坐标处的点的颜色。而“线性插值法”就是根据周围最接近的几个点(对于平面图像来说,共有四点)的颜色作线性插值计算(对于平面图像来说就是二维线性插值)来估计这点的颜色,在大多数情况下,它的准确度要高于最近邻域法,当然效果也要好得多,最明显的就是在放大时,图像边缘的锯齿比最近邻域法小非常多。当然它同时还带业个问题:就是图像会显得比较柔和。这个滤波器用专业术语来说(呵呵,卖弄一下偶的专业^_^)叫做:带阻性能好,但有带通损失,通带曲线的矩形系数不高。至于三次样条法我就不说了,复杂了一点,可自行参考数字图像处理方面的专业书籍,如本文的参考文献。

    再来讨论一下坐标变换的算法。简单的空间变换可以用一个变换矩阵来表示:

    [x’,y’,w’]=[u,v,w]*T

    其中:x’,y’为目标图像坐标,u,v为源图像坐标,w,w’称为齐次坐标,通常设为1,T为一个3X3的变换矩阵。

    这种表示方法虽然很数学化,但是用这种形式可以很方便地表示多种不同的变换,如平移,旋转,缩放等。对于缩放来说,相当于:

                             [Su 0 0 ]
    [x, y, 1] = [u, v, 1] * | 0 Sv 0 |
                             [0 0 1 ]
                
    其中Su,Sv分别是X轴方向和Y轴方向上的缩放率,大于1时放大,大于0小于1时缩小,小于0时反转。

    矩阵是不是看上去比较晕?其实把上式按矩阵乘法展开就是:

    { x = u * Su

    { y = v * Sv

    就这么简单。^_^

    有了上面三个方面的准备,就可以开始编写代码实现了。思路很简单:首先用两重循环遍历目标图像的每个点坐标,通过上面的变换式(注意:因为是用逆向映射,相应的变换式应该是:u = x / Su 和v = y / Sv)取得源坐标。因为源坐标不是整数坐标,需要进行二维线性插值运算:

    P = n*b*PA + n * ( 1 – b )*PB + ( 1 – n ) * b * PC + ( 1 – n ) * ( 1 – b ) * PD

    其中:n为v(映射后相应点在源图像中的Y轴坐标,一般不是整数)下面最接近的行的Y轴坐标与v的差;同样b也类似,不过它是X轴坐标。PA-PD分别是(u,v)点周围最接近的四个(左上,右上,左下,右下)源图像点的颜色(用TCanvas的Pixels属性)。P为(u,v)点的插值颜色,即(x,y)点的近似颜色。

    这段代码我就不写的,因为它的效率实在太低:要对目标图像的每一个点的RGB进行上面那一串复杂的浮点运算。所以一定要进行优化。对于VCL应用来说,有个比较简单的优化方法就是用TBitmap的ScanLine属性,按行进行处理,可以避免Pixels的像素级操作,对性能可以有很大的改善。这已经是算是用VCL进行图像处理的基本优化常识了。不过这个方法并不总是管用的,比如作图像旋转的时候,这时需要更多的技巧。

    无论如何,浮点运算的开销都是比整数大很多的,这个也是一定要优化掉的。从上面可以看出,浮点数是在变换时引入的,而变换参数Su,Sv通常就是浮点数,所以就从它下手优化。一般来说,Su,Sv可以表示成分数的形式:

    Su = ( double )Dw / Sw; Sv = ( double )Dh / Sh

    其中Dw, Dh为目标图像的宽度和高度,Sw, Sh为源图像的宽度和高度(因为都是整数,为求得浮点结果,需要进行类型转换)。

    将新的Su, Sv代入前面的变换公式和插值公式,可以导出新的插值公式:

    因为:

    b = 1 – x * Sw % Dw / ( double )Dw; n = 1 – y * Sh % Dh / ( double )Dh

    设:

    B = Dw – x * Sw % Dw; N = Dh – y * Sh % Dh

    则:

    b = B / ( double )Dw; n = N / ( double )Dh

    用整数的B,N代替浮点的b, n,转换插值公式:

    P = ( B * N * ( PA – PB – PC + PD ) + Dw * N * PB + DH * B * PC + ( Dw * Dh – Dh * B – Dw * N ) * PD ) / ( double )( Dw * Dh )

    这里最终结果P是浮点数,对其四舍五入即可得到结果。为完全消除浮点数,可以用这样的方法进行四舍五入:

    P = ( B * N … * PD + Dw * Dh / 2 ) / ( Dw * Dh )

    这样,P就直接是四舍五入后的整数值,全部的计算都是整数运算了。

    简单优化后的代码如下:

    int __fastcall TResizeDlg::Stretch_Linear(Graphics::TBitmap * aDest, Graphics::TBitmap * aSrc)
    {
        int sw = aSrc->Width - 1, sh = aSrc->Height - 1, dw = aDest->Width - 1, dh = aDest->Height - 1;
        int B, N, x, y;
        int nPixelSize = GetPixelSize( aDest->PixelFormat );
        BYTE * pLinePrev, *pLineNext;
        BYTE * pDest;
        BYTE * pA, *pB, *pC, *pD;
        for ( int i = 0; i <= dh; ++i )
        {
            pDest = ( BYTE * )aDest->ScanLine[i];
            y = i * sh / dh;
            N = dh - i * sh % dh;
            pLinePrev = ( BYTE * )aSrc->ScanLine[y++];
            pLineNext = ( N == dh ) ? pLinePrev : ( BYTE * )aSrc->ScanLine[y];
            for ( int j = 0; j <= dw; ++j )
            {
                x = j * sw / dw * nPixelSize;
                B = dw - j * sw % dw;
                pA = pLinePrev + x;
                pB = pA + nPixelSize;
                pC = pLineNext + x;
                pD = pC + nPixelSize;
                if ( B == dw )
                {
                    pB = pA;
                    pD = pC;
                }
                for ( int k = 0; k < nPixelSize; ++k )
                    *pDest++ = ( BYTE )( int )(
                        ( B * N * ( *pA++ - *pB - *pC + *pD ) + dw * N * *pB++
                        + dh * B * *pC++ + ( dw * dh - dh * B - dw * N ) * *pD++
                        + dw * dh / 2 ) / ( dw * dh )
                    );
            }
        }
        return 0;
    }

    应该说还是比较简洁的。因为宽度高度都是从0开始算,所以要减一,GetPixelSize是根据PixelFormat属性来判断每个像素有多少字节,此代码只支持24或32位色的情况(对于15或16位色需要按位拆开—因为不拆开的话会在计算中出现不期望的进位或借位,导致图像颜色混乱—处理较麻烦;对于8位及8位以下索引色需要查调色板,并且需要重索引,也很麻烦,所以都不支持;但8位灰度图像可以支持)。另外代码中加入一些在图像边缘时防止访问越界的代码。

    通过比较,在PIII-733的机器上,目标图像小于1024x768的情况下,基本感觉不出速度比StretchDraw有明显的慢(用浮点时感觉比较明显)。效果也相当令人满意,不论是缩小还是放大,图像质量比StretchDraw方法有明显提高。

    不过由于采用了整数运算,有一个问题必须加以重视,那就是溢出的问题:由于式中的分母是dw * dh,而结果应该是一个Byte即8位二进制数,有符号整数最大可表示31位二进制数,所以dw * dh的值不能超过23位二进制数,即按2:1的宽高比计算目标图像分辨率不能超过4096*2048。当然这个也是可以通过用无符号数(可以增加一位)及降低计算精度等方法来实现扩展的,有兴趣的朋友可以自己试试。

    当然这段代码还远没有优化到极致,而且还有很多问题没有深入研究,比如抗混叠(anti-aliasing)等,有兴趣的朋友可以自行参考相关书籍研究,如果你有什么研究成果,非常欢迎你为我的程序编写插件实现。
    展开全文
  • 图像缩放算法小结

    万次阅读 2019-04-10 14:17:57
    参考网址: https://blog.csdn.net/lfz_sau/article/details/51366700 http://www.cnblogs.com/blfshiye/p/4823027.html https://en.wikipedia.org/wiki/Lanczos_resampling ...

    参考网址:
    https://blog.csdn.net/lfz_sau/article/details/51366700
    http://www.cnblogs.com/blfshiye/p/4823027.html
    https://en.wikipedia.org/wiki/Lanczos_resampling
    https://wenku.baidu.com/view/22b38b70a417866fb84a8ea1.html
    https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms
    https://blog.csdn.net/u011630458/article/details/69524582

    图像缩放的基本原理就是根据原图像的像素值通过一定的规则计算得到目标图像的像素值。
    图像缩放的两个关键问题是应该选取原图像中哪些像素值,以及如何确定选取的像素值的权重。
    图像缩放的常见问题是产生锯齿(缩小)或者模糊(放大)。

    缩放图像是二维的尺度伸缩变换,目标图像的像素值从原图像得到。
    令h_step = H/h, w_step = W/w,目标图中相邻像素的距离就转换为了原图中的h_step和w_step(通常不是整数)。
    此外,原图和目标图的第一个像素重合。

    最近邻算法

    在待求像素的(待插值图的)四邻像素中,将距离待求像素最近的邻像素灰度赋给待求像素。
    见下图,设u为待求像素与四邻像素的左上点的水平坐标差,v为待求像素与四邻像素的左上点的垂直坐标差。将待求像素在待插值图中的坐标位置进行四舍五入处理,对应坐标的像素值即为待求像素的值。

    优点:
    最常见,最通用的算法之一,计算量很小,算法简单,因此运算速度较快。

    缺点:
    效果不好,放大图像时会出现严重的马赛克,缩小图像则会严重失真。它仅使用离待测采样点最近的像素的灰度值作为该采样点的灰度值,而没考虑其他相邻像素点的影响,因而重新采样后灰度值有明显的不连续性,图像质量损失较大,会产生明显的马赛克和锯齿现象。

    Bilinear算法

    双线性插值即在两个方向分别进行一次线性插值,通过四个相邻像素插值得到待求像素。
    见下图,已知Q11,Q12,Q21,Q22为原图中的四邻像素,P点为待求像素。
    图中所示的双线性插值步骤:
    (1)通过Q12,Q22线性插值得到R2,通过Q11,Q21线性插值得到R1;
    (2)通过R1,R2线性插值得到P.
    图中所示的双线性插值先进行了水平方向的插值,再进行垂直方向上的插值,也可以先垂直插值再水平插值。插值方向的顺序不影响最终的结果。
    双线性插值的公式为:
    f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy

    优点:
    最常见,最通用的算法之一,效果比最近邻插值法好。计算量较小,运算速度较快。图像连续性较好。双线性插值法效果要好于最近邻插值,只是计算量稍大一些,算法复杂些,程序运行时间也稍长些,但缩放后图像质量高,基本克服了最近邻插值灰度值不连续的特点,因为它考虑了待测采样点周围四个直接邻点对该采样点的相关性影响。

    缺点:
    放大时图像较为模糊,细节损失较严重。它仅考虑待测样点周围四个直接邻点灰度值的影响, 而未考虑到各邻点间灰度值变化率的影响, 因此具有低通滤波器的性质, 从而导致缩放后图像的高频分量受到损失, 图像边缘在一定程度上变得较为模糊。用此方法缩放后的输出图像与输入图像相比, 存在由于插值函数设计考虑不周而产生的图像质量受损与计算精度不高的问题。

    Bicubic算法

    在数值分析这个数学分支中,双三次插值(英语:Bicubic interpolation)是二维空间中最常用的插值方法。在这种方法中,函数f在点 (x,y) 的值可以通过矩形网格中最近的十六个采样点的加权平均得到,在这里需要使用两个多项式插值三次函数,每个方向使用一个。

    通过双三次插值可以得到一个连续的插值函数,它的一阶偏导数连续,并且交叉导数处处连续。
    双三次插值的计算公式:

    双三次插值过程类似于双线性插值,分水平插值和垂直插值两个步骤,但双三次插值涉及的像素数更多(4x4)。
    计算系数 的过程依赖于插值数据的特性。如果已知插值函数的导数,常用的方法就是使用四个顶点的高度以及每个顶点的三个导数。一阶导数h’x与h’y表示 x 与 y 方向的表面斜率,二阶相互导数h’’xy表示同时在 x 与 y 方向的斜率。这些值可以通过分别连续对 x 与 y 向量取微分得到。对于网格单元的每个顶点,将局部坐标(0,0, 1,0, 0,1 和 1,1) 带入这些方程,再解这 16 个方程。

    上图公式中的R(x)表示插值采样函数,可以根据需要选择不同的采样函数。常见的有基于三角采样函数、Bell分布采样函数和B样条采样函数。下面介绍这三种常见的双三次插值采样函数。

    优点:
    立方卷积插值计算量最大,算法也是最为复杂的。在几何运算中,双线性内插法的平滑作用可能会使图像的细节产生退化,在进行放大处理时,这种影响更为明显。在其他应用中,双线性插值的斜率不连续性会产生不希望的结果。立方卷积插值不仅考虑到周围四个直接相邻像素点灰度值的影响,还考虑到它们灰度值变化率的影响。因此克服了最近邻算法和双线性算法的不足之处,能够产生比双线性插值更为平滑的边缘,计算精度很高,处理后的图像像质损失最少,效果是最佳的。

    缺点:
    立方卷积插值计算量较大,算法相较双线性算法更为复杂。

    Lanczos算法

    a的典型值是2或3,得到的图像在抗锯齿和保留锐利边缘的效果最佳。下图是a=2和a=3时对应的函数图像。a = 2适合缩小图像,a = 3适合放大图像。

    类似于双三次插值,对4x4的像素卷积处理,得到待求像素。

    优点:
    得到的图像在抗锯齿和保留锐利边缘的效果较好。

    缺点:
    相当于立方卷积插值,计算量较大,算法相较双线性算法更为复杂。

    NEDI算法

    New Edge-Directed Interpolation,利用局部协方差特性来推导最佳线性MMSE预测的预测系数。由于低分辨率和高分辨率图像在边缘处具有相近的边缘信息,从而可以用低分辨率的协方差特性来得到高分辨率的预测系数。
    插值方法:通过4邻域点的值乘上各自的权重值来得到插值点的值(45°或135°方向上的点可看作旋转后的4邻域)

    摘自论文,出处暂时没找到。

    插值过程说明如下:
    (1)待插值点为O’点(偶行偶列)。图中□ABCD与□A’B’C’D’结构相似,假设它们具有相同的边缘信息。由于O点与A,B,C,D具有某种相关性,则对应地O’点与A’,B’,C’,D’有同样的相关性。因而可以通过求O点和A, B, C, D的协方差来得到A’, B’, C’, D’的权重值,进而插值得到O’的值。
    分别以A, B, C, D, O为中心取7x7的矩阵,计算A, B, C, D 与 O 的相关性,得到系数a, 公式为a=inv(C’ *C) *(C’ *r)
    其中矩阵C是由以点A, B, C, D为中心的7x7矩阵的像素值组成的, r表示点由以点O为中心的7x7矩阵的像素值组成的。得到的结果a表示A’, B’, C’, D’的权重值。
    注意:

    这两个条件说明A, B, C, D与O线性无关或处于平坦区域,因而令A’, B’, C’, D’的权重值均为1/4。此外,若计算结果超出0~255的范围,说明计算结果异常,为保证不出现坏点,也令A’, B’, C’, D’的权重值均为1/4.

    (2)待插值点为图中的浅绿色点或紫色点(偶行奇列,奇行偶列)。原理同前,矩阵取点方向为逆时针45°。如下图所示,取大小为6x6的框。

    优点:
    根据统计信息进行插值,细节保持较好。

    缺点:
    算法复杂,计算量大,运算速度较慢。

    EP2X算法

    EPX(Eric’s Pixel Expansion)是1992年Eric Johnston为了将SCUMM游戏放大到IBM PC上而设计的。算法具体实现如下所示:
    左下图为放大前的像素图,P为放大前的取样像素,ABCD为放大2倍后,取代P的四个子像素。
    A = P; B = P; C = P; D = P;
    若2, 4的值相同(R/G/B),则A = 2;
    若2, 6的值相同(R/G/B),则B = 6;
    若4, 8的值相同(R/G/B),则C = 4;
    若6, 8的值相同(R/G/B),则D = 8;
    若2, 4, 6, 8有三个以上相同,则A = B = C = D = P.

    基于EPX的改进算法Eagle:
    A = P; B = P; C = P; D = P;
    若1, 2, 4的值相同(R/G/B), 则A = 1;
    若2, 3, 6的值相同(R/G/B), 则B = 3;
    若4, 7, 8的值相同(R/G/B), 则C = 7;
    若6, 8, 9的值相同(R/G/B), 则D = 9.

    上述EPX 2x和Eagle 2x算法在RGB域已用MATLAB实现,若要对YUV域应用这两种算法,建议仅对Y分量实现。

    优点:
    算法简单,计算量较小,运算速度较快。边缘保持较好。

    缺点:
    适用于内容简单的图像,例如UI图,对于情景较为复杂的图像容易产生坏点。

    HQX算法

    HQX系列算法原理:
      通过比较输入图像中的像素点与其8邻域像素点的值,标记邻域点为近或者远(0或1),并使用一个预先生成的查找表格确定输入像素点相应输出的4、9或16个点的合适的权重。其中hq3x算法对斜线具有较好的抗锯齿作用。
    下面具体介绍HQ2X算法。

    在原图中取如图所示3x3的像素,计算w5和其8邻像素的差的绝对值,大于48则为1,否则为0.
    flag = f(w1)<<7 +f(w2)<<6 + f(w3)<<5 + f(w4)<<4 + f(w6)<<3 + f(w7)<< 2 + f(w8)<<1 + f(w9)<<0
    易知,flag的取值为0~255.
    HQ2X算法里原图中的1个像素映射到目标图中的4个像素——PIXEL00,PIXEL01,PIXEL10,PIXEL11。
    插值计算函数有:
    Interp1(c1, c2) : ret = (c13 + c2)>>2;
    Interp2(c1,c2,c3) : ret = (c1
    2 + c2 + c3)>>2;
    Interp3(c1,c2) : ret = (c17 + c2)>>3;
    Interp4(c1,c2,c3): ret = (c1
    2 + c27 + c37)>>4;
    Interp5(c1,c2) : ret = (c1 + c2)>>1;
    Interp6(c1,c2,c3) : ret = (c15 + c22 + c3)>>3;
    Interp7(c1,c2,c3) : ret = (c16 + c2 + c3)>>3;
    Interp8(c1,c2) : ret = (c1
    5 + c23)>>3;
    Interp9(c1,c2,c3) : ret = (c1
    2 + c23 + c33)>>3;
    Interp10(c1,c2,c3) : ret = (c1*14 + c2 + c3)>>4.
    HQ2X用到了其中的Interp1, Interp2, Interp6, Interp7, Interp9, Interp10.具体算法情况参见C代码,共有161种情况。

    优点:
    边界清晰,对比度高,细节保持较好。

    缺点:
    斜边或者有弧度的地方的连续性不好,有明显的锯齿。

    Google SR算法

    Google SR(即RAISR)的算法原理:
    先由LR(low resolution)图像经简单的upscaling得到HR-tmp(high resolution)图像,再用训练得到的滤波模板处理,得到最终的HR图像。
    RAISR的MATLAB代码组成部分:training和testing。
    Training部分:
    (1)已知original HR图,将其长宽均缩小到1/k,再通过cheap upscaling(如bilinear, bicubic等)放大到原尺寸,得到tmp HR图;
    (2)在tmp HR图中取固定大小的patch,利用最小二乘法求解出滤波模板H。则可通过tmp HR图估计original HR图中的像素;
    , 公式中的Ai指的是tmp HR图像中的patch,h是滤波模板,bi是original HR中相应的像素。直接求此公式的计算复杂度较高,所以转换成如下公式(这里从二维降为一维计算,简化了计算复杂度);
    , 其中 ,即将上述公式左乘A的转置。
    (3)考虑到patch不同旋转角度的线性滤波模板有所不同,且它们可以统一到一个模板中,故(2)中的A取了patch旋转90°,垂直翻转和中心对称三种情况进行累加计算(MATLAB代码仅有三种,论文中说了四种方向);
    (4)计算patch的idx, 根据梯度angle, strength, coherence(与水平和垂直的梯度有关,具体计算参见代码或论文)计算得到(详见代码);
    (5)计算当前像素的type,与缩放倍数k有关,type的取值范围是1~k^2,行和列号可被k整除的type为1,在k*k的块内从左到右、从上到下type递增;
    (6)将(3)中计算得到的滤波模板h保存到对应的idx, type类中;
    (7)对大量图像重复上述步骤。

    Testing部分:
    (1)已知original HR图,将其长宽均缩小到1/k,再通过cheap upscaling(如bilinear, bicubic等)放大到原尺寸,得到tmp HR图;
    (2)在tmp HR图中取固定大小的patch;
    (3)计算patch的idx, 根据梯度angle, strength, coherence计算得到(详见代码);
    (4)计算当前像素的type;
    (5)根据idx和type找到对应的滤波模板,处理tmp HR中的patch;
    (6)重复(2)-(5),直到处理完整个tmp HR图,得到RAISR HR图;
    (7)计算RAISR HR相对original HR图的PSNR和SSIM值,即为测试结果。
    注意:滤波模板是固定倍率的,训练和测试时缩放的倍数一致,应用的时候也只能用于给定的倍率,通常为2倍(论文示例)或3倍(MATLAB代码)。另外,cheap upscaling的算法也应当保持一致。

    RAISR的应用过程:
    (1)将LR输入图经给定的cheap upscaling算法放大指定倍数k,得到tmp HR图;
    (2)在tmp HR图中取固定大小的patch;
    (3)计算patch的idx, 根据梯度angle, strength, coherence计算得到(详见代码);
    (4)计算当前像素的type;
    (5)根据idx和type找到对应的滤波模板,处理tmp HR中的patch;
    (6)重复(2)-(5),直到处理完整个tmp HR图,得到RAISR HR输出图。

    数学知识:
    (1)解线性方程,求特征向量,例如求滤波模板h;
    (2)解线性方程,求特征值,例如求梯度angle, strength和coherence。

    该算法属于无监督学习算法,没有用损失函数对训练结果进行约束。

    优点:
    跟bicubic算法相比:细节清晰,轮廓分明,对比度高。主观质量更好。

    缺点:
    轮廓边缘有明显的伪轮廓;细节丰富的场景中存在坏点;计算量大。

    展开全文
  • 图像缩放

    千次阅读 2017-09-07 15:56:50
    图像缩放的定义为:将图像中的某点(x,y)经缩放后其位置变为(x’,y’),则两者之间的关系为:  X’= ax y’ = by a、b分别是x、y方向上的缩放比例。当a、b大于1时图像放大,小于1时,图像缩小。当a = -1,b = 1...

    图像缩放的定义为:将图像中的某点(x,y)经缩放后其位置变为(x’,y’),则两者之间的关系为:

                                                            X’= ax   y’ = by

    a、b分别是x、y方向上的缩放比例。当a、b大于1时图像放大,小于1时,图像缩小。当a = -1,b = 1时会产生一个关于y轴对称的镜像;当a = 1, b=-1时,会产生一个关于x 轴对称的镜像。其矩阵表示为:

                       

    最近邻插值法,是最简单的插值法。其做法是令输出像素的灰度值等于离它所映射到的位置最近的输入图像像素的灰度值。此方法会产生锯齿,放大倍数过大会出现马赛克。

    双线性插值也称为一阶差值,此方法是求得相邻的四个相邻的点的距离之比,用这个比率和四个相邻像素点的灰度值进行差值。具体方法如下:对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为f(i+u,j+v),其中i, j均为非负整数,p、q为区间[0,1)的浮点数,则这个像素f(i+p,j+q) 的值可由原图像坐标为( i , j ), (i+1, j), (i, j+1), (i+1 ,j+1) 所对应的四个像素的值决定:

                                             

    双线性插值算法计算量比较大,但缩放后图像质量高。由于双线性差值具有低通滤波的性质,使高频分量受损,故会使图像丢失细节变的模糊。

    具体算法实现:

    [csharp] view plain copy
    1. /// <summary>  
    2.   /// 图像缩放  
    3.   /// </summary>  
    4.   /// <param name="srcBmp">原始图像</param>  
    5.   /// <param name="width">目标图像宽度</param>  
    6.   /// <param name="height">目标图像高度</param>  
    7.   /// <param name="dstBmp">目标图像</param>  
    8.   /// <param name="zt">缩放选用的算法</param>  
    9.   /// <returns>处理成功 true 失败 false</returns>  
    10.   public static bool Zoom(Bitmap srcBmp, double width, double height, out Bitmap dstBmp, ZoomType zt) {//ZoomType为自定义的枚举类型  
    11.       if (srcBmp == null) {  
    12.           dstBmp = null;  
    13.           return false;  
    14.       }  
    15.       //若缩放大小与原图一样,则返回原图不做处理  
    16.       if (srcBmp.Width == width && srcBmp.Height == height) {  
    17.           dstBmp = new Bitmap(srcBmp);  
    18.           return true;  
    19.       }  
    20.       //计算缩放比例  
    21.       double ratioH = height / (double)srcBmp.Height;  
    22.       double ratioW = width / (double)srcBmp.Width;  
    23.       dstBmp = new Bitmap((int)width, (int)height);  
    24.   
    25.       BitmapData srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);  
    26.       BitmapData dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);  
    27.       unsafe {  
    28.           byte* srcPtr = null;  
    29.           byte* dstPtr = null;  
    30.           int srcI = 0;  
    31.           int srcJ = 0;  
    32.           double srcdI = 0;  
    33.           double srcdJ = 0;  
    34.           double a = 0;  
    35.           double b = 0;  
    36.           double F1 = 0;//横向插值所得数值  
    37.           double F2 = 0;//纵向插值所得数值  
    38.           if (zt == ZoomType.NearestNeighborInterpolation) {//邻近插值法  
    39.   
    40.               for (int i = 0; i < dstBmp.Height; i++) {  
    41.                   srcI = (int)(i / ratioH);  
    42.                   srcPtr = (byte*)srcBmpData.Scan0 + srcI * srcBmpData.Stride;  
    43.                   dstPtr = (byte*)dstBmpData.Scan0 + i * dstBmpData.Stride;  
    44.                   for (int j = 0; j < dstBmp.Width; j++) {  
    45.                       dstPtr[j * 3] = srcPtr[(int)(j / ratioW) * 3];  
    46.                       dstPtr[j * 3 + 1] = srcPtr[(int)(j / ratioW) * 3 + 1];  
    47.                       dstPtr[j * 3 + 2] = srcPtr[(int)(j / ratioW) * 3 + 2];  
    48.                   }  
    49.               }  
    50.           }  
    51.           if (zt == ZoomType.BilinearInterpolation) {//双线性插值法  
    52.               byte* srcPtrNext = null;  
    53.               for (int i = 0; i < dstBmp.Height; i++) {  
    54.                   srcdI = i / ratioH;  
    55.                   srcI = (int)srcdI;//当前行对应原始图像的行数  
    56.                   srcPtr = (byte*)srcBmpData.Scan0 + srcI * srcBmpData.Stride;//指原始图像的当前行  
    57.                   srcPtrNext = (byte*)srcBmpData.Scan0 + (srcI + 1) * srcBmpData.Stride;//指向原始图像的下一行  
    58.                   dstPtr = (byte*)dstBmpData.Scan0 + i * dstBmpData.Stride;//指向当前图像的当前行  
    59.                   for (int j = 0; j < dstBmp.Width; j++) {  
    60.                       srcdJ = j / ratioW;  
    61.                       srcJ = (int)srcdJ;//指向原始图像的列  
    62.                       if (srcdJ < 1 || srcdJ > srcBmp.Width - 1 || srcdI < 1 || srcdI > srcBmp.Height - 1) {//避免溢出(也可使用循环延拓)  
    63.                           dstPtr[j * 3] = 255;  
    64.                           dstPtr[j * 3 + 1] = 255;  
    65.                           dstPtr[j * 3 + 2] = 255;  
    66.                           continue;  
    67.                       }  
    68.                       a = srcdI - srcI;//计算插入的像素与原始像素距离(决定相邻像素的灰度所占的比例)  
    69.                       b = srcdJ - srcJ;  
    70.                       for (int k = 0; k < 3; k++) {//插值  
    71.                           F1 = (1 - b) * srcPtr[srcJ * 3 + k] + b * srcPtr[(srcJ + 1) * 3 + k];  
    72.                           F2 = (1 - b) * srcPtrNext[srcJ * 3 + k] + b * srcPtrNext[(srcJ + 1) * 3 + k];  
    73.                           dstPtr[j * 3 + k] = (byte)((1 - a) * F1 + a * F2);  
    74.                       }  
    75.                   }  
    76.               }  
    77.           }  
    78.       }  
    79.       srcBmp.UnlockBits(srcBmpData);  
    80.       dstBmp.UnlockBits(dstBmpData);  
    81.       return true;  
    82.   }  
    效果图不再展示~
    展开全文
  • 图像缩放

    2018-04-10 17:18:15
    图像缩放中坐标的空间变换以图像放大为例,对数字图像f(x,y)放大一倍,其数学表达式为x'=2x,y'=2y(其中,(x',y')表示(x,y)变化后所对应的坐标),如图1所示。图1现在将图像缩放写成一般的数学表达式:再写成矩阵...
  • 图像缩放方法总结

    千次阅读 2019-04-24 17:33:18
    最近在做图像检测和识别上,遇到不同尺寸的图像会导致结果产生误差:故总结下图像缩放的方法,减少算法推理的误差: 除了以下传统的算法外,也可以训练一个小型的神经网络,用于上下采样。 OpenCV图像缩放resize...
  • PIL图像缩放不按比例缩放按比例缩放 不按比例缩放 from PIL import Image, ImageOps import matplotlib.pyplot as plt import numpy as np import cv2 img = cv2.imread('./Homework/homework2/1.jpg') #注意cv2...
  • 【Halcon】图像、区域缩放

    万次阅读 2018-07-30 11:11:28
     无法停止的时间,并不仅仅是为了让人珍惜缅怀,也是为了让人能不断地体验到每一个美妙瞬间,所以才流泻不止吧! ———摘自:吉本芭娜娜《身体全知道》  最近在做一个项目的时候,... 根据缩放因子实现图像...
  • Matlab实现图像的比例缩放

    万次阅读 2019-07-01 21:55:37
    以灰度图像circuit.tif为例,利用Matlab图像处理工具箱中的imresize函数对图像进行比例缩放变换。要求:创建4个figure窗口(不可以用subplot,显示不出来放大效果),分别用于显示原始图像、等比例放大1.5倍后的图像...
  • 设置图像的显示Mode,如果图片放在BackGroundImage,则设置BackGroundImageLayOut,如果图片放在Image里,则设置SizeMode。 总之设置成Stretch(拉伸)。设置完后再通过调整PictureBox的Width和Height来改变图像大小。...
  • 缩放时,将鼠标的当前位置作为缩放的中心 • 移动时,修改图像的原点即可使用 Halcon 中 HWindowController 控件的 ImagePart 来实现图像缩放。 ImagePart 指示的是要在 HWindowController 的窗体中显示图像的...
  • 其第一个参数为待缩放图像,第二个参数为缩放后的图像尺寸大小,第三个和第四个参数为缩放尺度因子,第五个参数为缩放的插值方法。 插值方法: 默认时使用的是cv2.INTER_LINEAR 缩小时推荐使用cv2.INTER_AREA ....
  • html img图片等比例缩放

    千次阅读 2016-07-28 21:17:53
    在img标签里面只设置宽,不设置高,图片就会等比例缩放
  • 例如,如果我的屏幕是320像素宽,我只想让320像素的图片显示在屏幕上,而不是填满整个ImageView(即时这意味着其他的图像将被切断) 有什么方法能够阻止它按比例缩放么? 而且我想让左侧的图像贴着设备屏幕的...
  • 使用Matlab实现对图片缩放

    千次阅读 2017-03-23 21:54:01
    在做图像处理的时候,有时需要对图片的像素进行放大或则缩小。 使用Matlab很容易实现对图像的放大和缩小。这里只讲缩放到固定像素的方法。 clear;clc; %清除以前的数据 folderName = dir('train'); %显示train...
  • OpenCV对图像进行缩放显示

    千次阅读 2014-03-19 09:46:36
    #include "opencv2/opencv.hpp" #include using namespace std; using namespace cv; ... cv::Mat imagesrc = cv::imread("test.png");//读取图像 if (!imagesrc.data) { cout<<"no image can
  • matlab实现图像缩放

    千次阅读 2019-07-09 10:38:05
    matlab实现图像缩放 缩放同样是仿射变换的一种特例,它接受水平和垂直两个方向的缩放值。 matlab 实现水平,垂直,水平垂直缩放: clear all close all clc img = imread('test.jpg'); %读取输入图片的...
  • import tensorflow as tf import numpy as np ...#获取图像的基本 img = cv2.imread('image0.jpg', 1) imgInfo = img.shape height = imgInfo[0] width =imgInfo[1] dstHeight = int(height/2) dstWidth = int(wid...
  • OpenCV实现图片缩放

    万次阅读 2019-04-24 16:20:48
    代码位置:5-ImageResize.py import cv2 img = cv2.imread('./res/aero3.jpg') print(img.shape[:2]) width, height = img.shape[:2] reSize1 = cv2.resize(img, (2*width, 2*height), interpolation=cv2.INTER_...
  • 图像缩放算法

    千次阅读 2018-07-02 09:53:59
    缩放原理和公式图示: ...缩放图片图片 (宽DW,高DH) (宽SW,高SH) (Sx-0)/(SW-0)=(Dx-0)/(DW-0) (Sy-0)/(SH-0)=(Dy-0)/(DH-0) =&gt; Sx=Dx*SW/DW Sy=Dy*SH/DH 每一行的缩放比例是固定的;那么可以...
1 2 3 4 5 ... 20
收藏数 230,087
精华内容 92,034
关键字:

图像缩放