数字图像处理之【高斯金字塔】与【拉普拉斯金字塔】

数字图像处理之【高斯金字塔】与【拉普拉斯金字塔】

1.1 什么是高斯金字塔?

高斯金字塔(Gaussian Pyramid)是一种多分辨率图像表示方法,用于图像处理和计算机视觉领域。它通过对原始图像进行一系列的高斯平滑和下采样操作,生成一组分辨率逐渐降低的图像层次结构。

高斯金字塔的构建过程通常包括以下步骤:

  1. 高斯平滑(Gaussian Smoothing):对原始图像应用高斯滤波器,生成一个平滑后的图像。高斯滤波器是一种低通滤波器,用于减少图像中的高频噪声。

  2. 下采样(Downsampling):将平滑后的图像进行下采样,通常是将图像的宽度和高度各减半,得到较低分辨率的图像。

  3. 重复上述步骤:对下采样后的图像重复高斯平滑和下采样过程,直到达到预定的分辨率级别。每一个新生成的图像称为一个金字塔层。

1.2 什么是拉普拉斯金字塔?

拉普拉斯金字塔(Laplacian Pyramid)基于高斯金字塔多分辨率图像表示方法,用于图像处理和计算机视觉领域。它通过从高斯金字塔中提取(高频)细节信息,形成一系列细节图像的层次结构。拉普拉斯金字塔可以用于图像压缩、图像增强和图像融合等任务。

构建拉普拉斯金字塔的过程通常包括以下步骤:

  1. 构建高斯金字塔:首先,通过高斯平滑和下采样操作构建高斯金字塔。

  2. 生成拉普拉斯金字塔层

    • 从高斯金字塔的每一层生成下一层(低分辨率层)后,将下一层上采样(通常是通过插值方法将图像的宽度和高度各加倍)回到当前层的分辨率。
    • 计算当前层与上采样后的图像的差值,得到当前层的拉普拉斯层。
  3. 重复上述步骤:对高斯金字塔的每一层重复生成拉普拉斯层的过程,直到达到最底层。

1.3 示意图

从图中我们可以得到什么信息?拉普拉斯金字塔图像=原图的高频信息。

因此如果我们想回复原图,是不是只要用拉普拉斯金字塔图像加上上采样后的图像就能得到?我想应该是的。但是用文字描述我认为过于繁琐,我们用数学公式来进行清晰的表达。

L n \mathrm{L_n} Ln为拉普拉斯金字塔的第 n \mathrm n n层(自底向上), G n \mathrm{G_n} Gn为高斯金字塔的第 n \mathrm n n层(自底向上), G a u s s B l u r \mathrm{GaussBlur} GaussBlur为高斯平滑函数, p y r D o w n \mathrm{pyrDown} pyrDown为下采样函数, p y r U p \mathrm{pyrUp} pyrUp为上采样函数,则有
G n + 1 = p y r D o w n ( G a u s s B l u r ( G n ) ) L n = G n − p y r U p ( p y r D o w n ( G a u s s B l u r ( G n ) ) ) G n = L n + p y r U p ( p y r D o w n ( G a u s s B l u r ( G n ) ) ) \begin{aligned} &\mathrm {G_{n+1}=pyrDown(GaussBlur(G_n))}\\ &\mathrm {L_n=G_{n}-pyrUp(pyrDown(GaussBlur(G_n)))}\\ &\mathrm {G_n=L_n+pyrUp(pyrDown(GaussBlur(G_n)))} \end{aligned} Gn+1=pyrDown(GaussBlur(Gn))Ln=GnpyrUp(pyrDown(GaussBlur(Gn)))Gn=Ln+pyrUp(pyrDown(GaussBlur(Gn)))

1.4 OpenCV实现

对于以上代码,读者可将图片换成自己喜欢的图片进行测试;函数内部有一部分条件语句是因为如果原图宽或高非偶数,那么下采样后再上采样就会和原图大小不一样。

比如 801 × 801 801\times801 801×801的图像下采样后尺寸是 401 × 401 401\times401 401×401(如果原图尺寸是奇数,那么使用向上取整的除法),再上采样就变成了 802 × 802 802\times802 802×802和原图尺寸不匹配。

为了正确处理这种突发情况,我们需要对图像进行裁剪,刚好裁剪1行和1列。

import cv2
import numpy as np


def correctSize(imgOri, imgDownsample):
    imgUpsample = cv2.pyrUp(imgDownsample)
    if imgOri.shape[0] % 2 == 1:  # 检查原始图像宽度是否为奇数
        imgUpsample = imgUpsample[1:, :, :]  # 如果是,将放大后的图像宽度减少1
        # imgUpsample = imgUpsample[1:, :]  # 如果是,将放大后的图像宽度减少1
    if imgOri.shape[1] % 2 == 1:  # 检查原始图像宽度是否为奇数
        imgUpsample = imgUpsample[:, 1:, :]  # 如果是,将放大后的图像宽度减少1
        # imgUpsample = imgUpsample[1:, :]  # 如果是,将放大后的图像宽度减少1
    return imgOri, imgUpsample


