朱琛的小屋

opencv小练习:哈尔小波(haar)

首先说一下一维haar小波的原理。
例如我们有一个一维的图像[2,4,6,8,10,12,14,16].

  1. 求均值:我们求相邻像素的均值[3,7,11,15]。这个新的图像分辨率就成了原来的一半(8/2=4)。
  2. 求差值。上面的均值我们存储了图像的整体信息。但是很多细节信息我们丢掉了,所以我们同时要记录图像的细节信息,这样在重构时能够恢复图像的全部信息。下面是求第m个差值的公式:

$$b[m]=(a[2m]-a[2m+1])/2$$
经过计算我们得到了结果[-1,-1,-1,-1]。这个新的分辨率也成了原来的一半(8/2=4)。

  1. 此时上面两步形成了第一次分解的结果[3,7,11,15,-1,-1,-1,-1]。包含了图像的整体信息和细节信息。接下来的分解我们重复1,2步,将整体信息再次进行分解,得到了二级分解结果[5,13,-2,-2].同样的,前面的[5,13]是整体信息,后面的[-2,-2]是细节信息。
分辨率 整体信息 细节信息
4 3,7,11,15 -1,-1,-1,-1
2 5,13 -2,-2
1 9 -4

经过三次分解,我们得到了一个整体信息和三个细节系数,这个就是一维小波变换。

对于二维haar小波,我们通常一次分解形成了整体图像,水平细节,垂直细节,对角细节。首先我们按照一维haar小波分解的原理,按照行顺序对行进行处理,然后按照列顺序对行处理结果进行同样的处理。最后形成了如下的形式。

cpp代码(opencv版本:opencv3.0):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*************************************************
Copyright:zhuchen
Author: zhuchen
Date:2016-01-10
Description:多级haar小波变换
**************************************************/



# include<opencv2/opencv.hpp>
# include<iostream>

using namespace std;
using namespace cv;

int main(){
Mat img = imread("lenna.bmp",0);
int Height = img.cols;
int Width = img.rows;
int depth = 3; //定义分解深度
int depthcount = 1;
Mat tmp = Mat::ones(Width, Height, CV_32FC1);
Mat wavelet = Mat::ones(Width, Height, CV_32FC1);
Mat imgtmp = img.clone();
imgtmp.convertTo(imgtmp, CV_32FC1);
while (depthcount<=depth){
Width = img.rows / depthcount;
Height = img.cols / depthcount;
int step = 2 * depthcount;
for (int i = 0; i < Width; i++){
for (int j = 0; j < Height / 2; j++){
tmp.at<float>(i, j) = (imgtmp.at<float>(i, 2 * j) + imgtmp.at<float>(i, 2 * j + 1)) / 2;
tmp.at<float>(i, j + Height / 2) = (imgtmp.at<float>(i, 2 * j) - imgtmp.at<float>(i, 2 * j + 1)) / 2;
}
}
for (int i = 0; i < Width / 2; i++){
for (int j = 0; j < Height; j++){
wavelet.at<float>(i, j) = (tmp.at<float>(2 * i, j) + tmp.at<float>(2 * i + 1, j)) / 2;
wavelet.at<float>(i + Width / 2, j) = (tmp.at<float>(2 * i, j) - tmp.at<float>(2 * i + 1, j)) / 2;
}
}
imgtmp = wavelet;
depthcount++;
}

namedWindow("jpg",0);
wavelet.convertTo(wavelet, CV_8UC1);
wavelet += 50; //图像暗度过低,所以这里我加了50
imshow("jpg", wavelet);
waitKey(0);
return 0;
}
朱琛 wechat
扫一扫,用手机看更方便~
坚持原创技术分享,您的支持将鼓励我继续创作!