图像处理-放大和缩小

个人博客:http://www.chenjianqu.com/

原文链接:http://www.chenjianqu.com/show-7.html

在计算机图像处理和计算机图形学中,图像缩放(image scaling)是指对数字图像的大小进行调整的过程。图像缩放是一种非平凡的过程,需要在处理效率以及结果的平滑度(smoothness)和清晰度(sharpness)上做一个权衡。当一个图像的大小增加之后,组成图像的像素的可见度将会变得更高,从而使得图像表现得“软”。相反地,缩小一个图像将会增强它的平滑度和清晰度。

 

图像缩小

  图像缩小是通过减少像素个数来实现的,因此要根据缩小的尺寸,从原图像中选择合适的像素点,使图像缩小后可以保持原有图像的特征。图像缩小的算法有很多,这里主要介绍和实现两种算法:等间隔采样、局部均值。

 

基于等间隔采样的图像缩小算法

  等间隔采样其实就是在原图中每间隔一定的距离取像素点放到输出图像上。设原图的大小为W*H,宽度和长度的缩小因子分别为看k1和k2,那么采样间隔为:W/k1,W/k2.也就是说在原图的水平方向每隔W/k1,在垂直方向每隔W/k2取一个像素。长和宽的缩小因子k1和k2相等时,图像时等比例缩小,不等时是不等比例缩小,缩小图像的长和宽的比例会发生变化。

算法的实现步骤:

(1)计算采样间隔

    设原图的大小为W*H,将其放大(缩小)为(k1*W)*(K2*H),则采样区间为

    ii=1/k1;      

    jj=1/k2;

    当k1==k2时为等比例缩小;当k1!=k2时为不等比例放大(缩小);当k1<1 && k2<1时为图片缩小,k1>1 && k2>1时图片放大。

(2)求出放大(缩小)后的图像

    设原图为F(x,y)(i=1,2, ……W; j=1,2,……H),放大(缩小)的图像为G(x,y)(x=1,2, ……M; y=1,2,……N,其中M=W*k1,N=H*k2),则有 G(x,y) = f(ii*x, jj*y)

 

代码实现:

//图像缩小—等间隔采样 参数:原图 x轴缩放比例 y轴缩放比例
Mat ZoomOutEqualInterval(Mat& src, double x_k,double y_k)
{
 
    Mat dst(src.rows*y_k, src.cols*x_k, src.type(), Scalar(0));
    x_k = 1 / x_k;//将缩小率转换为采样间隔
    y_k = 1 / y_k;
    cout << "dst x y:" << dst.cols << " " << dst.rows << endl;
    cout << "src x y:" <<src.cols << " " << src.rows << endl;
    if (src.channels() == 3)
    {
        for (int i = 0; i < dst.rows; i++)
        {
            for (int j = 0; j < dst.cols; j++)
            {
 
                int x = j * x_k + 0.5;
                int y = i * y_k + 0.5;
                if (x >= src.cols)x = src.cols - 1;
                if (y >= src.rows)y = src.rows - 1;
                dst.at<Vec3b>(i, j) = src.at<Vec3b>(y, x);
            }
        }
    }
    return dst;
}

缩小一倍的效果如下:

1_20190110230138_288_20190118141407_577.png1_20190110230138_288.png

 

基于局部均值的图像缩小算法

算法描述

  等间隔采样的缩小方法实现简单,但是原图像中未被选中的像素信息会在缩小后的图像中丢失。局部均值的图像缩小方法对其进行了改进。在求缩小图像的像素时,不仅仅单纯的取在原图像中的采样点像素,而是以相邻的两个采样点为分割,将原图像分成一个个的子块。缩小图像的像素取相应子块像素的均值。

tt_20190110230350_946.png

根据局部均值缩小的原理:g11 = (f11 + f12 + f21 + f22 ) / 4

代码实现: 

