OpenCV官方教程中文版 —— 图像金字塔

news2024/11/17 7:52:11

OpenCV官方教程中文版 —— 图像金字塔

  • 前言
  • 一、原理
  • 二、使用金字塔进行图像融合

前言

学习图像金字塔

使用图像创建一个新水果:“橘子苹果”

将要学习的函数有:cv2.pyrUp(),cv2.pyrDown()。

一、原理

一般情况下,我们要处理是一副具有固定分辨率的图像。但是有些情况下,我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小。这种情况下,我们需要创建创建一组图像,这些图像是具有不同分辨率的原始图像。我们把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集合)。如果我们把最大的图像放在底部,最小的放在顶部,看起来像一座金字塔,故而得名图像金字塔。

有两类图像金字塔:高斯金字塔和拉普拉斯金字塔。

高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。这样操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。所以这幅图像的面积就变为原来图像面积的四分之一。这被称为 Octave。连续进行这样的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函数cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。

函数 cv2.pyrDown() 从一个高分辨率大尺寸的图像向上构建一个金子塔(尺寸变小,分辨率降低)。

# -*- coding:utf-8 -*-
import cv2 as cv

# 高斯金字塔
def pyramid_demo(image):
    level = 4  # 金字塔的层数
    temp = image.copy()  # 拷贝图像
    pyramid_images = []
    for i in range(level):
        dst = cv.pyrDown(temp)  # down是降采样-尺寸变小,分辨率降低(缩小)
        pyramid_images.append(dst)
        cv.imshow("pyramid" + str(i), dst)
        temp = dst.copy()
    return pyramid_images

src = cv.imread("ball.png")
cv.namedWindow('input image', cv.WINDOW_NORMAL)
cv.imshow("input image", src)
pyramid_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

下图是一个四层的图像金字塔。

在这里插入图片描述
函数 cv2.pyrUp() 从一个低分辨率小尺寸的图像向下构建一个金子塔(尺寸变大,但分辨率不会增加)。

higher_reso2 = cv2.pyrUp(lower_reso)

你要记住的是是 higher_reso2 和 higher_reso 是不同的。因为一旦使用 cv2.pyrDown(),图像的分辨率就会降低,信息就会被丢失。下图就是从 cv2.pyrDown() 产生的图像金字塔的(由下到上)第三层图像使用函数cv2.pyrUp() 得到的图像,与原图像相比分辨率差了很多。

在这里插入图片描述

拉普拉斯金字塔可以有高斯金字塔计算得来,公式如下:

在这里插入图片描述
拉普拉金字塔的图像看起来就像边界图,其中很多像素都是 0。他们经常被用在图像压缩中。下图就是一个三层的拉普拉斯金字塔:

# -*- coding:utf-8 -*-
import cv2 as cv
# 高斯金字塔
def pyramid_demo(image):
    level = 4  # 金字塔的层数
    temp = image.copy()  # 拷贝图像
    pyramid_images = []
    for i in range(level):
        dst = cv.pyrDown(temp)  # down是降采样-尺寸变小,分辨率降低(缩小)
        pyramid_images.append(dst)
        cv.imshow("pyramid" + str(i), dst)
        temp = dst.copy()
    return pyramid_images


# 拉普拉斯金字塔,拉普拉斯金字塔时,图像大小必须是2的n次方*2的n次方,不然会报错
def laplian_demo(image):
    pyramid_images = cv.resize(image, (512, 512), interpolation=cv.INTER_CUBIC)  # 可以替换成INTER_LINEAR
    pyramid_images = pyramid_demo(pyramid_images)
    level = len(pyramid_images)  # 4 层
    for i in range(level-1, 0, -1):  # 每次递减
        expand = cv.pyrUp(pyramid_images[i], dstsize=pyramid_images[i - 1].shape[:2])
        lpls = cv.subtract(pyramid_images[i - 1], expand)
        cv.imshow("lpls_down" + str(i), lpls)

def pyramid_demo_2(image):
    higher_reso2 = cv.pyrUp(image)
    cv.imshow("pyramid", higher_reso2)
    return higher_reso2

src = cv.imread("ball.png")
src2 = cv.imread("lower_reso.png")
cv.namedWindow('input image', cv.WINDOW_NORMAL)
cv.imshow("input image", src)
#pyramid_demo(src)
#pyramid_demo_2(src2)
laplian_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

二、使用金字塔进行图像融合

图像金字塔的一个应用是图像融合。例如,在图像缝合中,你需要将两幅图叠在一起,但是由于连接区域图像像素的不连续性,整幅图的效果看起来会很差。这时图像金字塔就可以排上用场了,他可以帮你实现无缝连接。这里的一个经典案例就是将两个水果融合成一个,看看下图也许你就明白我在讲什么了。

