图像和视频编码过程中,采用变换将像素值转换到频域进行处理。JPEG和H.26x通常将图像分成小块,在块内进行变换编码。这种方式容易产生块效应。
小波变换的变换基长度是可变的,因此可以对整帧图像进行处理,避免了分块过程。
下图为对一幅图像进行一次小波变换示意图。
![](https://i-blog.csdnimg.cn/blog_migrate/2a5039d64c7d427371764bb1e086f8f4.png)
图像分辨率为MxN,首先乘以右边的MxM矩阵,得到的结果中,左半边是低频图像,右半边是水平方向高频图像。然后,左边的NxN矩阵再乘以中间图像,得到的结果中图像被分为四个部分,如下图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/b377342b20982a963ac4cdd2f8098f6f.png)
对图像的左上角低频的A部分,可以再进行小波变换,结果如下图
![](https://i-blog.csdnimg.cn/blog_migrate/b7f1465b875ad5522b2715f523039f5a.png)
下面代码为小波变换示例程序。读取yuv420序列,对每一帧进行小波变换后,输出对应的图像文件。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ABS(x) ( (x)>=0?(x):-(x) )
int main(int argc, char* argv[])
{
FILE *yuv420_file, *yuv420_dwtfile;
long f_size = 0;
int pic_width, pic_height, yuv420_frame_size, yuv420_y_size, yuv420_frame_num;
int pixel_byte = 1; // 8bit
unsigned char *yuv420_buf, *yuv420_dwtbuf;
unsigned char *psrc_yuv420, *pdst_yuv420_dwt;
int i, w, h, depth_count, dwt_width, dwt_height;
int dwt_depth = 1;
if(argc < 6)
{
printf("This program is used to load yuv420 frame and perform discrete wavelet transform.\n");
printf("Usage:\n");
printf("yuv_dwt yuv420file output_dwtfile width height dwt_depth\n");
return 0;
}
printf("Input YUV420 File: %s\n", argv[1]);
yuv420_file = fopen(argv[1], "rb");
if(yuv420_file == NULL)
{
printf("Open input yuv420(10bit) file %s error\n", argv[1]);
return -1;
}
yuv420_dwtfile = fopen(argv[2], "wb");
if(yuv420_dwtfile == NULL)
{
printf("Open output file %s error\n", argv[2]);
fclose(yuv420_file);
return -1;
}
pic_width = atoi(argv[3]);
pic_height = atoi(argv[4]);
dwt_depth = atoi(argv[5]);
yuv420_frame_size = pic_width * pic_height * 3 / 2 * pixel_byte; // yuv420frame is 10bit
yuv420_y_size = pic_width * pic_height * pixel_byte; // yuv420frame is 10bit
yuv420_buf = (unsigned char*)malloc(yuv420_frame_size);
yuv420_dwtbuf = (unsigned char*)malloc(yuv420_y_size);
fseek(yuv420_file, 0L, SEEK_END); // seek to file end
f_size = ftell(yuv420_file);
fseek(yuv420_file, 0L, SEEK_SET); // seek to file begin
yuv420_frame_num = f_size / yuv420_frame_size;
printf("YUV420 Frame Size %dx%d, Frame numbers = %d\n", pic_width, pic_height, yuv420_frame_num);
for(i = 0; i < yuv420_frame_num; i++)
{
printf("Process Frame %d\n", i + 1);
fread(yuv420_buf, 1, yuv420_frame_size, yuv420_file);
psrc_yuv420 = (unsigned char *)yuv420_buf;
pdst_yuv420_dwt = (unsigned char *)yuv420_dwtbuf;
dwt_width = pic_width;
dwt_height = pic_height;
depth_count = 0;
while(depth_count < dwt_depth)
{
// Horizontal transform
for(h = 0; h < dwt_height; h++)
{
for(w = 0; w < dwt_width / 2; w++)
{
pdst_yuv420_dwt[h * pic_width + w] = (psrc_yuv420[h * pic_width + 2 * w] + psrc_yuv420[h * pic_width + 2 * w + 1]) / 2;
pdst_yuv420_dwt[h * pic_width + w + dwt_width / 2] = ABS(psrc_yuv420[h * pic_width + 2 * w] - psrc_yuv420[h * pic_width + 2 * w + 1]) / 2;
}
}
// Vertical transform
for(w = 0; w < dwt_width; w++)
{
for(h = 0; h < dwt_height / 2; h++)
{
psrc_yuv420[h * pic_width + w] = (pdst_yuv420_dwt[2 * h * pic_width + w] + pdst_yuv420_dwt[(2 * h + 1) * pic_width + w]) / 2;
psrc_yuv420[(dwt_height / 2 + h) * pic_width + w] = ABS(pdst_yuv420_dwt[2 * h * pic_width + w] - pdst_yuv420_dwt[(2 * h + 1) * pic_width + w]) / 2;
}
}
depth_count++;
dwt_width /= 2;
dwt_height /= 2;
}
//*** Output dwt frame
fwrite(psrc_yuv420, 1, yuv420_y_size, yuv420_dwtfile);
}
fclose(yuv420_file);
fclose(yuv420_dwtfile);
free(yuv420_buf);
free(yuv420_dwtbuf);
}
原始图像如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f8a45a410f057d142edee97d8b1c20fa.jpeg)
一阶小波变换结果
![](https://i-blog.csdnimg.cn/blog_migrate/d1950e267150cd5386e90d72f70ce9a1.jpeg)
二阶小波变换结果
![](https://i-blog.csdnimg.cn/blog_migrate/efed7c24124660f0863b45abbcf4d404.jpeg)