//图像缩小—局部均值采样 参数:原图 x轴缩放比例 y轴缩放比例
Mat ZoomOutLocalMean(Mat& src, double x_k, double y_k)
{
 
    Mat dst(src.rows*y_k, src.cols*x_k, src.type(), Scalar(0));
    x_k = 1 / x_k;//将缩小率转换为采样间隔
    y_k = 1 / y_k;
    cout << "dst x y:" << dst.cols << " " << dst.rows << endl;
    cout << "src x y:" << src.cols << " " << src.rows << endl;
    if (src.channels() == 3)
    {
        for (int i = 0; i < dst.rows; i++)
        {
            for (int j = 0; j < dst.cols; j++)
            {
                int j_start = (j-1) * x_k+1;
                if (j_start < 0)j_start = 0;
                int j_end = j* x_k;
                if (j_end >=src.cols )j_end = src.cols;
 
                int i_start= (i-1) * y_k +1;
                if (i_start < 0)i_start = 0;
                int i_end = i * y_k;
                if (i_end >= src.rows)i_end = src.rows;
 
                int pix[3] = { 0,0,0 };
                
                int count = (j_end - j_start)*(i_end - i_start);
                for (int n = i_start; n < i_end; n++)
                    for (int m = j_start; m < j_end; m++) {
                        pix[0] = src.at<Vec3b>(n, m)[0];
                        pix[1] = src.at<Vec3b>(n, m)[1];
                        pix[2] = src.at<Vec3b>(n, m)[2];
                    }
                if (count != 0) {
                    Vec3b v(pix[0] / count, pix[1] / count, pix[2] / count);
                    dst.at<Vec3b>(i, j) = v;
 
                }
                else
                    dst.at<Vec3b>(i, j) = src.at<Vec3b>(i,j);
            }
        }
    }
    return dst;
}

效果图:

2_20190110230200_741.png

 

 

图像放大

  要将该图像放大两倍,可以有很多种算法,最简单的方法为邻域插值,即将每一个原像素原封不动地复制映射到扩展后对应四个像素中:

      这种方法在放大图像的同时保留了所有的原图像的所有信息,但是会产生锯齿现象。

双线性插值的效果对于放大的图像而言较领域插值来得平滑,但是却使得图像变得模糊而且仍然会有一部分锯齿现象。双三次插值更好比双线性插值更好。这里只实现最近邻插值和双线性插值。

 

最邻近插值

原理

    原始图像:I(x,y), 输出图像:F(x,y),则放大过程可转换为I(x,y)=F(int(c1*i),int(c2*j)),其中c1=1/y轴放大倍数,c2=1/x轴放大倍数系数乘以原坐标值得到的坐标值可能含有小数,所以,我们必须采取一定方法(如:四舍五入,我们这里直接去掉小数部分)来舍弃小数部分,从而取得整数表示的像素点坐标, 该过程即为最邻近插值方法。

 

优缺点

  最邻近插值简单且直观,但得到的图像质量不高,特别在图像放大后可能产生明显锯齿。

代码实现://图像放大-最近邻插值法

Mat ZoomInNearestNeighborInterpolation(Mat& src, double x_k, double y_k)
{
         Mat dst(src.rows*y_k, src.cols*x_k, src.type(), Scalar(0));
         x_k = 1 / x_k;
         y_k = 1 / y_k;
         if (src.channels() == 3)
         {
                   for (int i = 0; i < dst.rows; i++)
                   {
                            for (int j = 0; j < dst.cols; j++)
                                     dst.at<Vec3b>(i, j) = src.at<Vec3b>(y_k*i, x_k*j);
                   }
         }
         return dst;
}

当x轴和y轴的放大系数均为2时,运行的效果为:

3_20190110230222_120.png

  

双线性插值

原理

      如图所示,最邻近插值是当求得p0后,直接找其邻近的点p1, p2, p3, p4中的一个的像素值作为目标点的像素;而双线性插值,则是根据p0点与周围4点(p1, p2, p3, p4)距离关系计算目标点的像素值。

4_20190110230651_777.png

通过计算得到的原始点为p0(x0, y0),则其4周的点分别为:

x0的可能取值为:sx1 = (int)x0, sx2 = sx1 + 1

y0的可能取值为:sy1 = (int)y0, sy2 = sy1 + 1

设:

s1 = y0 – sy1

s2 = sx2 – x0

s3 = 1.0 – s1

s4 = 1.0 – s2

假设p1, p2, p3, p4的像素值分别为v1, v2, v3, v4,