img = cv2.imread('lena.png')
# img = cv2.imread('lena.png',cv2.IMREAD_GRAYSCALE) # 读取灰度图像

print(img.shape)
img12 = cv2.pyrDown(img)
img14 = cv2.pyrDown(img12)
img18 = cv2.pyrDown(img14)
img116 = cv2.pyrDown(img18)
ori, imgUpsample = correctSize(img, img12)
# imgRes = cv2.subtract(img, img12)
# 暂不清楚用subtract有什么隐藏机制,用该函数做减法会损失不少信息,所以就直接用原始减法好了
imgRes = ori - imgUpsample
imgRes = imgRes.clip(0, 255)
# imgRes = cv2.subtract(*correctSize(img12, img14))
# imgRes = cv2.subtract(*correctSize(img14, img18))
# imgRes = cv2.subtract(*correctSize(img18, img116))

cv2.imshow("高斯金字塔第n层图像的高频信息图-拉普拉斯", imgRes)
# cv2.imshow("高斯金字塔第n层图像的高频信息图-拉普拉斯", np.hstack((imgUpsample, imgRes)))

cv2.waitKey()
cv2.destroyAllWindows()

1.5 手搓代码(高斯平滑+下采样+上采样+拉普拉斯图像生成)

首先给出高斯平滑所用的高斯核
1 256 [ 1 4 6 4 1 4 16 24 16 4 6 24 36 24 6 4 16 24 16 4 1 4 6 4 1 ] \frac{1}{256}\begin{bmatrix}1&4&6&4&1\\4&16&24&16&4\\6&24&36&24&6\\4&16&24&16&4\\1&4&6&4&1\end{bmatrix} 2561 1464141624164624362464162416414641

然后就是手搓代码了,纯手搓,但是运行速度有点慢,如果你图像很大的话

import cv2
import numpy as np

img = cv2.imread('lena.png')

# 定义高斯核,并归一化,用来做卷积
GaussSmoothKernel = np.array([[1, 4, 6, 4, 1],
                              [4, 16, 24, 16, 4],
                              [6, 24, 36, 24, 6],
                              [4, 16, 24, 16, 4],
                              [1, 4, 6, 4, 1]], dtype=np.float32)
GaussSmoothKernel = GaussSmoothKernel / 256

Smoothedimg = np.zeros(img.shape, dtype=np.uint8)

# 下面的单数是封装好的,可用来做图像卷积
# Smoothedimg = cv2.filter2D(img, -1, GaussSmoothKernel)
for i in range(img.shape[0]):
    for j in range(img.shape[1]):
        for k in range(3):
            if i-2 < 0 or i+2 >= img.shape[0] or j-2 < 0 or j+2 >= img.shape[1]:
                # 处理图像边边角角的模糊,在else语句中的操作没法对边角进行平滑,因为边界像素没有相邻像素,无法进行卷积操作
                for m in range(5):
                    for n in range(5):
                        if i+m-2 >= 0 and i+m-2 < img.shape[0] and j+n-2 >= 0 and j+n-2 < img.shape[1]:
                            Smoothedimg[i, j, k] += GaussSmoothKernel[m, n] * img[i+m-2, j+n-2, k]
            else:
                # 图像的边界处的像素无法通过此操作进行卷积操作
                Smoothedimg[i, j, k] = np.sum(GaussSmoothKernel * img[max(i-2, 0):min(i+3, img.shape[0]), max(j-2, 0):min(j+3, img.shape[1]), k], axis=(0, 1))

downsample = Smoothedimg[::2, ::2, :]

# 生成一个0值张量,用来存储上采样后的图像
Upsample = np.zeros((downsample.shape[0]*2, downsample.shape[1]*2, 3), dtype=np.uint8)

for i in range(downsample.shape[0]):
    for j in range(downsample.shape[1]):
        Upsample[i*2, j*2, :] = downsample[i, j, :]
        # 下面为插值操作
        Upsample[i*2+1, j*2, :] = downsample[i, j, :]
        Upsample[i*2, j*2+1, :] = downsample[i, j, :]
        Upsample[i*2+1, j*2+1, :] = downsample[i, j, :]

# 用于处理图像各方向为奇数的情况:这种情况上采样后图像会比原图大一点点,因此需要给它做个裁剪
if img.shape[0] % 2 == 1:
    Upsample = Upsample[1:, :, :]