你可以通过阅读后边的更多资源来了解更多关于图像融合,拉普拉斯金字塔的细节。实现上述效果的步骤如下:

  1. 读入两幅图像,苹果和橘子
  2. 构建苹果和橘子的高斯金字塔(6 层)
  3. 根据高斯金字塔计算拉普拉斯金字塔
  4. 在拉普拉斯的每一层进行图像融合(苹果的左边与橘子的右边融合)
  5. 根据融合后的图像金字塔重建原始图像。

在这里插入图片描述
整个过程的代码如下。(为了简单,每一步都是独立完成的,这回消耗更多的内存,如果你愿意的话可以对他进行优化)

在这里插入图片描述

# -*- coding: utf-8 -*-
import cv2
from matplotlib import pyplot as plt
import numpy as np

A = cv2.imread('apple.png')
A = cv2.resize(A, (256, 256), interpolation=cv2.INTER_CUBIC)  # 可以替换成INTER_LINEAR
B = cv2.imread('orange.png')
B = cv2.resize(B, (256, 256), interpolation=cv2.INTER_CUBIC)  # 可以替换成INTER_LINEAR
b, g, r = cv2.split(A)
A = cv2.merge([r, g, b])
b, g, r = cv2.split(B)
B = cv2.merge([r, g, b])

# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)

# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpA[i])
    L = cv2.subtract(gpA[i - 1], GE)
    lpA.append(L)

# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpB[i])
    L = cv2.subtract(gpB[i - 1], GE)
    lpB.append(L)

# Now add left and right halves of images in each level
# numpy.hstack(tup)
# Take a sequence of arrays and stack them horizontally
# to make a single array.

LS = []
for la, lb in zip(lpA, lpB):
    rows, cols, dpt = la.shape
    ls = np.hstack((la[:, 0:int(cols / 2)], lb[:, int(cols / 2):]))
    LS.append(ls)

# now reconstruct
ls_ = LS[0]
for i in range(1, 6):
    ls_ = cv2.pyrUp(ls_)
    ls_ = cv2.add(ls_, LS[i])

# image with direct connecting each half
real = np.hstack((A[:, :int(cols / 2)], B[:, int(cols / 2):]))

plt.figure()
plt.subplot(221)
plt.imshow(A)  # expects distorted color
plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
plt.title("apple")
plt.subplot(222)
plt.imshow(B)  # expect true color
plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
plt.title("orange")
plt.subplot(223)
plt.imshow(real)  # expect true color
plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
plt.title("Direct_connection")
plt.subplot(224)
plt.imshow(ls_)  # expect true color
plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
plt.title("Pyramid_blending")
plt.show()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Ubuntu18.04】激光雷达与相机联合标定(Livox+HIKROBOT)(一)

LivoxHIKROBOT联合标定 引言1 海康机器人HIKROBOT SDK二次开发并封装ROS1.1 介绍1.2 安装MVS SDK1.3 封装ROS packge 2 览沃Livox SDK二次开发并封装ROS3 相机雷达联合标定3.1 环境配置3.1.1 安装依赖——PCL 安装3.1.2 安装依赖——Eigen 安装3.1.3 安装依赖——Ceres-solver …

计算机视觉-数学基础*变换域表示

被研究最多的图像(或任何序列数据)变换域表示是通过傅 里叶分析 。所谓的傅里叶表示就是使用 正弦函数的线性组合来表示信号。对于一个给定的图像I(n1,n2) ,可以用如下方式分解它(即逆傅里叶变换): 其中&a…

浅谈APP自动化测试工具主要优势

移动应用程序已经成为我们日常生活和商业活动的重要组成部分。随着用户对应用性能、稳定性和用户体验的需求不断增加,开发人员不得不寻找方法来确保他们的应用在各种情况下都能正常运行。这就引入了自动化测试工具,这些工具通过自动执行测试用例来检查应…

openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立

文章目录 openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立107.1 默认的用户权限107.2 三权分立较非三权分立权限变化说明 openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立 默认权限机制和管理员两节的描述基于的是openGauss创建之初…

2023-10-23 LeetCode每日一题(老人的数目)

2023-10-23每日一题 一、题目编号 2678. 老人的数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的字符串 details 。details 中每个元素都是一位乘客的信息,信息用长度为 15 的字符串表示,表示方式如下: 前十…

Java,回形数