则双线性插值计算p0点像素值v0公式为:

v0 = v1*s1*s4 + v2*s1*s2 + v3*s2*s3 + v4*s3*s4

 

优缺点

  双线性内插值法计算量大,但缩放后图像质量高,不会出现像素值不连续的的情况。

  双线性插值具有低通滤波器的性质,使高频分量受损,所以可能会使图像轮廓在一定程度上变得模糊。

 

代码实现:

//图像放大-双线性插值法
Mat ZoomInBilinearInterpolation(Mat& src, double x_k, double y_k)
{
    Mat dst(src.rows*y_k, src.cols*x_k, src.type(), Scalar(0));
    x_k = 1 / x_k;
    y_k = 1 / y_k;
    if (src.channels() == 3)
    {
        for (int i = 0; i < dst.rows; i++){
            for (int j = 0; j < dst.cols; j++)
            {
                double x0 = x_k * j;
                double y0 = y_k * i;
                int x1 = int(x0);
                int y1 = int(y0);
                
                
                double s1 = y0 - y1;
                double s4 = x0 - x1;
                double s2 = 1 - s4;
                double s3 = 1 - s1;
                if (x1 >= src.cols - 1)x1 = src.cols - 2;
                if (y1 >= src.rows - 1)y1 = src.rows - 2;
                dst.at<Vec3b>(i, j) = src.at<Vec3b>(y1, x1)*s1*s4 + src.at<Vec3b>(y1, x1 + 1)*s1*s2 + src.at<Vec3b>(y1 + 1, x1 + 1)*s2*s3 + src.at<Vec3b>(y1 + 1, x1)*s3*s4;
            }
        }
    }
    return dst;
}

效果图:

5_20190110230729_462.png

 

三次卷积法

原理

  双立方插值算法与双线性插值算法类似,对于放大后未知的像素点P,将对其影响的范围扩大到邻近的16个像素点,依据对P点的远近影响进行插值计算,因P点的像素值信息来自16个邻近点,所以可得到较细致的影像,不过速度比较慢。

6_20190110230750_486.png

  不过双立方插值算法与双线性插值算法的本质区别不仅在于扩大了影响点的范围,还采用高级的插值算法,如图所示:

7_20190110230812_167.png

     要求A,B两点之间e点的值,需要利用A,B周围A-1,A,B,B 1四个点的像素值,通过某种非线性的计算,得到光滑的曲线,从而算出e点的值来。

    所谓“双”或者叫“二次”的意思就是在计算了横向插值影响的基础上,把上述运算拓展到二维空间,再计算纵向插值影响的意思。

      双立方插值算法能够得到相对清晰的画面质量,不过计算量也变大。该算法在现在的众多图像处理软件中最为常用,比如Photoshop,After Effects,Avid,Final Cut Pro等。

      为了得到更好的图像质量,在以上的基础上,许多新的算法不断涌现,它们使用了更加复杂的改进的插值方式。譬如B样条(B-SPline), 米切尔(Mitchell)等插值算法,它们的目的是使插值的曲线显得更平滑,图像边缘的表现更加完美。

 

自适应样条插值极其增强技术( S-Spline & S-Spline XL)

  与上述经典的插值方法最大的区别在于, S-Spline 采用了一种自适应技术,那些传统的方法总是依据周围的像素点来求未知点的色彩值,也就是说需要求解的色彩值仅仅依靠该像素点在图像中的位置,而非实际的图像的像素信息,而自适应样条算法还会考虑实际图像的像素信息。 实验表明,经过 S-Spline 算法得到的图像效果要优于双立方插值算法。

      现在 S-Spline 算法又出现了增强版 S-Spline XL,新版本的 S-Spline XL 算法较 S-Spline 而言画面的锐度得到进一步增强,物体的轮廓更加清晰,边缘的锯齿现象大大减弱,图像感受更加自然。

 

 

参考文献

[1]博客园:淑月尘缘. 图像缩放算法 .

https://www.cnblogs.com/sycy/p/4743620.html . 2015-08-19

[2]CSDN博客:rainbowbirds_aes.图像放大算法.

https://blog.csdn.net/rainbowbirds_aes/article/details/83114266. 2018.10.17