if img.shape[1] % 2 == 1:
    Upsample = Upsample[:, 1:, :]

# 获取拉普拉斯图像
Laplacian = img - Upsample

# cv2.imshow('img', img)
# cv2.imshow('Smoothedimg', Smoothedimg)
# cv2.imshow('downsample', downsample)
# cv2.imshow('Upsample', Upsample)
# cv2.imshow('Laplacian', Laplacian)
cv2.imshow('ori+smoothedimg+downsample+Upsample+Laplacian', np.vstack((np.hstack((img, Smoothedimg)), np.hstack((Upsample, Laplacian)))))

# 该语句配合上面插值语句使用,把上面的插值语句注释,然后用下面这条语句输出,你将看到下采样丢失了多少信息
# cv2.imshow('DownsampleLossInfo', (Smoothedimg - Upsample).clip(0, 255))

cv2.waitKey(0)
cv2.destroyAllWindows()

看看效果呗,感觉手搓的效果还不赖,当然肯定没法和封装好的比,封装好的函数使用了更为复杂的插值算法

在这里插入图片描述

上图从左到右边,从上到下依次为 原图 → 高斯平滑后的图 → 经过下采样后,再进行上采样恢复了分辨率的图 → 拉普拉斯图 原图\to高斯平滑后的图\to经过下采样后,再进行上采样恢复了分辨率的图\to拉普拉斯图 原图高斯平滑后的图经过下采样后,再进行上采样恢复了分辨率的图拉普拉斯图

1.6 一些后话

其实看了上面的东西我觉得读者也应该理解为什么高斯核被称为低通滤波器了:低频信息总是通过(保留),高频信息却被删除了。这使得图像看起来更加平滑,减少了噪声和细节。

相反,OpenCVSobel算子就是一个具有高通滤波器性质的算子,该算子用来做图像锐化,即边缘增强,这意味着它会增强图像的边缘和细节,而使平滑区域变暗或去除。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/759853.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

istitle()方法——判断首字母是否大写其他字母小写

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 istitle()方法用于判断字符串中所有的单词首字母是否为大写而其他字母为小写。istitle()方法的语法格式如下&#xff1a; str.istitle() …

Java并发编程基础知识点

目录 Java并发编程基础知识点1、线程&#xff0c;进程概念及二者的关系进程相关概念线程相关概念进程与线程的关系补充小知识点&#xff1a; 2、线程的状态Java线程的状态&#xff1a;Java线程不同状态之间的切换图示 3、Java程序中如何创建线程&#xff1f;①、继承Thread类②…

【python】python知名品牌调查问卷数据分析可视化(源码+调查数据表)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

某度,网盘免费加速,复活!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 有小伙伴反馈之前如下夸克网盘脚本的加速方法失效&#xff0c;小武今天测试&#xff0c;依旧正常使用&#xff01; 百度/迅雷/夸克&#xff0c;网盘免费加速&#xff0c;已破&#xf…

Vite: 高阶特性 Pure ESM

概述 ESM 已经逐步得到各大浏览器厂商以及 Node.js 的原生支持&#xff0c;正在成为主流前端模块化方案。 而 Vite 本身就是借助浏览器原生的 ESM 解析能力( type“module” )实现了开发阶段的 no-bundle &#xff0c;即不用打包也可以构建 Web 应用。不过我们对于原生 ESM 的…

线性表与顺序存储结构(下)

前言 接上文&#xff08;线性表与顺序存储结构&#xff08;上&#xff09;&#xff09;。 这些顺序存储结构的方法在顺序表上下卷中已经提到过&#xff0c;但是有些许不同&#xff0c;可以为理解顺序表提供更丰富的视角。&#xff08;不过最主要的区别在于顺序表上下卷中的顺…

FairGuard游戏加固无缝兼容 Android 15 预览版

2024年6月25日&#xff0c;谷歌发布了 Android 15 Beta 3 &#xff0c;作为Android 15 “平台稳定性”的里程碑版本&#xff0c;谷歌建议所有应用、游戏、SDK、库和游戏引擎开发者都将“平台稳定性”里程碑版本作为规划最终兼容性测试和公开发布的目标。 安卓开发者博客提供的版…

Hadoop3:MapReduce中的ETL(数据清洗)

一、概念说明 “ETL&#xff0c;是英文Extract-Transform-Load的缩写&#xff0c;用来描述将数据从来源端经过抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;、加载&#xff08;Load&#xff09;至目的端的过程。ETL一词较常用在数据仓库&#…

算法09 日期相关模拟算法【C++实现】

这是《C算法宝典》算法篇的第09节文章啦~ 如果你之前没有太多C基础&#xff0c;请点击&#x1f449;专栏&#xff1a;C语法入门&#xff0c;如果你C语法基础已经炉火纯青&#xff0c;则可以进阶算法&#x1f449;专栏&#xff1a;算法知识和数据结构&#x1f449;专栏&#xff…

