Opencv 插值方法 总结

一、概括

面试的时候问到了一个图,就是如何将一个算子放缩??我第一反应是resize(),但是后来我转念一想,人家问的是插值方式,今天来总结一下

最邻近插值法原理分析及c++实现_最临近插值法-CSDN博客

我们总常用的插值方式,临近插值 、双线性插值、三次样条插值、拉格朗日插值、多项式、区域插值等

下面我们就一步一步的将其概括出来

二、临近插值

最邻近插值法 : 其核心思想是选取离目标点最近的点作为待插入的新值点

如图:其他的Q12 Q22 Q11  Q21都是已知的像素点,要求插入一个点P

从上图可以看出P到 Q12 最近,那么我就直接将P=Q12

计算两份方向上的缩放后的图像

	int dst_cols = round(src.cols * sx);  // 列  ==xint dst_rows = round(src.rows * sy);  // 行==y

有3*3 --》5*5 ,那么我们可以计算P(3,3)

 sx=5/3

那么 new_i=3/sx=round(9/5)=2;

        new_j=3/sy=round(9/5)=2

P(3,3)=src(2,2)=83

 

void NearestInterpolation(cv::Mat& src, cv::Mat& dst, float sx, float sy)
{//放大的因子 x,y 方向可能会不一样的// 放缩之后的图像的大小int dst_cols = round(src.cols * sx);  // 列  ==xint dst_rows = round(src.rows * sy);  // 行==ydst = cv::Mat(dst_rows, dst_cols, src.type());//灰度图像处理if (src.channels() == 1){for (int i = 0; i < dst.rows; i++){for (int j = 0; j < dst.cols; j++){//插值计算,取最近值插入到新的图像中int i_new = round(i / sy);int j_new = round(j / sx);if (i_new > src.rows - 1){i_new = src.rows - 1;}if (j_new > src.cols - 1){j_new = src.cols - 1;}dst.at<uchar>(i, j) = src.at<uchar>(i_new, j_new);}}}//彩色图像处理else {for (int i = 0; i < dst.rows; i++){for (int j = 0; j < dst.cols; j++){int i_new = round(i / sy);int j_new = round(j / sx);if (i_new > src.rows - 1){i_new = src.rows - 1;}if (j_new > src.cols - 1){j_new = src.cols - 1;}//Bdst.at<cv::Vec3b>(i, j)[0] = src.at<cv::Vec3b>(i_new, j_new)[0];//Gdst.at<cv::Vec3b>(i, j)[1] = src.at<cv::Vec3b>(i_new, j_new)[1];//Rdst.at<cv::Vec3b>(i, j)[2] = src.at<cv::Vec3b>(i_new, j_new)[2];}}}
}

优点:简单、计算量小。
缺点:效果不好,图像放大后失真现象严重。

 

三、线性插值 

resize() 函数默认的就是双线性插值,

我们先看线性插值:

线性插值:


然后我们将上面的做个变性,就写成了如下:

 双线性插值原理

顾名思义就是做两次线性插值,但是其实是3次

c++ opencv图像双线性插值的应用方法 - 知乎

案例:

 算法流程:

1、先通过每个方向的缩放因子,计算出我们缩放后的图像的大小

2、计算通过新图像的row_new 和col_new 推算出原图像中的四个点 的位置并获得四个点的灰度值

3、通过上面拿到的公式来计算新插入的值

4、计算边界的特殊值


