iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++OpenCV实现图像双三次插值算法详解
  • 722
分享到

C++OpenCV实现图像双三次插值算法详解

2024-04-02 19:04:59 722人浏览 泡泡鱼
摘要

目录前言一、图像双三次插值算法原理二、c++ OpenCV代码1.计算权重矩阵2.遍历插值3. 测试及结果前言 近期在学习一些传统的图像处理算法,比如传统的图像插值算法等。传统的图像

前言

近期在学习一些传统的图像处理算法,比如传统的图像插值算法等。传统的图像插值算法包括邻近插值法、双线性插值法和双三次插值法,其中邻近插值法和双线性插值法在网上都有很详细的介绍以及用c++编写的代码。但是,网上关于双三次插值法的原理介绍虽然很多,也有对应的代码,但是大多都不是很详细。因此基于自己对原理的理解,自己编写了图像双三次插值算法的c++ opencv代码,在这里记录一下。

一、图像双三次插值算法原理

首先是原理部分。图像双三次插值的原理,就是目标图像的每一个像素都是由原图上相对应点周围的4x4=16个像素经过加权之后再相加得到的。这里的加权用到的就是三次函数,这也是图像双三次插值算法名称的由来(个人猜测)。用到的三次函数如下图所示:

最关键的问题是,这个三次函数的输入和输出分别代表啥。简单来说输入就是原图对应点周围相对于这点的4x4大小区域的坐标值,大小在0~2之间,输出就是这些点横坐标或者纵坐标的权重。4个横坐标、4个纵坐标,对应相乘就是4x4大小的权重矩阵,然后使用此权重矩阵对原图相对应的区域进行相乘并相加就可以得到目标图点的像素。

下图可以帮助大家更好地理解

首先,u和v是什么呢?举一个例子,对于一幅100x100的灰度图像,要将其放大到500x500,那么其缩放因子sx=500/100=5,sy=500/100=5。现在目标图像是500x500,需要用原图的100x100个像素值来填满这500x500个空,根据src_x=i/sx和src_y=j/sy可以得到目标像素坐标(i,j)所对应的原图像素坐标(src_x, src_y),这个src_x和src_y的小数部分就是上图中的u和v。

理解了u和v,就可以利用u和v来计算双三次插值算法的权重了。上面说了三次函数的输入是原图对应点周围相对于这点的4x4大小区域的坐标值,对于上面这幅图而言,横坐标有四个输入,分别是1+u,u,1-u,2-u;纵坐标也有四个输入,分别是1+v,v,1-v,2-v,根据三次函数算出权重之后两两相乘就是对应的4x4大小的权重矩阵。

知道了怎么求权重矩阵之后,就可以遍历整幅图像进行插值了。下面是基于自己对原理的理解编写的c++ opencv代码,代码没有做优化,但是能够让大家直观地理解图像双三次插值算法。

二、C++ OpenCV代码

1.计算权重矩阵

前面说了权重矩阵就是横坐标的4个输出和纵坐标的4个输出相乘,因此只需要求出横坐标和纵坐标相对应的8个输出值就行了。

代码如下:


std::vector<double> getWeight(double c, double a = 0.5)
{
	//c就是u和v,横坐标和纵坐标的输出计算方式一样
	std::vector<double> temp(4);
	temp[0] = 1 + c; temp[1] = c; 
	temp[2] = 1 - c; temp[3] = 2 - c;
	
	//y(x) = (a+2)|x|*|x|*|x| - (a+3)|x|*|x| + 1   |x|<=1
	//y(x) = a|x|*|x|*|x| - 5a|x|*|x| + 8a|x| - 4a  1<|x|<2
	std::vector<double> weight(4);
	weight[0] = (a * pow(abs(temp[0]), 3) - 5 * a * pow(abs(temp[0]), 2) + 8 * a * abs(temp[0]) - 4 * a);
	weight[1] = (a + 2) * pow(abs(temp[1]), 3) - (a + 3) * pow(abs(temp[1]), 2) + 1;
	weight[2] = (a + 2) * pow(abs(temp[2]), 3) - (a + 3) * pow(abs(temp[2]), 2) + 1;
	weight[3] = (a * pow(abs(temp[3]), 3) - 5 * a * pow(abs(temp[3]), 2) + 8 * a * abs(temp[3]) - 4 * a);

	return weight;
}

