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






4.67/5 (9投票s)
本文演示了使用 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 快速小波变换库 了解 vec1D
和 BaseFWT2D
,以及从我的另一篇文章 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 优化函数略快(稍后需要看一下)。
Haar
对 BaseFWT2D
的扩展非常简单。我为虚拟函数 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 日:初始发布