实现基于最近邻内插和双线性内插的图像缩放C++实现
平时我们写图像处理的代码时,如果需要缩放图片,我们都是直接调用图像库的resize函数来完成图像的缩放。作为一个机器视觉或者图像处理算法的工作者,图像缩放代码的实现应该是必须掌握的。在众多图像缩放算法中,最近邻内插算法和双线性内插算法最为基本和常见,所以这篇文章就说一说如何用c++实现这两种算法下的图像缩放。
最近邻内插
最近邻内插这种算法就是根据原图像和目标图像的尺寸,计算缩放的比例,然后根据缩放比例计算目标像素所依据的原像素,过程中自然会产生小数,这时就采用四舍五入,取与这个点最相近的点,当然向下取整也是可以的。
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace std;
void scale(cv::Mat& input_img, int width, int height);
int main()
{
    cv::Mat img = cv::imread("41.png",0);
    cv::imshow("src", img);
    scale(img, 450, 300);
    return 0;
}
//获取原图相应坐标的像素值
uchar get_scale_value(cv::Mat& input_img, int i, int j)
{
    uchar* p = input_img.ptr<uchar>(i);
    return p[j];
}
void scale(cv::Mat& input_img,int width,int height)
{
    cv::Mat output_img(height, width, CV_8UC1);
    output_img.setTo(0);
    float h_scale_rate = (float)input_img.rows/ height;  //高的比例
    float w_scale_rate = (float)input_img.cols / width;  //宽的比例
    for (int i = 0; i < height; i++)
    {
        uchar* p = output_img.ptr<uchar>(i);
        for (int j = 0; j < width; j++)
        {
            int i_scale = h_scale_rate * i;   //依照高的比例计算原图相应坐标中的x,这里采用的是向下取整,当然四舍五入也可以
            int j_scale = w_scale_rate * j;  //依照宽的比例计算原图相应坐标中的y
            //cout << "i_scale: " << i_scale <<" j_scale: "<< j_scale << endl;
            p[j] = get_scale_value(input_img,i_scale, j_scale);
        }
    }
    cv::imshow("scale", output_img);
    cv::imwrite("result.png", output_img);
    cv::waitKey();
}
原图

缩放图

最近邻内插算法实现的图像缩放的原理很简单,编码起来也容易,缺点就是得到的图像效果不太好。
双线性内插
对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(x,y),当然我们也可以将其表示成整数+小数的形式,即(i+u,j+v),其中i、j均为非负整数,u、v为[0,1)区间的浮点数,则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
双线性内值算法的核心思想就是上面的那个公式,它解释了对于原图不存在的浮点像素(比如<1.5,1.5>)是如何确定其实际值的。其实它是以4个相邻的像素值来共同确定,即<1,1> <2,1> <1,2> <2,2>。谁离<1,1>比较近,谁就对它起的影响比较大,这些都在公式中有所体现,这就是双线性插值的精髓。
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace std;
void bin_linear_scale(cv::Mat& input_img, int width, int height);
int main()
{
    cv::Mat img = cv::imread("41.png", 0);
    cv::imshow("src", img);
    bin_linear_scale(img, 450, 300);
    return 0;
}
//f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
uchar get_scale_value(cv::Mat& input_img, float raw_i, float raw_j)
{
    int i = raw_i;
    int j = raw_j;
    float u = raw_i - i;
    float v = raw_j - j;
    //注意处理边界问题,容易越界
    if (i + 1 >= input_img.rows || j + 1 >= input_img.cols)
    {
        uchar* p = input_img.ptr<uchar>(i);
        return p[j];
    }
    uchar* p = input_img.ptr<uchar>(i);
    uchar x1 = p[j];  //f(i,j)
    uchar x2 = p[j + 1];  //f(i,j+1)
    p = input_img.ptr<uchar>(i+1);
    uchar x3 = p[j];   //(i+1,j)
    uchar x4 = p[j + 1];  //f(i+1,j+1) 
   // printf("%d %d\n", i, j);
    return ((1-u)*(1-v)*x1+(1-u)*v*x2+u*(1-v)*x3+u*v*x4);
}
void bin_linear_scale(cv::Mat& input_img, int width, int height)
{
    cv::Mat output_img(height, width, CV_8UC1);
    output_img.setTo(0);
    float h_scale_rate = (float)input_img.rows / height;
    float w_scale_rate = (float)input_img.cols / width;
    for (int i = 0; i < height; i++)
    {
        uchar* p = output_img.ptr<uchar>(i);
        for (int j = 0; j < width; j++)
        {
            float i_scale = h_scale_rate * i;
            float j_scale = w_scale_rate * j;
            //cout << "i_scale: " << i_scale <<" j_scale: "<< j_scale << endl;
            p[j] = get_scale_value(input_img, i_scale, j_scale);
        }
    }
    cv::imshow("scale", output_img);
    cv::imwrite("result.png", output_img);
    cv::waitKey();
}


实现基于最近邻内插和双线性内插的图像缩放C++实现的更多相关文章
- 基于FPGA的线阵CCD图像测量系统研究——笔记
		