2.遍历插值

代码如下:


void bicubic(cv::Mat& src, cv::Mat& dst, int dst_rows, int dst_cols)
{
	dst.create(dst_rows, dst_cols, src.type());
	double sy = static_cast<double>(dst_rows) / static_cast<double>(src.rows);
	double sx = static_cast<double>(dst_cols) / static_cast<double>(src.cols);
	cv::Mat border;
	cv::copyMakeBorder(src, border, 1, 1, 1, 1, cv::BORDER_REFLECT_101);

	//处理灰度图
	if (src.channels() == 1)
	{
		for (int i = 1; i < dst_rows + 1; ++i)
		{
			int src_y = (i + 0.5) / sy - 0.5; //做了几何中心对齐
			if (src_y < 0) src_y = 0;
			if (src_y > src.rows - 1) src_y = src.rows - 1;
			src_y += 1;
			//目标图像点坐标对应原图点坐标的4个纵坐标
			int i1 = std::floor(src_y);
			int i2 = std::ceil(src_y);
			int i0 = i1 - 1;
			int i3 = i2 + 1;
			double u = src_y - static_cast<int64>(i1);
			std::vector<double> weight_x = getWeight(u);

			for (int j = 1; j < dst_cols + 1; ++j)
			{
				int src_x = (j + 0.5) / sy - 0.5;
				if (src_x < 0) src_x = 0;
				if (src_x > src.rows - 1) src_x = src.rows - 1;
				src_x += 1;
				//目标图像点坐标对应原图点坐标的4个横坐标
				int j1 = std::floor(src_x);
				int j2 = std::ceil(src_x);
				int j0 = j1 - 1;
				int j3 = j2 + 1;
				double v = src_x - static_cast<int64>(j1);
				std::vector<double> weight_y = getWeight(v);

				//目标点像素对应原图点像素周围4x4区域的加权计算(插值)
				double pix = weight_x[0] * weight_y[0] * border.at<uchar>(i0, j0) + weight_x[1] * weight_y[0] * border.at<uchar>(i0, j1)
					+ weight_x[2] * weight_y[0] * border.at<uchar>(i0, j2) + weight_x[3] * weight_y[0] * border.at<uchar>(i0, j3)
					+ weight_x[0] * weight_y[1] * border.at<uchar>(i1, j0) + weight_x[1] * weight_y[1] * border.at<uchar>(i1, j1)
					+ weight_x[2] * weight_y[1] * border.at<uchar>(i1, j2) + weight_x[3] * weight_y[1] * border.at<uchar>(i1, j3)
					+ weight_x[0] * weight_y[2] * border.at<uchar>(i2, j0) + weight_x[1] * weight_y[2] * border.at<uchar>(i2, j1)
					+ weight_x[2] * weight_y[2] * border.at<uchar>(i2, j2) + weight_x[3] * weight_y[2] * border.at<uchar>(i2, j3)
					+ weight_x[0] * weight_y[3] * border.at<uchar>(i3, j0) + weight_x[1] * weight_y[3] * border.at<uchar>(i3, j1)
					+ weight_x[2] * weight_y[3] * border.at<uchar>(i3, j2) + weight_x[3] * weight_y[3] * border.at<uchar>(i3, j3);
				if (pix < 0) pix = 0;
				if (pix > 255)pix = 255;

				dst.at<uchar>(i - 1, j - 1) = static_cast<uchar>(pix);
			}
		}
	}
	//处理彩色图像
	else if (src.channels() == 3)
	{
		for (int i = 1; i < dst_rows + 1; ++i)
		{
			int src_y = (i + 0.5) / sy - 0.5;
			if (src_y < 0) src_y = 0;
			if (src_y > src.rows - 1) src_y = src.rows - 1;
			src_y += 1;
			int i1 = std::floor(src_y);
			int i2 = std::ceil(src_y);
			int i0 = i1 - 1;
			int i3 = i2 + 1;
			double u = src_y - static_cast<int64>(i1);
			std::vector<double> weight_y = getWeight(u);

			for (int j = 1; j < dst_cols + 1; ++j)
			{
				int src_x = (j + 0.5) / sy - 0.5;
				if (src_x < 0) src_x = 0;
				if (src_x > src.rows - 1) src_x = src.rows - 1;
				src_x += 1;
				int j1 = std::floor(src_x);
				int j2 = std::ceil(src_x);
				int j0 = j1 - 1;
				int j3 = j2 + 1;
				double v = src_x - static_cast<int64>(j1);
				std::vector<double> weight_x = getWeight(v);

				cv::Vec3b pix;

				pix[0] = weight_x[0] * weight_y[0] * border.at<cv::Vec3b>(i0, j0)[0] + weight_x[1] * weight_y[0] * border.at<cv::Vec3b>(i0, j1)[0]
					+ weight_x[2] * weight_y[0] * border.at<cv::Vec3b>(i0, j2)[0] + weight_x[3] * weight_y[0] * border.at<cv::Vec3b>(i0, j3)[0]
					+ weight_x[0] * weight_y[1] * border.at<cv::Vec3b>(i1, j0)[0] + weight_x[1] * weight_y[1] * border.at<cv::Vec3b>(i1, j1)[0]
					+ weight_x[2] * weight_y[1] * border.at<cv::Vec3b>(i1, j2)[0] + weight_x[3] * weight_y[1] * border.at<cv::Vec3b>(i1, j3)[0]
					+ weight_x[0] * weight_y[2] * border.at<cv::Vec3b>(i2, j0)[0] + weight_x[1] * weight_y[2] * border.at<cv::Vec3b>(i2, j1)[0]
					+ weight_x[2] * weight_y[2] * border.at<cv::Vec3b>(i2, j2)[0] + weight_x[3] * weight_y[2] * border.at<cv::Vec3b>(i2, j3)[0]
					+ weight_x[0] * weight_y[3] * border.at<cv::Vec3b>(i3, j0)[0] + weight_x[1] * weight_y[3] * border.at<cv::Vec3b>(i3, j1)[0]
					+ weight_x[2] * weight_y[3] * border.at<cv::Vec3b>(i3, j2)[0] + weight_x[3] * weight_y[3] * border.at<cv::Vec3b>(i3, j3)[0];
				pix[1] = weight_x[0] * weight_y[0] * border.at<cv::Vec3b>(i0, j0)[1] + weight_x[1] * weight_y[0] * border.at<cv::Vec3b>(i0, j1)[1]
					+ weight_x[2] * weight_y[0] * border.at<cv::Vec3b>(i0, j2)[1] + weight_x[3] * weight_y[0] * border.at<cv::Vec3b>(i0, j3)[1]
					+ weight_x[0] * weight_y[1] * border.at<cv::Vec3b>(i1, j0)[1] + weight_x[1] * weight_y[1] * border.at<cv::Vec3b>(i1, j1)[1]
					+ weight_x[2] * weight_y[1] * border.at<cv::Vec3b>(i1, j2)[1] + weight_x[3] * weight_y[1] * border.at<cv::Vec3b>(i1, j3)[1]
					+ weight_x[0] * weight_y[2] * border.at<cv::Vec3b>(i2, j0)[1] + weight_x[1] * weight_y[2] * border.at<cv::Vec3b>(i2, j1)[1]
					+ weight_x[2] * weight_y[2] * border.at<cv::Vec3b>(i2, j2)[1] + weight_x[3] * weight_y[2] * border.at<cv::Vec3b>(i2, j3)[1]
					+ weight_x[0] * weight_y[3] * border.at<cv::Vec3b>(i3, j0)[1] + weight_x[1] * weight_y[3] * border.at<cv::Vec3b>(i3, j1)[1]
					+ weight_x[2] * weight_y[3] * border.at<cv::Vec3b>(i3, j2)[1] + weight_x[3] * weight_y[3] * border.at<cv::Vec3b>(i3, j3)[1];
				pix[2] = weight_x[0] * weight_y[0] * border.at<cv::Vec3b>(i0, j0)[2] + weight_x[1] * weight_y[0] * border.at<cv::Vec3b>(i0, j1)[2]
					+ weight_x[2] * weight_y[0] * border.at<cv::Vec3b>(i0, j2)[2] + weight_x[3] * weight_y[0] * border.at<cv::Vec3b>(i0, j3)[2]
					+ weight_x[0] * weight_y[1] * border.at<cv::Vec3b>(i1, j0)[2] + weight_x[1] * weight_y[1] * border.at<cv::Vec3b>(i1, j1)[2]
					+ weight_x[2] * weight_y[1] * border.at<cv::Vec3b>(i1, j2)[2] + weight_x[3] * weight_y[1] * border.at<cv::Vec3b>(i1, j3)[2]
					+ weight_x[0] * weight_y[2] * border.at<cv::Vec3b>(i2, j0)[2] + weight_x[1] * weight_y[2] * border.at<cv::Vec3b>(i2, j1)[2]
					+ weight_x[2] * weight_y[2] * border.at<cv::Vec3b>(i2, j2)[2] + weight_x[3] * weight_y[2] * border.at<cv::Vec3b>(i2, j3)[2]
					+ weight_x[0] * weight_y[3] * border.at<cv::Vec3b>(i3, j0)[2] + weight_x[1] * weight_y[3] * border.at<cv::Vec3b>(i3, j1)[2]
					+ weight_x[2] * weight_y[3] * border.at<cv::Vec3b>(i3, j2)[2] + weight_x[3] * weight_y[3] * border.at<cv::Vec3b>(i3, j3)[2];

				for (int i = 0; i < src.channels(); ++i)
				{
					if (pix[i] < 0) pix = 0;
					if (pix[i] > 255)pix = 255;
				}
				dst.at<cv::Vec3b>(i - 1, j - 1) = static_cast<cv::Vec3b>(pix);
			}
		}	
	}	
}