回形数基本思路: 用不同的四个分支分别表示向右向下向左向上,假如i表示数组的行数,j表示数组的列数,向右向左就是控制j的加减,向上向下就是控制i的加减。 class exercise {public static void main(String[] args){//回…

Jenkins 重新定义 pom 内容,打包

文章目录 源码管理构建 源码管理 添加仓库地址,拉取凭证,选择需要的分支 构建 勾选 构建环境 下删除原始 build 配置,防止文件错误 Pre Steps 构建前处理 pom.xml ,例如我是需要删除该模块的所有子模块配置,我这里…

超声波清洗机频率如何选择?高频和低频有什么区别

超声波清洗原理就是在清洗液中产生“空化效应”,即清洗液产生拉伸和压缩现象,清洗液拉伸时会产生大量微小气泡,清洗液压缩时气泡会被压碎破裂。这些气泡产生和破裂的局部压强可达到上千个大气压的冲击力,这种极强大的压力足以使得…

切片不够技术来凑

概述 随着数据经度的提升,18级的切片有些场景已经不够用了,但是大部分在线的栅格切片最大级别还是18级,如果地图继续放大,有的框架(leaflet会,openlayers和mapboxGL不会)会存在没有底图的情况。…

Spring源码篇(十二)事件机制

文章目录 前言应用示例第一种:EventListener第二种:实现ApplicationListener第三种:TransactionalEventListener补充:筛选条件 源码初始化事件器注册监听器添加监听器添加1:应用启动前的监听器SpringApplication实例化…

Hadoop3教程(三十五):(生产调优篇)HDFS小文件优化与MR集群简单压测

文章目录 (168)HDFS小文件优化方法(169)MapReduce集群压测参考文献 (168)HDFS小文件优化方法 小文件的弊端,之前也讲过,一是大量占用NameNode的空间,二是会使得寻址速度…

【Linux】进程优先级|进程并发概念|在vim中批量化注释

文章目录 前言tips——如何在vim中批量化注释进程更深度理解一、什么是进程优先级二、 为什么要有优先级三、Linux怎么设置优先级查看进程优先级的命令PRI and NI用top命令更改已存在进程的nice: 如何根据优先级开展调度呢?五、其他概念并发(…

使用Github.io创建自己的博客

文章目录 1.最终效果2.操作步骤2.1 前置操作2.2 按照自己需求修改内容2.2.1 基本修改2.2.2 额外添加知乎等社交网站链接 2.3 首页修改2.4 查看发布状态2.5 奇怪的错误(头像显示错误)2.6 本地调试2.7 后续修改 3. 项目设置为私密(要付费升级账号才行❌)3.…

【BA-BP分类】基于蝙蝠算法优化神经网络分类研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

RHCE---Shell基础 2

文章目录 目录 文章目录 前言 一.变量 概述 定义 自定义变量 环境变量 概述: 定义环境变量: 位置变量 "$*"会把所有位置参数当成一个整体(或者说当成一个单词 变量的赋值和作用域 read 命令 变量和引号 变量的作用域 变…

Java SOAP 调用 C# 的WebService

Java SOAP 调用 C# 的WebService,C# 的WebService方法的创建可以参考上一篇文章。IntelliJ IDEA Community Edition 2021.2.3的idea64.exe新建项目,导入需要的jar,代码如下: import org.apache.axis.client.Service; import org.…

微信小程序 picker-view 组件构建一个上下拖动选择器

picker-view是官方的一个选择器组件 支持多级选择 当然也可以单项选择 我们先来看看是个什么东西吧 简单写一个 wxml代码 <view><picker-view bindchange"pickerChange" style"width: 300rpx; height: 200rpx; font-size: 20px;"><!-- pic…

1.顺序表-头插、头删、尾插、尾删

文章目录 简介1.头插功能2.头删功能3.尾插功能4.尾删功能5.此程序共包含4个文件&#xff0c;2个.c文件和2个.h文件5.1 SeqList.h文件5.2 SeqList.c文件5.3 test.h文件5.4 test.c文件 6.测试结果6.1 测试尾插和尾删的运行结果6.2 测试头插和头删的运行结果 7.温馨提示 简介 本文…

实战:打造一个开箱即用的超丝滑超漂亮hexo博客网站-v4-(通过百度网盘同步空间来同步source核心数据)

实战&#xff1a;打造一个开箱即用的超丝滑超漂亮hexo博客网站-v4-(通过百度网盘同步空间来同步source核心数据) 目录 文章目录 实战&#xff1a;打造一个开箱即用的超丝滑超漂亮hexo博客网站-v4-(通过百度网盘同步空间来同步source核心数据)目录写在前面本次更新方案背景方案官…

C语言每日一题(17)老人的数目

力扣 2678 老人的数目 给你一个下标从 0 开始的字符串 details 。details 中每个元素都是一位乘客的信息&#xff0c;信息用长度为 15 的字符串表示&#xff0c;表示方式如下&#xff1a; 前十个字符是乘客的手机号码。接下来的一个字符是乘客的性别。接下来两个字符是乘客的…