快速 2:1 图像缩小(按比例缩小)

介绍

本文提供了一种简单、快速、实用的 2:1 图像缩小算法的实现。
在非常特殊的情况下使用 2:1 图像缩小,但效果很好。

背景

图像处理始终是一项昂贵的工作。当需要显示缩放的图片时,最好使用 GPU 进行渲染(OpenGL、DirectX)。但使用 GPU 并不总是可行的,最好有替代方案。

高质量的图像大小调整(放大/缩小)对 CPU 的要求极高,尤其是在大图像上。此外,有时需要进行多次处理。为了缓解这种情况,可以应用不同的技巧。如果必须缩小图片(按比例缩小),可以应用类似于 mip-maps 的技巧。这种情况是如果我们想要将图片缩小两倍以上(目标大小小于原始大小的一半),我们可以通过在实际缩放之前应用半缩小来加快整个过程。由于使用较少计算的最简单算法,2:1 比例缩小非常快。

例如,如果我们有图像 1920x1024 并且需要将其缩小到 500x281,我们必须执行如下代码:

C++
<span style="color:#000000"><span style="background-color:#fbedbb">shrink( imageDst, imageSrc )</span></span>

但是我们可以通过像这样预先收缩 2:1 来优化它:

C++
<span style="color:#000000"><span style="background-color:#fbedbb">shrinkHalf( imageHalf, imageSrc );
shrink( imaheDst, imageHalf );</span></span>

在我的一个项目中,当我必须缩放 3 个监视器的图像以生成预览时,结果是:

<span style="color:#000000"><span style="background-color:#fbedbb">Scale: 46 ms
ShrinkHalf + Scale: 25 ms
ShrinkHalf + ShrinkHalf + Scale: 16 ms</span></span>

这意味着,应用一次的技巧会导致 %36 加速。
并且该技巧应用了两次,导致 %66 加速。

演示应用程序有两个按钮:

  • 缩小 2:1 - 执行整个源图像的图像缩小
  • Shrink 2:1 rnd - 从源图像执行随机矩形的图像收缩

左边是原图。右边是灰度的原始图像和彩色的缩小图像(或缩小的部分)。

当原件被更新并且也需要更新缩小的副本时,只缩小图像的一部分是合适的。这可以节省大量 CPU 和处理时间。

全图2:1

2:1 随机矩形

使用代码

项目中有一对文件:ShrinkHalf.hShrinkHalf.cpp
要使用代码,您只需将这些文件放入您的项目中并包含ShrinkHalf.h文件。
这些文件包含所有算法的实现。

所有函数都作为参数接收:

  • BYTE* pixels- 24 位 BGR 格式的像素数组(b,g,r, b,g,r, ..., b,g,r)
  • int width- 图像的像素宽度
  • int height- 图像的像素高度

因此,为了使用这些功能,您应该执行以下操作:

C++

请注意,目的地不提供尺寸,因为它们是根据源尺寸计算的。

以下是可用的功能:

C++

第一个函数执行整个图像的 2:1 缩小。
第二个函数从源图像执行指定矩形的 2:1 缩小,计算目标图像的相应矩形。
如果你使用它,你应该注意你可能需要修正 +1/-1 的源矩形点,因为整数舍入。
如果应该应用密集更新(例如,视频渲染),这将非常有用。

兴趣点

shrinkHalf函数中,有注释代码有效,但我更喜欢将内部调用留给shrinkHalfPart.

C++
//static
void    shrinkHalf( BYTE* target, const BYTE* source, int srcWidth, int srcHeight )
{
    shrinkHalfPart( target, source, srcWidth, 
                    srcHeight, 0, 0, srcWidth-1, srcHeight-1 );

    //~~~~~
/*
    int    dstWidth    = srcWidth  / 2;
    int    dstHeight   = srcHeight / 2;

    int    srcLineBytes    = srcWidth * 3;
    int    dstLineBytes    = dstWidth * 3;
    int    dstRows         = dstHeight;

    const BYTE*    sl    = source;
          BYTE*    tl    = target;
    const BYTE*    te    = target + srcHeight/2 * dstLineBytes;

    while( tl < te )
    {
              BYTE*    pt    = tl;
        const BYTE*    p1    = sl;
        const BYTE*    p2    = p1 + srcLineBytes;
        const BYTE*    pe    = sl + srcLineBytes;

        while( p1 < pe )
        {
            *pt++    = (p1[0] + p1[3] + p2[0] + p2[3]) >> 2;    //    / 4;    blue;
            *pt++    = (p1[1] + p1[4] + p2[1] + p2[4]) >> 2;    //    / 4;    green;
            *pt++    = (p1[2] + p1[5] + p2[2] + p2[5]) >> 2;    //    / 4;    red;

            p1    += 6;//2*3;
            p2    += 6;//2*3;
        }

        sl    += srcLineBytes << 1;    //    Shift by 1 is equal to " * 2 "
        tl    += dstLineBytes;
    }
*/
}

因此,如果有人想要一个干净简单的函数,他们可以删除调用的第一行shrinkHalfPart并取消注释代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值