3. 测试及结果


int main()
{
	cv::Mat src = cv::imread("C:\\Users\\Echo\\Pictures\\Saved Pictures\\bilateral.png");
	cv::Mat dst;
	bicubic(src, dst, 309/0.5, 338/0.5);
	cv::imshow("gray", dst);
	cv::imshow("src", src);
	cv::waiTKEy(0);
}

彩色图像(放大两倍)

以上就是C++ OpenCV实现图像双三次插值算法详解的详细内容,更多关于C++ OpenCV 图像双三次插值算法的资料请关注编程网其它相关文章!

--结束END--

本文标题: C++OpenCV实现图像双三次插值算法详解

本文链接: https://www.lsjlt.com/news/159023.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++OpenCV实现图像双三次插值算法详解
    目录前言一、图像双三次插值算法原理二、C++ OpenCV代码1.计算权重矩阵2.遍历插值3. 测试及结果前言 近期在学习一些传统的图像处理算法,比如传统的图像插值算法等。传统的图像...
    99+
    2024-04-02
  • C++ OpenCV如何实现图像双三次插值算法
    本篇内容主要讲解“C++ OpenCV如何实现图像双三次插值算法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++ OpenCV如何实现图像双三次插值算法”吧!一、图像双三...
    99+
    2023-06-21
  • 详解Python+OpenCV实现图像二值化
    目录一、图像二值化1.效果2.源码二、图像二值化(调节阈值)1.源码一2.源码二一、图像二值化 1.效果 2.源码 import cv2 import numpy as np im...
    99+
    2024-04-02
  • OpenCV实现图像去噪算法的步骤详解
    目录一、函数参考1、Primal-dual算法2、非局部均值去噪算法三、OpenCV源码1、源码路径2、源码代码四、效果图像示例一、函数参考 1、Primal-dual算法 Prim...
    99+
    2024-04-02
  • Python实现RGB等图片的图像插值算法
    目录前言RGB彩色图像和数组理解图片坐标对其左对齐中心对齐临近插值算法线性插值法双线性插值三种插值算法的综合使用附件前言 问题:我们在放大图片的过程中,放大的目标图像和原图图像之间会...
    99+
    2024-04-02
  • OpenCV实现图像细化算法
    目录1.基础概念2.细化过程3.代码实现4.实验结果1.基础概念 图像细化(Image Thinning),一般指二值图像的骨架化(Image Skeletonization)的一种...
    99+
    2022-11-13
    OpenCV 图像细化
  • Python怎么实现RGB等图片的图像插值算法
    这篇文章主要介绍“Python怎么实现RGB等图片的图像插值算法”,在日常操作中,相信很多人在Python怎么实现RGB等图片的图像插值算法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python怎么实现R...
    99+
    2023-06-21
  • 基于Python实现二维图像双线性插值
    目录插值简介最近邻法 (Nearest Interpolation)双三次插值 (Bicubic interpolation)双线性插值 (Bilinear Interpolatio...
    99+
    2024-04-02
  • 详解C++ OpenCV实现图像拼接的原理及方法
    目录前言一、图像拼接相关原理 图像特征采集特征提取算法透视变换透视矩阵图像拷贝二、案例实现Step1:导入目标图片Step2:特征点提取和匹配 Step3:图像配...
    99+
    2024-04-02
  • OpenCV图像算法实现图像切分图像合并示例
    目录将一张图片切分成多个小图片并将小图片合并为原图图像切分图像合并验证友情提示将一张图片切分成多个小图片并将小图片合并为原图 最近用到一个功能,需要将一张原图切分成多个小图像,然后对...
    99+
    2024-04-02
  • OpenCV图像算法怎么实现图像切分图像合并
    本篇内容介绍了“OpenCV图像算法怎么实现图像切分图像合并”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!将一张图片切分成多个小图片并将小图...
    99+
    2023-06-30
  • C++OpenCV单峰三角阈值法Thresh_Unimodal详解
    目录需求说明具体流程功能函数C++测试代码测试效果需求说明 在对图像进行处理时,经常会有这类需求:想通过阈值对图像进行二值化分割,以提取自己感兴趣的区域,常见的阈值分割方法有常数分割...
    99+
    2024-04-02
  • C++中实现OpenCV图像分割与分水岭算法
    分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水...
    99+
    2024-04-02
  • OpenCV如何实现图像去噪算法
    今天小编给大家分享一下OpenCV如何实现图像去噪算法的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、函数参考1、Prim...
    99+
    2023-07-02
  • OpenCV图像分割之分水岭算法与图像金字塔算法详解
    目录前言一、使用分水岭算法分割图像1、cv2.distanceTransform()函数2、cv2.connectedComponents()函数3、cv2.watershed()函...
    99+
    2024-04-02
  • 基于Python如何实现二维图像双线性插值
    本篇内容主要讲解“基于Python如何实现二维图像双线性插值”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“基于Python如何实现二维图像双线性插值”吧!在对二维数据进行 resize / ma...
    99+
    2023-07-02
  • OpenCV图像缩放resize各种插值方式的比较实现
    1. resize函数说明     OpenCV提供了resize函数来改变图像的大小,函数原型如下: void resize(InputArray src,...
    99+
    2024-04-02
  • C++中怎么实现OpenCV图像分割与分水岭算法
    小编给大家分享一下C++中怎么实现OpenCV图像分割与分水岭算法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!分水岭算法是一种图像区域分割法,在分割的过程中,它...
    99+
    2023-06-15
  • Python+Opencv实现图像模板匹配详解
    目录引言一、匹配方法 二、匹配单个对象 三、匹配多个对象引言 什么是模板匹配呢? 看到这里大家是否会觉得很熟悉的感觉涌上心头!在人脸识别是不是也会看见&...
    99+
    2024-04-02
  • 详解PythonOpenCV图像分割算法的实现
    目录前言1.图像二值化2.自适应阈值分割算法3.Otsu阈值分割算法4.基于轮廓的字符分离4.1轮廓检测 4.2轮廓绘制4.3包围框获取4.4矩形绘制 前言 图像...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作