/// <summary>
/// 双线性插值处理
/// </summary>
/// <param name="src"></param>
/// <param name="scale_x"></param>
/// <param name="scale_y"></param>
/// <param name="dst"></param>
void DoubleLineInterpolate(Mat src, double scale_x,double scale_y, Mat& dst)
{int result_H = static_cast<int>(src.rows * scale_y);int result_W = static_cast<int>(src.cols * scale_x);dst = Mat::zeros(cv::Size(result_W, result_H), src.type());for (int i = 0; i < dst.rows; i++){for (int j = 0; j < dst.cols; j++){// 非常重要的一步就是用新的图像来推算出原来图像的四个像素的位置和灰度值double before_x = double(j + 0.5) / scale_x - 0.5f;double before_y = double(i + 0.5) / scale_y - 0.5;int top_y = static_cast<int>(before_y);int bottom_y = top_y + 1;int left_x = static_cast<int>(before_x);int right_x = left_x + 1;//计算变换前坐标的小数部分double u = before_x - left_x;double v = before_y - top_y;// 如果计算的原始图像的像素大于真实原始图像尺寸if ((top_y >= src.rows - 1) && (left_x >= src.cols - 1)){//右下角dst.at<uchar>(i, j) = (1. - u) * (1. - v) * src.at<uchar>(top_y, left_x);}else if (top_y >= src.rows - 1){//最后一行dst.at<uchar>(i, j)= (1. - u) * (1. - v) * src.at<uchar>(top_y, left_x)+ (1. - v) * u * src.at<uchar>(top_y, right_x);}else if (left_x >= src.cols - 1){dst.at<uchar>(i, j)= (1. - u) * (1. - v) * src.at<uchar>(top_y, left_x)+ (v) * (1. - u) * src.at<uchar>(bottom_y, left_x);}else{dst.at<uchar>(i, j)= (1. - u) * (1. - v) * src.at<uchar>(top_y, left_x)+ (1. - v) * (u)*src.at<uchar>(top_y, right_x)+ (v) * (1. - u) * src.at<uchar>(bottom_y, left_x)+ (u) * (v)*src.at<uchar>(bottom_y, right_x);}}}  
}

 

 

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

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

相关文章

836. 合并集合(acwing)

文章目录 836. 合并集合题目描述并查集acwing并查集模板 836. 合并集合 题目描述 一共有 n 个数&#xff0c;编号是 1∼n&#xff0c;最开始每个数各自在一个集合中。 现在要进行 m 个操作&#xff0c;操作共有两种&#xff1a; M a b&#xff0c;将编号为 a 和 b 的两个数…

Python与C++的对比——跟老吕学Python编程

Python与C的对比——跟老吕学Python编程 Python与C的对比1.C编译型 vs Python解释型2.执行效率3.开发效率4.跨平台5.可移植性6.内存管理机制7.易学性8.静态类型 vs 动态类型9.面向对象编程概念10.垃圾回收11.应用领域 Python与C的对比表 Python与C的对比 Python和C都是最受欢迎…

数据结构小记【Python/C++版】——散列表篇

一&#xff0c;基础概念 散列表&#xff0c;英文名是hash table&#xff0c;又叫哈希表。 散列表通常使用顺序表来存储集合元素&#xff0c;集合元素以一种很分散的分布方式存储在顺序表中。 散列表是一个键值对(key-item)的组合&#xff0c;由键(key)和元素值(item)组成。键…

解密阿里巴巴面试题:如何设计一个微博?

亲爱的小米科技粉丝们,大家好呀!今天小米带来了一则热门话题——阿里巴巴面试题:如何设计一个微博?别着急,跟着小米一起来揭秘吧! 实现哪些功能? 在设计微博系统时,需要考虑实现哪些功能才能满足用户的需求。除了基本的发布推文、时间线、新闻推送、关注/不允许用户以…

编程训练基础代码六

1、定义一个方法&#xff0c;该方法能够找出两个小数中的较小值并返回。 public class SmallerValue {public static void main(String[] args) {Scanner sc new Scanner(System.in);System.out.println("请输入两个整数: ");int asc.nextInt();int bsc.nextInt();…

算法 -【找出字符串的可整除数组】

找出字符串的可整除数组 题目示例1示例2 分析代码 题目 给你一个下标从 0 开始的字符串 word &#xff0c;长度为 n &#xff0c;由从 0 到 9 的数字组成。另给你一个正整数 m 。word 的可整除数组 div 是一个长度为 n 的整数数组&#xff0c;并满足&#xff1a; 如果 word[0…

【JavaScript 漫游】【034】AJAX

文章简介 本篇文章为【JavaScript 漫游】专栏的第 034 篇文章&#xff0c;对浏览器模型的 XMLHttpRequest 对象&#xff08;AJAX&#xff09;的知识点进行了总结。 XMLHttpRequest 对象概述 浏览器与服务器之间&#xff0c;采用 HTTP 协议通信。用户在浏览器地址栏键入一个网…

Java项目源码基于springboot的家政服务平台的设计与实现

大家好我是程序员阿存&#xff0c;在java圈的辛苦码农。辛辛苦苦板砖&#xff0c;今天要和大家聊的是一款Java项目源码基于springboot的家政服务平台的设计与实现&#xff0c;项目源码以及部署相关请联系存哥&#xff0c;文末附上联系信息 。 项目源码&#xff1a;Java基于spr…

虚拟机镜像iso下载

MSDN, 我告诉你 - 做一个安静的工具站 (itellyou.cn)

CANalyzer使用_00 概述

计划写一个专题&#xff0c;该专题主要介绍CANalyzer的使用&#xff0c;每次文档计划写一个点&#xff0c;自己不累&#xff0c;别人看着也不累&#xff0c;并且方便拓展。本文作为专题的开篇主要介绍下CANalyzer软件的背景&#xff0c;软件界面等信息。 1 软件介绍 CANalyze…

FastAPI 学习笔记

FastAPI 学习笔记 0. 引言1. 快速开始2. 升级示例代码 0. 引言 在 Python 这个充满活力的生态系统中&#xff0c;FastAPI 应运而生&#xff0c;它是一个现代的、快速的 Web 框架&#xff0c;专注于构建 RESTful API。 无论你是一名有经验的 Python 开发人员&#xff0c;还是一…

MyBatis注解开发详解

MyBatis注解开发详解 一、前言 MyBatis是一个优秀的持久层框架&#xff0c;它支持定制化SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解来配置和映射原始类型、接口和Java POJO&#xff08;Plain…

HTTP/2、HTTP/3对HTTP/1.1的性能改进和优化

HTTP/1.1 相比 HTTP/1.0 提高了什么性能&#xff1f; 性能上的改进&#xff1a; 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。 支持管道&#xff08;pipeline&#xff09;网络传输&#xff0c;只要第一个请求发出去了&#xff0c;不必等其回来&#xff0c;就可以…

Purple Pi OH鸿蒙开发板7天入门OpenHarmony开源鸿蒙教程【五】

在完成了Purple Pi OH大部分的接口测试之后&#xff0c;紧接着就是一个充满挑战的任务——利用SDK来编译生成我们自己的镜像文件。通过这一过程&#xff0c;不仅能够让你获得一个可在真实硬件上运行的系统镜像&#xff0c;更重要的是&#xff0c;它让你对OpenHarmony系统的构建…

C++中的内存管理方式

一、C内存管理方式简介 C语言中的内存管理方式在C中可以继续使用&#xff0c;但是在有些地方就无能为力&#xff0c;而且使用起来比较麻烦。因此C中引入了自己的内存管理方式&#xff0c;通过new和delete操作符进行动态内存管理。 二、new语法 new可以申请1个或多个空间&…

Android自定义binder实现进程间通信

通过binder建立进程间通信&#xff0c;主要分为两步&#xff1a; 1. 定义一个binder的服务&#xff08;在androidManifest.xml中声明&#xff09;接受远端请求。 服务中创建一个binder实例&#xff0c; 在接收到客户端的连接时&#xff0c;向请求方返回回binder的引用。重写Bi…

Qt - 信号和槽

目录 一、信号 二、槽 三、信号和槽的使用 (一) 连接信号和槽 (二) 自定义槽 (三) 通过 Qt Creator生成信号槽代码 (四) 自定义信号 四、带参数的信号和槽 五、信号与槽的断开 六、Qt4版本信号与槽的连接 (一) Qt4版本信号与槽连接的优缺点 一、信号 在 Qt 中&…

【简单模拟】第十二届蓝桥杯省赛第二场C++ B组《特殊年份》(C++)

【题目描述】 今年是 2021 年&#xff0c;2021 这个数字非常特殊&#xff0c;它的千位和十位相等&#xff0c;个位比百位大 1&#xff0c;我们称满足这样条件的年份为特殊年份。 输入 5 个年份&#xff0c;请计算这里面有多少个特殊年份。 【输入格式】 输入 5 行&#xff…

​Ubuntu20.04 创建新的用户​

1、了解Linux目录结构 推荐看一下&#xff1a;https://www.runoob.com/linux/linux-system-contents.html Linux支持多个用户进行操作的&#xff0c;这样提高了系统的安全性&#xff0c;也可以多人共用一个系统&#xff0c;不过要注意的是系统中安装的软件相关路径&#xff0…

CubeMX使用教程(5)——定时器PWM输出

本篇我们将利用CubeMX产生频率固定、占空比可调的两路PWM信号输出 例如PA6引脚输出100Hz的PWM&#xff1b;PA7引脚输出500Hz的PWM&#xff0c;双路同时输出 我们还是利用上一章定时器中断的工程进行学习&#xff0c;这样比较方便 首先打开CubeMX对PA6、PA7进行GPIO配置 注&a…