Resize:最近邻插值、双线性插值、双三次插值

Resize:最近邻插值、双线性插值、双三次插值

    • Opencv resize函数
      • 1. 最近邻插值(INTER_NEAREST)
        • 1.1 原理
        • 1.2 代码实例
        • 1.3 简单的代码复现
        • 1.4 特点
      • 2. 双线性插值(INTER_LINEAR)(默认值)
        • 2.1 原理
        • 2.2 简单的代码复现
      • 3. 双三次插值(INTER_CUBIC)
      • 4. 三种方法的直观对比

Opencv resize函数

官方文档:Opencv resize()

void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR );
参数含义: 
InputArray src     -原图像 
OutputArray dst    -输出图像 
Size dsize         -目标图像的大小 
double fx=0        -在x轴上的缩放比例 
double fy=0        -在y轴上的缩放比例 
int interpolation  -插值方式,有以下5种方式 

INTER_NEAREST      -最近邻插值 
INTER_LINEAR       -双线性插值 (默认使用) 
INTER_AREA         -区域插值。 
INTER_CUBIC        -三次样条插值,也叫立方插值(超过4*4像素邻域内的双三次插值)
INTER_LANCZOS4     -Lanczos插值(超过8*8像素邻域的Lanczos插值)

当不输入fx和fy时,函数会自动计算

fx = float(src.shape[1] / dsize[1])
fy = float(src.shape[0] / dsize[0])

python中cv2.resize默认的是INTER_LINEAR官方建议:如果是缩小图片,使用INTER_AREA插值算法看起来是最好的,如果是放大图片,可以选择INTER_CUBIC(慢)或INTER_LINEAR(快但效果还不错)。

官方原文:To shrink an image, it will generally look best with INTER_AREA interpolation, whereas to enlarge an image, it will generally look best with INTER_CUBIC (slow) or INTER_LINEAR (faster but still looks OK).

1. 最近邻插值(INTER_NEAREST)

1.1 原理

最近邻插值,也称为零阶插值。计算原理为,目标图像位置直接采用与它最邻近位置的原始图像的像素点为其赋值

目标图像位置(dst_x, dst_y)最邻近的原始图像位置(src_x, src_y)的计算:src_x = int(dst_x / scale_x)src_y = int(dst_y / scale_y),其中scale_xscale_y分别表示在图像宽度方向和高度方向的缩放比例。

1.2 代码实例

使用一个灰度图实例进行放大缩小

import numpy as np
import cv2

# 生成3*3的灰度图
img = np.array([[1,2,3],[4,5,6],[7,8,9]], dtype=np.uint8)

# 放大一倍
resized_up = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_NEAREST)

# 缩小一倍
resized_down = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_NEAREST)

# 缩小一倍再放大一倍
resized_down_up = cv2.resize(resized_down, None, fx=2, fy=2, interpolation=cv2.INTER_NEAREST)

print(img, resized_up, resized_down, resized_down_up)
(array([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]], dtype=uint8),
 array([[1, 1, 2, 2, 3, 3],
        [1, 1, 2, 2, 3, 3],
        [4, 4, 5, 5, 6, 6],
        [4, 4, 5, 5, 6, 6],
        [7, 7, 8, 8, 9, 9],
        [7, 7, 8, 8, 9, 9]], dtype=uint8),
 array([[1, 3],
        [7, 9]], dtype=uint8)),
array([[1, 1, 3, 3],
       [1, 1, 3, 3],
       [7, 7, 9, 9],
       [7, 7, 9, 9]], dtype=uint8)

由上可知:

  • 当dsize不指定的时候,则由fx和fy计算后四舍五入得到
  • 对同一张图缩小再放大,与原图不会保持一致
1.3 简单的代码复现
  • 官方函数
import cv2

# 读取图像
img = cv2.imread('F:/Datas/kaggle/archive/test/apple/apple.jpg')

# 缩放尺寸
dim = (int(img.shape[1] * 2), int(img.shape[0] * 2))

# 使用最近邻插值缩放图像
resized = cv2.resize(img, dim, fx=2, fy=2, interpolation = cv2.INTER_NEAREST)