[3]博客园:Brook_icv. OpenCV2:等间隔采样和局部均值的图像缩小.

http://www.cnblogs.com/wangguchangqing/p/4011892.html. 2014.10.08

[3]韩九强,杨磊.数据图像处理-基于XAVIS组态软件.西安交通大学出版社.2018.8

 

 

 

 

 

  • 29
    点赞
  • 155
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Halcon是一种常用的机器视觉开发软件,可以用于图像采集和处理。要实现图像实时放大缩小功能,可以通过Halcon提供的图像处理功能完成。 首先,我们需要使用Halcon的图像采集功能来获取原始图像。Halcon提供了丰富的相机接口和图像采集函数,可以方便地连接和控制相机进行图像采集。 接下来,我们可以使用Halcon的图像处理函数实现实时的放大缩小功能。通过使用函数zoom_image来缩小图像,或者使用函数zoom_image_ext来放大图像。这些函数可以通过设置缩放因子来实现不同的放大缩小倍数。同时,还可以设置插值方法来保持图像的质量。 在放大缩小图像的过程中,为了保持实时性,可以使用多线程来处理图像。Halcon支持多线程编程,可以将图像处理过程放置在一个独立的线程中进行,与图像采集同时进行,从而实现实时的放大缩小功能。 最后,我们可以使用Halcon提供的图像显示函数来展示放大缩小后的图像。通过设置显示窗口的大小,可以适应不同大小的图像展示需求。 总的来说,要在Halcon中实现图像的实时放大缩小功能,需要结合图像采集、图像处理图像显示等功能。通过合理设置图像处理参数和多线程处理方式,可以实现实时性要求,并展示放大缩小后的图像效果。 ### 回答2: Halcon采集图像实时放大缩小是通过调节图像采集参数来实现的。首先,可以使用Halcon的图像采集接口进行实时图像采集。通过设置图像采集参数,如分辨率和帧率,可以调整采集到的图像的清晰度和流畅度。 要实现图像的实时放大缩小,可以使用Halcon的图像处理功能。首先,可以使用Halcon的缩放功能对采集到的图像进行缩小。通过调整缩放因子,可以控制图像缩小程度。缩小后的图像可以用于显示或者进一步的处理。 另外,如果需要实现图像放大,可以使用Halcon的插值功能。通过对图像进行插值处理,可以在保持图像质量的同时将图像放大。Halcon提供了不同的插值方法,如双线性插值和双三次插值,可以根据具体需求选择合适的插值方法。 通过在图像采集和处理过程中合理调节参数,可以实现Halcon采集图像的实时放大缩小。这样可以满足不同应用场景对图像的显示和处理需求,提高图像处理的效果和用户体验。 ### 回答3: Halcon是一种机器视觉软件,用于图像处理和分析。它提供了丰富的功能和工具,可以实现对图像的实时放大缩小操作。 要实现图像的实时放大缩小,首先需要通过Halcon采集图像。Halcon支持多种图像采集设备,可以通过相机、摄像头或者其他设备获取图像。一旦图像被采集到Halcon中,就可以进行后续的处理和分析工作。 在Halcon中,可以使用zoom_image函数来实现图像放大缩小操作。该函数可以根据指定的比例因子对图像进行缩放。比例因子大于1表示放大图像,小于1表示缩小图像。通过调整比例因子的值,可以实现不同程度的放大缩小效果。 除了使用zoom_image函数,还可以使用其他一些函数来进一步控制放大缩小的效果。例如,可以使用scale_image函数来指定放大缩小操作的中心点,以及具体的放大缩小比例。此外,还可以使用resize_image函数来改变图像的尺寸,从而实现放大缩小的效果。 需要注意的是,图像的实时放大缩小操作需要在循环中实现,以便不断更新图像的显示。可以使用while循环来实现图像的连续放大缩小,直到满足特定的条件时退出循环。 综上所述,Halcon可以通过采集图像并使用适当的函数来实现图像的实时放大缩小。通过调整放大缩小的参数,可以获得不同程度的变化效果。这种功能可以在机器视觉应用中广泛应用,例如图像检测、分析和处理等方面。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值