65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Haar 变换快速进行二维图像缩放

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (9投票s)

2007 年 10 月 18 日

GPL3

3分钟阅读

viewsIcon

128233

downloadIcon

3198

本文演示了使用 Haar 变换结合 MMX 优化进行二维图像缩放。

引言

这是一个基于 Haar 变换的快速二元图像下采样类。它从我的另一篇文章 用于图像处理的 2D 快速小波变换库 扩展了 BaseFWT2D 类,用于此特定目的。它使用 MMX 优化,适用于执行二元下采样的图像处理领域:2, 4, 8, 16, 32 ... pow(2, N) 次。 我在人脸检测过程中使用该代码作为预处理。

背景

您需要熟悉 Haar 变换。

Using the Code

我安排了一个控制台项目,为 640x480 图像分配 RGB 数组,并实现了几次下采样以收集统计数据并输出其平均时间。我使用了精确的时间计数器 - 我记得很久以前从 Code Project 下载的。 在我的 2.2GHz TravelMate 上的已许可 Vista 系统上,将此图像下采样到 80x60(缩小八倍)需要 5-6 毫秒。

项目中的类是

  • vec1D //1D vector wrapper
  • vec2D //2D vector wrapper
  • BaseFWT2D //abstract base class for 2D FWT
  • Haar : public BaseFWT2D //Haar based down sampling
  • ImageResize //provides RGB data down sampling

您可以从我的文章 用于图像处理的 2D 快速小波变换库 了解 vec1DBaseFWT2D,以及从我的另一篇文章 2D 向量类包装器,SSE 优化用于数学运算 了解 vec2D

ImageResize 类包含三个 Haar 类的对象,用于红色、绿色和蓝色通道的下采样。 首先,您需要将 ImageResize 对象初始化为特定的宽度、高度和下采样比率

  • void init(unsigned int w, unsigned int h, float zoom = 0.125f);

缩放因子是图像下采样因子,生成的图像将按 1/zoom 倍下采样。 默认值(0.125f)提供 8 倍下采样的图像。 您只能使用等于 1/2、1/4、1/8、... 1/pow(2,N) 的缩放比例对图像进行下采样。

然后,您可以使用以下重载函数对传入的图像进行下采样

  • int resize(const unsigned char* pBGR);
  • int resize(const unsigned char* pR, const unsigned char* pG, 
                const unsigned char* pB) const;

第一个函数采用 RGB 流,其中三元组中的第一个字节用于蓝色通道,最后一个字节用于红色通道。第二个函数将 RGB 通道放在单独的缓冲区中。

//your bitmap data goes in that fashion
//unsigned char* pBGR = new unsigned char[width*height*3];

unsigned int width = 640;
unsigned int height = 480;
float zoom = 0.25;

ImageResize resize;
resize.init(width, height, zoom);

//keep resizing incoming data after initialization.
resize.resize(pBGR);

为了访问下采样的图像,定义了以下函数

  • char** getr() const;
  • char** getg() const;
  • char** getb() const;

请注意,它们提供 2D char 指针,指向 char 范围 -128 ... 127 中的数据。

//print out resized red channel
char** pr = resize.getr();
for(unsigned int y = 0; y < height * zoom; y++) {
        for(unsigned int x = 0; x < width * zoom; x++)
                wprintf(L" %d", (pr[y][x] + 128));
        wprintf(L"\n");
}

您还可以在 resize() 调用后使用以下方法访问 RGB 位图的下采样灰度版本

  • inline const vec2D* gety() const;

它返回 vec2D 类型的指针。我编写了 rgb2y(int r, int g, int b) 函数,用于将单个 RGB 三元组转换为具有 SSE 优化的灰度像素,但是,我目前在该版本的类中使用简单的浮点运算,并打开了编译器的 SSE 优化。 实际上,它运行速度比我的 SSE 优化函数略快(稍后需要看一下)。

HaarBaseFWT2D 的扩展非常简单。我为虚拟函数 BaseFWT2D::transrows()BaseFWT2D::transcols() 提供了实现(我没有为 BaseFWT2D::synthrows()BaseFWT2D::synthcols() 编写,因为这是一个下采样类,而不是上采样)。它们是 MMX 优化的,Haar 变换背后的数学原理是,您取 2 个连续的像素,并计算它们的平均值。 因此,您首先沿水平方向将图像的大小减小两倍,并且垂直方向也是如此。 当您按列执行此操作时,这很容易,但是对于单个行,您必须选择连续的偶数和奇数像素,并并行地对它们进行平均。

我这样做

unsigned char* sour;

__m64 m00FF;
m00FF.m64_u64 = 0x00FF00FF00FF00FF;

__m64 *msour = (__m64 *)sour;

//even coeffs
__m64 even = _mm_packs_pu16(_mm_and_si64
    (*msour, m00FF), _mm_and_si64(*(msour + 1), m00FF));
//odd coeffs
__m64 odd = _mm_packs_pu16(_mm_srli_pi16(*msour, 8), _mm_srli_pi16(*(msour + 1), 8));

msour += 2;

关注点

可以使用 SSE2 整数内部函数修改 Haar 类,以实现更快的处理,我希望以后能够实现并提交更新,否则,如果有人有兴趣使用 SSE2 支持修改它,请告诉我。 我敢打赌,使用 SSE2 可以将 640x480 下采样到 80x60 的时间约为 1-2 毫秒。

历史

  • 2007 年 10 月 18 日:初始发布
© . All rights reserved.