# 显示缩放后的图像
cv2.imshow("Original image", img)
cv2.imshow("Resized image", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 将图片写入本地
cv2.imwrite("F:/Datas/kaggle/archive/test/apple/applex2.jpg", resized)
  • 简单的复现
def resizeNearestRGB(src, dsize, fx, fy):
    cols, rows = dsize
    dst = np.zeros((rows, cols, 3), dtype=np.uint8)

    for i in range(rows):
        for j in range(cols):
            x = int(j / fx)
            y = int(i / fy)
            dst[i, j][0] = src[y, x][0]
            dst[i, j][1] = src[y, x][1]
            dst[i, j][2] = src[y, x][2]

    return dst

img = cv2.imread('F:/Datas/kaggle/archive/test/apple/apple.jpg')

dim = (int(img.shape[1] * 2), int(img.shape[0] * 2))
new_image = resizeNearestRGB(img, dim, 2, 2)

cv2.imshow("Original image", img)
cv2.imshow("Resized image", new_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 比较两个矩阵是否相等
if np.array_equal(resized, new_image):
    print("两个矩阵相等")
else:
    print("两个矩阵不相等")
    
OUT: 两个矩阵相等

在这里插入图片描述

1.4 特点

由于是以最近的点作为新的插入点,因此边缘不会出现渐变过渡区域,这也导致缩放后的图像容易出现锯齿的现象

在这里插入图片描述

2. 双线性插值(INTER_LINEAR)(默认值)

2.1 原理

双线性插值,又称双线性内插。其核心思想是在x和y两个方向分别进行线性插值。

1) 将目标图像的位置(dst_x, dst_y)映射到原图P(src_x, src_y)中,但这时取得的是float格式的结果;

src_x = float(dst_x / scale_x)
src_y = float(dst_y / scale_y)

2)得到P点在原图中最邻近的4个点Q11Q12Q21Q22
在这里插入图片描述

3)首先在x方向进行两次线性插值得到R1R2两个点的像素值f(R1)f(R2),然后再在y方向一次线性插值得到最终点P的像素值f(P),将该值赋值给目标图像(dst_x, dst_y)注意此处如果先在y方向插值,再在x方向插值,其结果是一样的

在这里插入图片描述

在这里插入图片描述

2.2 简单的代码复现
  • 官方代码
import cv2

# 读取图像
img = cv2.imread('F:/Datas/kaggle/archive/test/apple/apple.jpg')

# 缩放尺寸
dim = (int(img.shape[1] * 2), int(img.shape[0] * 2))

# 使用最近邻插值缩放图像
resized = cv2.resize(img, dim, fx=2, fy=2, interpolation = cv2.INTER_LINEAR)