模型预测控制:线性MPC

模型预测控制&#xff1a;线性MPC 模型预测控制&#xff08;Model Predictive Control, MPC&#xff09;是一种广泛应用于工业过程控制和自动驾驶等领域的先进控制技术。MPC通过在线解决优化问题来计算控制输入&#xff0c;从而实现系统的最优控制。本文将介绍线性MPC的系统模…

架构师篇-8、运用事件风暴进行业务领域建

如何成为优秀架构师&#xff1f; 需要有一定的技术积累&#xff0c;但是核心是懂业务。 具备一定的方法&#xff0c;并且有很强的业务理解能力。 技术架构师&#xff1a;形成技术方案&#xff0c;做的更多的是底层的平台&#xff0c;提供工具。 业务架构师&#xff1a;解决方…

Cyber Weekly #13

赛博新闻 1、谷歌发布最强开源小模型Gemma-2 本周五&#xff08;6月28日&#xff09;凌晨&#xff0c;谷歌发布最强开源小模型Gemma-2&#xff0c;分别为9B&#xff08;90亿&#xff09;和27B&#xff08;270亿&#xff09;参数规模&#xff0c;其中9B 模型在多项基准测试中均…

50-4 内网信息收集 - 本机信息收集

一、内网信息收集 内网信息收集可以从以下几个方面进行:本机信息收集、域内信息收集、内网资源探测等。通过这些步骤,我们可以全面了解当前主机的角色和所处内网的拓扑结构,从而选择更合适、更精准的渗透方案。 二、本机基础信息收集 在本机基础信息收集阶段,可以执行以下…

怎么监控公司文件?高效省力的7个办法,企业都在用

公司文件监控方法主要包括以下几个方面&#xff0c;以确保数据安全和防止文件泄密&#xff1a; 使用专业监控软件&#xff1a;如安企神等专业的企业级监控软件&#xff0c;可以详细记录员工的电脑操作&#xff0c;包括文件访问、修改、删除、复制等行为&#xff0c;以及外设使用…

RTMP推流到SRS流媒体服务器消息处理

RTMP推流到SRS流媒体服务器消息处理 SRS和客户端是怎么交换消息的&#xff1f;各个消息有什么作用&#xff1f;握手成功后&#xff0c;SRS和客户端进行消息交换&#xff0c;对应wiresharek这部分截图&#xff1a; 流程图&#xff08;之前画的&#xff0c;可能不够详细&#xf…

百亿级存储架构: ElasticSearch+HBase 海量存储架构与实现

百亿级存储架构&#xff1a; ElasticSearchHBase 海量存储架构与实现 尼恩&#xff1a;百亿级数据存储架构起源 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;经常性的指导小伙伴们改造简历。 经过尼恩的改造之后&#xff0c;很多小伙伴拿到了一线互联网企业如得物、阿…

AI模型的奥运会:谁将在OlympicArena中夺冠?

获取本文论文原文PDF&#xff0c;请在公众号【AI论文解读】留言&#xff1a;论文解读 引言&#xff1a;AI模型的奥林匹克级评测 评估和比较不同AI模型的性能始终是一个核心话题。随着技术的不断进步&#xff0c;这些模型在处理复杂任务的能力上有了显著的提升。为了更精确地衡…

springboot汽车租赁管理系统-计算机毕业设计源码08754

目 录 摘 要 第 1 章 引 言 1.1 选题背景和意义 1.2 国内外研究现状 1.3 论文结构安排 第 2 章 系统的需求分析 2.1 系统可行性分析 2.1.1 技术方面可行性分析 2.1.2 经济方面可行性分析 2.1.3 法律方面可行性分析 2.1.4 操作方面可行性分析 2.2 系统功能需求分析…

有了文章生成器,轻易满足你对文章的需求

写文章对于大多数人来说并不轻松&#xff0c;往往一篇文章写作完成是需要消耗一个人的大量时间与精力的&#xff0c;如果想要写的文章特别好&#xff0c;那么还要再花一点时间去进入后期的修改。就没有什么方法让大家轻易的去完成文章写作吗&#xff1f;答案是有的&#xff0c;…

【TB作品】密码锁,ATMEGA128单片机,Proteus仿真

题目 5 &#xff1a;密码锁 使用单片机实现简易密码锁&#xff0c;通过输入密码&#xff0c;实现门锁的开启&#xff08;控制继电器&#xff09;。 具体要求如下&#xff1a; &#xff08;1&#xff09;当输入正确密码后&#xff0c;继电器开启。 &#xff08;2&#xff09;当三…