本文是对基于FPGA的线阵CCD图像测量系统研究(作者:高尚)的阅读笔记 第一章绪论 1. 读读看 读了前面的摘要依然没有看懂作者要做什么.接着往下读....终于看到了一个字眼“基于机器视觉的图像测量 ...
 - 基于qml创建最简单的图像处理程序(3)-使用opencv&qml进行图像处理
		
<基于qml创建最简单的图像处理程序>系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面http://www.cnblogs.com/jsxyhelu/p/83 ...
 - 基于qml创建最简单的图像处理程序(2)-使用c++&qml进行图像处理
		
<基于qml创建最简单的图像处理程序>系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面http://www.cnblogs.com/jsxyhelu/p/8 ...
 - 基于qml创建最简单的图像处理程序(1)-基于qml创建界面
		
<基于qml创建最简单的图像处理程序>系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面http://www.cnblogs.com/jsxyhelu/p/83 ...
 - 基于均值坐标(Mean-Value Coordinates)的图像融合算法的优化实现
		
目录 1. 概述 2. 实现 2.1. 原理 2.2. 核心代码 2.3. 第二种优化 3. 结果 1. 概述 我在之前的文章<基于均值坐标(Mean-Value Coordinates)的图像 ...
 - Python图像处理丨基于OpenCV和像素处理的图像灰度化处理
		
摘要:本篇文章讲解图像灰度化处理的知识,结合OpenCV调用cv2.cvtColor()函数实现图像灰度操作,使用像素处理方法对图像进行灰度化处理. 本文分享自华为云社区<[Python图像处理 ...
 - c#数字图像处理(十)图像缩放
		
图像几何变换(缩放.旋转)中的常用的插值算法 在图像几何变换的过程中,常用的插值方法有最邻近插值(近邻取样法).双线性内插值和三次卷积法. 最邻近插值: 这是一种最为简单的插值方法,在图像中最小的单位 ...
 - OpenCV计算机视觉学习(11)——图像空间几何变换(图像缩放,图像旋转,图像翻转,图像平移,仿射变换,镜像变换)
		
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 图像 ...
 - opencv3 图像处理(一)图像缩放( python与c++ 实现)
		
opencv3 图像处理 之 图像缩放( python与c++实现 ) 一. 主要函数介绍 1) 图像大小变换 Resize () 原型: void Resize(const CvArr* src,C ...
 
随机推荐
- Gedit 有用插件介绍
			
刚刚接触Ubuntu,对于高手们用的Vim,本人只能望尘莫及.但是,Ubuntu自带的Gedit让我找到了windows的感觉,而且在添加一些插件后更加喜欢这个工具了. gedit本身带有一些常用插件 ...
 - EF的表左连接方法Include和Join
			
在EF中表连接常用的有Join()和Include(),两者都可以实现两张表的连接,但又有所不同. 例如有个唱片表Album(AlbumId,Name,CreateDate,GenreId),表中含外 ...
 - SQL SERVER 2008自动发送邮件(完整版)
			
这两天都在搞这个东西,从开始的一点不懂,到现在自己可以独立的完成这个功能!在这个过程中,CSDN的好多牛人都给了我很大的帮助,在此表示十二分的感谢!写这篇文章,一是为了巩固一下,二嘛我也很希望我写的这 ...
 - [aaronyang原创] Mssql 一张表3列的sql面试题,看你sql学的怎么样
			
文章已经迁移到:http://www.ayjs.net/post/99.html 文章已经迁移到:http://www.ayjs.net/post/99.html 文章已经迁移到:http://www ...
 - java中基础数据类型的应用
			
1.float 与 double float是单精度类型,占用4个字节的存储空间 double是双精度类型,占用8个字节的存储空间 1)当你不声明的时候,默认小数都用double来表示,所以如果要 ...
 - Gituhb 上一些值得攻读的玩具代码库
			
https://github.com/sindresorhus/globby https://github.com/dylansmith/node-exif-renamer https://githu ...
 - Flowable 的event介绍
			
1 事件分为两种,一种是抛出:当流程执行到这时,抛出一个事件:另一种是捕获:当流程执行到这时,他就会等待一个事件的发生. 一个事件需要有事件定义,否则不会做任何“特殊”的事.对于一个流程实例,一个开始 ...
 - RAID简介[zz]
			
RAID 0 是指磁盘分段(Disk Striping)技术其实现方法为将数据分段,同时写到多个磁盘上.其优点是磁盘可以实现并行的输入和输出,提高磁盘读写速度,但是这种技术无容错性能:RAID 1是指 ...
 - supervisor 安装脚本
			
mkdir /data/tools && cd /data/tools wget --no-check-certificate https://bootstrap.pypa.io/ez ...
 - HBase随机读写
			
HDFS不太适合做大量的随机读应用,但HBASE却特别适合随机的读写 个人理解: 1.数据库一般都会有一层缓存,任何对数据的更改实际上是先更改内存中的数据.然后有异步的守护进程负责将脏页按照一定策略刷 ...