图像金字塔常用作多分辨率模型。视频图像的多分辨率模型是视频图像处理的重要方法。图像金字塔包括高斯金字塔和拉普拉斯金字塔两种实现形式。
高斯金字塔的实现包括两步:高斯低通滤波和下采样。首先利用高斯核对图像进行卷积;然后进行下采样,得到不同尺度下的目标图像。
高斯金字塔工作原理,为了获取层级为i+1层的高斯金字塔图像:
(1)对图像i进行高斯内核卷积
(2)将所有偶数行和列去除
得到的图像即为 i+1层的图像,显而易见,结果图像只有原图的四分之一。通过对输入图像i层(原始图像)不停迭代以上步骤就会得到整个金字塔。同时我们也可以看到,向下取样会逐渐丢失图像的信息。
以上就是对图像的向下取样操作,即缩小图像。
拉普拉斯金字塔是建立在高斯金字塔的基础上的,就是高斯金字塔在不同层之间的差分。
拉普拉斯金字塔工作原理:
如果想放大图像,则需要通过向上取样操作得到,具体做法如下:
(1)将图像在每个方向扩大为原来的两倍,新增的行和列以0填充
(2)使用先前同样的内核(乘以4)与放大后的图像卷积,获得 “新增像素”的近似值
得到的图像即为放大后的图像,但是与原来的图像相比会发觉比较模糊,因为在缩放的过程中已经丢失了一些信息,如果想在缩小和放大整个过程中减少信息的丢失,这些数据形成了拉普拉斯金字塔。
也就是说,拉普拉斯金字塔是通过源图像减去先缩小后再放大的图像的一系列图像构成的。
实验环境:
(1)OpenCV3.4.3
(2)Ubuntu16.04
(3)VS Code
(4)C++
#include
#include
#include
#include
#include
#include
#include
class Exp8{
public:
Exp8(std::vector path){
for(int i = 0; i < path.size(); i++){
original_color_image.push_back(cv::imread(path[i]));
original_gray_image.push_back(color2Gray(original_color_image[i]));
}
std::cout<< "初始化结束" << "\n";
for(int i = 5; i < 10; i = i + 2){
makeGaussTemplate(i);
filter_size.push_back(i);
}
computerGaussTemplateSum();
zerosPadding(0);
}
// 0 彩色图像转灰度图像
cv::Mat color2Gray(cv::Mat& src){
//创建与原图同类型和同大小的矩阵
cv::Mat gray_image = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);
if(src.channels()!=1){
for(int i = 0; i < src.rows; i++)
for(int j = 0; j < src.cols; j++)
gray_image.at(i, j) = (src.at(i, j)[0] + src.at(i, j)[1] + src.at(i, j)[2]) / 3;
}
else
gray_image = src.clone();
return gray_image;
}
// 1 生成高斯滤波模板
void makeGaussTemplate(int size=5, int sigma=1){
cv::Mat gaussTemplate = cv::Mat::zeros(size, size, CV_32F);
int center=size/2;
double min = g(center,center);
for(int i=0; i < size; i++)
for(int j=0; j < size; j++)
gaussTemplate.at(i, j) = g(i-center,j-center)/min;
gaussTemplate.convertTo(gaussTemplate, CV_8U);
gauss_template.push_back(gaussTemplate);
}
// 1.1 计算正态分布
double g(double x, double y, double sigma=1){
return exp(-(x*x + y*y)/(2*sigma*sigma));
}
// 1.2 计算高斯模板之和
void computerGaussTemplateSum(){
for(int k=0; k < gauss_template.size(); k++){
int sum = 0;
for(int i=0; i < gauss_template[k].rows; i++)
for(int j=0; j < gauss_template[k].cols; j++)
sum += gauss_template[k].at(i, j);
gauss_template_sum.push_back(sum);
}
}
// 1.3 预处理零填充
void zerosPadding(int id, int kernel_size=5){
int m = kernel_size/2;
cv::Mat gray_dst = cv::Mat::zeros(2*m + original_gray_image[id].rows, 2*m + original_gray_image[id].cols, original_gray_image[id].type());
cv::Mat color_dst = cv::Mat::zeros(2*m + original_color_image[id].rows, 2*m + original_color_image[id].cols, original_color_image[id].type());
// 相加,填充零
gray_dst(cv::Rect(m, m, original_gray_image[id].cols, original_gray_image[id].rows)) += original_gray_image[id];
color_dst(cv::Rect(m, m, original_color_image[id].cols, original_color_image[id].rows)) += original_color_image[id];
color_image_padding.push_back(color_dst);
gray_image_padding.push_back(gray_dst);
}
// 1.4 计算高斯滤波
int computerGaussResult(cv::Mat& image_block, int size_id=0){
int sum = gauss_template_sum[size_id];
return image_block.dot(gauss_template[size_id])/sum;
}
// 2 向下采样,缩小图像
void grayDownSampling(int pic_id, int level=1, int size_id=0){
int size = filter_size[size_id];
int m = size/2;
int rate=2*level;
cv::Mat image_shrink = cv::Mat::zeros(original_gray_image[pic_id].rows/rate, original_gray_image[pic_id].cols/rate, original_gray_image[pic_id].type());
cv::Mat image_process = cv::Mat::zeros(original_gray_image[pic_id].size(), original_gray_image[pic_id].type());
// 1 高斯滤波
for(int i = m; i < gray_image_padding[pic_id].rows - m; i++)
for(int j = m; j < gray_image_padding[pic_id].cols - m; j++){
cv::Mat sub_matrix = gray_image_padding[pic_id](cv::Rect(j - m, i - m, size, size));
image_process.at(i - m, j - m) = computerGaussResult(sub_matrix, size_id);
}
cv::imshow("高斯滤波", image_process);
cv::waitKey(0);
// 2 缩小图像
for(int i = 0; i < image_shrink.rows - m; i++)
for(int j = 0; j < image_shrink.cols - m; j++)
image_shrink.at(i, j) = image_process.at(rate*i + 1, rate*j + 1);
gray_image_downsampling.push_back(image_shrink);
}
// 3 向上采样,放大图像
void grayUpSampling(int pic_id, int level=1, int size_id=0){
int size = filter_size[size_id];
int m = size/2;
int rate=2*level;
// 1 放大图像
cv::Mat image_amplify = cv::Mat::zeros(gray_image_downsampling[pic_id].rows*rate, gray_image_downsampling[pic_id].cols*rate, gray_image_downsampling[pic_id].type());
for(int i = 0; i < gray_image_downsampling[pic_id].rows - m; i++)
for(int j = 0; j < gray_image_downsampling[pic_id].cols - m; j++)
image_amplify.at(rate*i + 1, rate*j + 1) = gray_image_downsampling[pic_id].at(i, j);
cv::imshow("直接放大", image_amplify);
cv::waitKey(0);
// 2 高斯滤波
//int rows=image_amplify.rows, cols = image_amplify.cols;
cv::Mat image_process = image_amplify.clone();
imageZerosPadding(image_amplify, image_amplify);
//cv::Mat image_process = image_amplify.clone();
for(int i = m; i < image_amplify.rows - m; i++)
for(int j = m; j < image_amplify.cols - m; j++){
cv::Mat sub_matrix = image_amplify(cv::Rect(j - m, i - m, size, size));
//image_process.at(i, j) = 4*computerGaussResult(sub_matrix, size_id);
if((i-m) == 0 || (j-m) == 0 || (i-m) == (image_process.rows-1) || (j-m) == (image_process.cols-1))
image_process.at(i-m, j-m) = 8*computerGaussResult(sub_matrix, size_id);
else
image_process.at(i-m, j-m) = 4*computerGaussResult(sub_matrix, size_id);
//std::cout<<"j-m:"< original_color_image;
std::vector original_gray_image;
// 零填充图像
std::vector color_image_padding;
std::vector gray_image_padding;
// 高斯滤波模板
std::vector gauss_template;
std::vector gauss_template_sum;
// 降采样后的图像
std::vector color_image_downsampling;
std::vector gray_image_downsampling;
// 向上采样后的图像
std::vector color_image_upsampling;
std::vector gray_image_upsampling;
// 高斯模板尺寸
std::vector filter_size;
};
int main(){
std::vector path;
path.push_back("/home/lyd/image_process/pic/lena.jpg");
Exp8 a(path);
a.run();
return 0;
}