# 显示缩放后的图像
cv2.imshow("Original image", img)
cv2.imshow("Resized image", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 将图片写入本地
cv2.imwrite("F:/Datas/kaggle/archive/test/apple/applex2.jpg", resized)
  • 简单的复现
def resizeNearestRGB(src, dsize, fx, fy):
    cols, rows = dsize
    dst = np.zeros((rows, cols, 3), dtype=np.uint8)

    for i in range(rows):
        for j in range(cols):
            x = j / fx
            y = i / fy
            x1, y1 = int(x), int(y)
            x2 = min(x1 + 1, src.shape[1] - 1)
            y2 = min(y1 + 1, src.shape[0] - 1)
            Q11, Q21 = src[y1, x1], src[y1, x2]
            Q12, Q22 = src[y2, x1], src[y2, x2]
            if x2 == x1:
                R1 = Q11
                R2 = Q12
            else:
                R1 = Q11 * (x2 - x)/(x2 - x1) + Q21 * (x - x1)/(x2 - x1)
                R2 = Q12 * (x2 - x)/(x2 - x1) + Q22 * (x - x1)/(x2 - x1)
            if y2 == y1:
                P = R1
            else:
                P = R1 * (y2 - y)/(y2 - y1) + R2 * (y - y1)/(y2 - y1)
            dst[i, j] = P

    return dst


image = cv2.imread('F:/Datas/kaggle/archive/test/apple/apple.jpg')

new_size = (int(image.shape[1] * 2), int(image.shape[0] * 2))
new_image = resizeNearestRGB(image, new_size, 2, 2)

cv2.imshow('new image', new_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

自己复现的代码得到的像素值和opencv中内部实现存在一点偏差,可能opencv内部有进行优化
在这里插入图片描述

双线性内插值算法放大后的图像质量较高,不会出现像素值不连续的情况,然而此算法具有低通滤波器的性能,使高频分量受损,所以可能会使图像轮廓在一定程序上变得模糊。

3. 双三次插值(INTER_CUBIC)

在这里插入图片描述

双立方插值是双线性插值的扩展,又称双三次插值,使用相邻的16(4x4)个像素点的加权之和进行插值,每个像素的权重由基于距离的函数取得。

双立方插值算法比双线性插值能更好地保留细节、增加锐度和清晰度,但是,它可能会导致波纹。

在这里插入图片描述

4. 三种方法的直观对比

三种方法的对比:25(5x5)个拼凑在一起的单位方块,颜色表示函数值,黑点是指定数据被插值的位置。双线性插值得到的图像在正方形边界处会有像素值突变现象。
在这里插入图片描述

参考

图像处理中常见的几种插值方法:最近邻插值、双线性插值、双三次插值(附Pytorch测试代码)

维基百科

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

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

相关文章

分布式限流要注意的问题

本文已收录至我的个人网站:程序员波特,主要记录Java相关技术系列教程,共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源,让想要学习的你,不再迷茫。 为什么需要匀速限流 同学们回想一下在Guava小节里…

在java中为什么重写equals要重写hashcode

为什么重写equals要重写hashcode 在Java中,当我们重写equals方法时,通常也需要重写hashCode方法。这是因为: 一致性:如果两个对象相等(即equals方法返回true),那么它们的哈希码(has…

Oracle AWR报告的生成和解读

Oracle AWR报告的生成和解读 一、AWR报告概念及原理 Oracle10g以后,Oracle提供了一个性能检测的工具:AWR(Automatic Workload Repository 自动工作负载库)这个工具可以自动采集Oracle运行中的负载信息,并生成与性能相…

Python 网络编程之TCP详细讲解

【一】传输层 【1】概念 传输层是OSI五层模型中的第四层,负责在网络中的两个端系统之间提供数据传输服务主要协议包括**TCP(传输控制协议)和UDP(用户数据报协议)** 【2】功能 **端到端通信:**传输层负责…

【点云、图像】学习中 常见的数学知识及其中的关系与python实操[更新中]

文章目录 前言一、平均值、方差、协方差平均值(mean)np.mean()方差(variance)np.var()总体方差 np.var(a, ddof0)无偏样本方差np.var(a, ddof1)有偏样本方差标准差(standard deviation)np.std(a, ddof1)默认…

【原创】docker +宝塔+安装zabbix

Zabbix: Zabbix可以监控各种网络服务、服务器和网络设备,而无需在目标设备上安装客户端。它的强大之处在于自带的Web界面,能够提供实时监控和各种报警功能。方法1: 步骤 创建Docker Compose文件: 首先,你需要创建一个docker-comp…

Elasticsearch Windows部署-ELK技术栈

1、下载Elasticsearch、kibana、logstash 本文不介绍ELK相关原理知识,只记录部署操作过程 下载地址Past Releases of Elastic Stack Software | Elastic 选择同一版本,这里选择是当前最新版本8.11.3 解压放在同目录下,方便后续操作与使用 …

基于Simdroid电子散热模块的电子设备机箱散热设计与优化

一、背景介绍 热设计就是通过合理的散热方式保证良好的热环境,确保电子设备可靠的工作。随着电子技术的迅速发展,电子设备的结构越来越复杂,且越来越趋于小型化,散热问题成为了影响设备可靠性的重要因素。据统计,电子…

三种引入CSS的方式

文章目录 CSS基础知识概述CSS的注释CSS的格式 三种引入CSS的方式内嵌式外链式行内式优先级 CSS基础知识 概述 Cascading Style Sheet 层叠样式表 前端三大基础之一(Html结构 CSS样式 JS动作) 最早由网景公司(Netscape)提出,在1996年受到w…

【51单片机系列】单片机与PC进行串行通信

一、单片机与PC机串行通信的设计 工业现场的测控系统中,常使用单片机进行监测点的数据采集,然后单片机通过串口与PC通信,把采集的数据串行传送到PC机上,再在PC机上进行数据处理。 PC机配置的都是RS-232标准串口,为D型…

1.15io网络

子网掩码 1.由于对于一个网络下面的主机号还是很庞大,为了进一步划分网络,我们可以将主机号再次进行划分为两部分,分别是网段号和主机号 2.此时就引入的子网掩码的概念 3. 在引入子网掩码后,IP 网络号 子网号 主机号 4.子网…

DataX数据同步(全量)

1. DataX简介 1.1 DataX概述 DataX 是阿里巴巴开源的一个异构数据源离线同步工具,致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 源码地址:https://github.com/alibaba/Dat…

第十讲 单片机驱动彩色液晶屏 控制RA8889软件:图像运算

单片机驱动TFT彩色液晶屏系列讲座 目录 第一讲 单片机最小系统STM32F103C6T6通过RA8889驱动彩色液晶屏播放视频 第二讲 单片机最小系统STM32F103C6T6控制RA8889驱动彩色液晶屏硬件框架 第三讲 单片机驱动彩色液晶屏 控制RA8889软件:如何初始化 第四讲 单片机驱动彩色液晶屏 控…

【设计模式之美】重构(三)之解耦方法论:如何通过封装、抽象、模块化、中间层等解耦代码?

文章目录 一. “解耦”概述二. 如何给代码“解耦”?1. 封装与抽象2. 中间层2.1. 引入中间层能**简化模块或类之间的依赖关系**。2.2. 引入中间层可以起到过渡的作用,能够让开发和重构同步进行,不互相干扰。 3. 模块化4. 其他设计思想和原则4.…

[我的Rust库更新]get_local_info 0.2.3

今天收到西安城市开发者社区的文章收录通知,谢谢社区的肯定。 随即发布0.2.3版本,增加峰值算法。 get_local_info是一个获取linux本地信息的Rust三方库,其目标是降低获取本地linux系统信息的难度。支持银河麒麟10、UOS、鸿蒙等国产系统。 项…

力扣hot100 只出现一次的数字 位运算

Problem: 136. 只出现一次的数字 文章目录 思路复杂度Code 思路 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) Code class Solution {public int singleNumber(int[] nums) {int res 0;for(int x : nums)res ^ x;return res;} }

C#编程-使用反射检索元数据

使用反射检索元数据 术语反射通常用来指镜像。如果您站在镜子面前,镜子会反射出您的所有物理属性,如:您的身高、肤色和身体结构。在C#中也一样,反射被用于反射程序有关的所有信息。C#程序可以利用反射获得类在运行时的信息。 反射在运行时获取类型信息的过程中被使用。提…

C技能树-学习笔记(1-2)C语言概述和数据类型

参考:https://edu.csdn.net/skill/c 1、输出 “Hello, World!” 字符串,请选出错误答案。 2、错误的print函数。 for … in …:是python的语法,C语言的写法是for (;😉 3、C标准 没有C19标准。 4、了解C编译管道 …

实战whisper:本地化部署通用语音识别模型

前言 Whisper 是一种通用语音识别模型。它是在大量不同音频数据集上进行训练的,也是一个多任务模型,可以执行多语言语音识别、语音翻译和语言识别。 这里呢,我将给出我的一些代码,来帮助你尽快实现【语音转文字】的服务部署。 以下…

3.3.3 使用集线器的星形拓扑

3.3.3 使用集线器的星形拓扑 集线器的一些特点 3.3.4 以太网的信道利用率 多个站在以太网上同时工作就可能会发生碰撞当发生碰撞时,信道资源实际上是被浪费了。因此,当扣除碰撞所造成的信道损失后,以太网总的信道利用率并不能达到100% 3.…