精华内容
下载资源
问答
  • 双线性插值算法c++

    2018-02-25 16:38:30
    图像处理算法中的双线性插值算法的纯c++实现, 希望能给大家提供一些思路。
  • 能实现图像压缩代码简单易懂,适合新手入门学习
  • 双线性插值算法

    2018-05-21 17:54:33
    双线性插值算法的C语言实现方式,双线性插值算法的C语言实现方式 可以参考一下。
  • 双线性插值法原理: ① 何为线性插值? 插值就是在两个数之间插入一个数,线性插值原理图如下: 在位置 x 进行线性插值,插入的值为f(x) ↑ ② 各种插值法: 插值法的第一步都是相同的,计算目标图...

    码字不易,如果此文对你有所帮助,请帮忙点赞、评论,感谢!

    一. 双线性插值法原理:

            ① 何为线性插值?

            插值就是在两个数之间插入一个数,线性插值原理图如下:

    在位置 x 进行线性插值,插入的值为f(x) ↑

            ② 各种插值法:

            插值法的第一步都是相同的,计算目标图(dstImage)的坐标点对应原图(srcImage)中哪个坐标点来填充,计算公式为:

            srcX = dstX * (srcWidth/dstWidth)

            srcY = dstY * (srcHeight/dstHeight)

            (dstX,dstY)表示目标图像的某个坐标点,(srcX,srcY)表示与之对应的原图像的坐标点。srcWidth/dstWidth 和 srcHeight/dstHeight 分别表示宽和高的放缩比。

            那么问题来了,通过这个公式算出来的 srcX, scrY 有可能是小数,但是原图像坐标点是不存在小数的,都是整数,得想办法把它转换成整数才行。

            不同插值法的区别就体现在 srcX, scrY 是小数时,怎么将其变成整数去取原图像中的像素值。

            最近邻插值(Nearest-neighborInterpolation):看名字就很直白,四舍五入选取最接近的整数。这样的做法会导致像素变化不连续,在目标图像中产生锯齿边缘。

            双线性插值(Bilinear Interpolation):双线性就是利用与坐标轴平行的两条直线去把小数坐标分解到相邻的四个整数坐标点。权重与距离成反比。

            双三次插值(Bicubic Interpolation):与双线性插值类似,只不过用了相邻的16个点。但是需要注意的是,前面两种方法能保证两个方向的坐标权重和为1,但是双三次插值不能保证这点,所以可能出现像素值越界的情况,需要截断。

            ③ 双线性插值算法原理

    双线性插值算法原理图,将P的小数坐标变成 Q11、Q12、Q21、Q22 4个整数坐标内容的加权和 ↑

            假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。最常见的情况,f就是一个像素点的像素值。首先在 x 方向进行线性插值,然后再在 y 方向上进行线性插值,最终得到双线性插值的结果。

    x 方向上线性插值算法 ↑

    y 方向上线性插值算法 ↑

    双线性插值算法 ↑

        ④ 举例说明

    如果选择一个坐标系统使得 f 的四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么双线性插值公式就可以化简为上式 ↑

    矩阵表示为 ↑

    可以看到,与这种插值方法名称不同的是,这种插值方法的结果通常不是线性的,它的形式是  ↑


    二. python实现灰度图像双线性插值算法:

    灰度图像双线性插值放大缩小

    import numpy as np
    import math
    import cv2
    
    def double_linear(input_signal, zoom_multiples):
        '''
        双线性插值
        :param input_signal: 输入图像
        :param zoom_multiples: 放大倍数
        :return: 双线性插值后的图像
        '''
        input_signal_cp = np.copy(input_signal)   # 输入图像的副本
    
        input_row, input_col = input_signal_cp.shape # 输入图像的尺寸(行、列)
    
        # 输出图像的尺寸
        output_row = int(input_row * zoom_multiples)
        output_col = int(input_col * zoom_multiples)
    
        output_signal = np.zeros((output_row, output_col)) # 输出图片
    
        for i in range(output_row):
            for j in range(output_col):
                # 输出图片中坐标 (i,j)对应至输入图片中的最近的四个点点(x1,y1)(x2, y2),(x3, y3),(x4,y4)的均值
                temp_x = i / output_row * input_row
                temp_y = j / output_col * input_col
    
                x1 = int(temp_x)
                y1 = int(temp_y)
    
                x2 = x1
                y2 = y1 + 1
    
                x3 = x1 + 1
                y3 = y1
    
                x4 = x1 + 1
                y4 = y1 + 1
    
                u = temp_x - x1
                v = temp_y - y1
    
                # 防止越界
                if x4 >= input_row:
                    x4 = input_row - 1
                    x2 = x4
                    x1 = x4 - 1
                    x3 = x4 - 1
                if y4 >= input_col:
                    y4 = input_col - 1
                    y3 = y4
                    y1 = y4 - 1
                    y2 = y4 - 1
    
                # 插值
                output_signal[i, j] = (1-u)*(1-v)*int(input_signal_cp[x1, y1]) + (1-u)*v*int(input_signal_cp[x2, y2]) + u*(1-v)*int(input_signal_cp[x3, y3]) + u*v*int(input_signal_cp[x4, y4])
        return output_signal
    
    # Read image
    img = cv2.imread("../paojie_g.jpg",0).astype(np.float)
    out = double_linear(img,2).astype(np.uint8)
    # Save result
    cv2.imshow("result", out)
    cv2.imwrite("out.jpg", out)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    三. 灰度图像双线性插值实验结果:

    原图 ↑

    放大2倍后图像 ↑


    四. 彩色图像双线性插值python实现

    from PIL import Image
    import matplotlib.pyplot as plt
    import numpy as np 
    import math
    def BiLinear_interpolation(img,dstH,dstW):
        scrH,scrW,_=img.shape
        img=np.pad(img,((0,1),(0,1),(0,0)),'constant')
        retimg=np.zeros((dstH,dstW,3),dtype=np.uint8)
        for i in range(dstH):
            for j in range(dstW):
                scrx=(i+1)*(scrH/dstH)-1
                scry=(j+1)*(scrW/dstW)-1
                x=math.floor(scrx)
                y=math.floor(scry)
                u=scrx-x
                v=scry-y
                retimg[i,j]=(1-u)*(1-v)*img[x,y]+u*(1-v)*img[x+1,y]+(1-u)*v*img[x,y+1]+u*v*img[x+1,y+1]
        return retimg
    im_path='../paojie.jpg'
    image=np.array(Image.open(im_path))
    image2=BiLinear_interpolation(image,image.shape[0]*2,image.shape[1]*2)
    image2=Image.fromarray(image2.astype('uint8')).convert('RGB')
    image2.save('out.png')

    五. 彩色图像双线性插值实验结果:

    原图 ↑

    RGB图像双线性插值放大2倍后图像 ↑


    六. 最近邻插值算法和双三次插值算法可参考:

            ① 最近邻插值算法:https://www.cnblogs.com/wojianxin/p/12515061.html

            https://blog.csdn.net/Ibelievesunshine/article/details/104936006

            ② 双三次插值算法:https://www.cnblogs.com/wojianxin/p/12516762.html

            https://blog.csdn.net/Ibelievesunshine/article/details/104942406


    七. 参考内容:

            https://www.cnblogs.com/wojianxin/p/12516029.html

            https://www.jianshu.com/p/84c7d98be5ee

    展开全文
  • C#二维数组双线性插值算法

    热门讨论 2014-03-16 11:59:34
    C#的二维数组双线性插值算法。 用于二维数组的双线性插值算法,可分别设置长度和宽度。
  • C语言版本双线性插值算法inline double bilinear_interp(double x, double y, double v11, double v12,double v21, double v22) {return (v11 * (1 - y) + v12 * y) * (1 - x) + (v21 * (1 - y) + v22 * y) * x;...

    C语言版本双线性插值算法

    inline double bilinear_interp(double x, double y, double v11, double v12,

    double v21, double v22) {

    return (v11 * (1 - y) + v12 * y) * (1 - x) + (v21 * (1 - y) + v22 * y) * x;

    }

    使用ARM NOEN优化后的双线性插值版本

    inline uint8x8_t bilinear_interp_NEON(double x, double y, uint8x8_t v11,uint8x8_t v12,

    uint8x8_t v21,uint8x8_t v22)

    {

    uint16x8_t v11_16 = vmovl_u8(v11);

    uint16x8_t v12_16 = vmovl_u8(v12);

    uint16x8_t v21_16 = vmovl_u8(v21);

    uint16x8_t v22_16 = vmovl_u8(v22);

    ///convert v11 to two float32x4

    uint16x4_t v_16_low = vget_low_u16(v11_16);

    uint16x4_t v_16_high = vget_high_u16(v11_16);

    uint32x4_t v_32_low = vmovl_u16(v_16_low);

    uint32x4_t v_32_high = vmovl_u16(v_16_high);

    float32x4_t v11_32f_low = vcvtq_f32_u32(v_32_low);

    float32x4_t v11_32f_high = vcvtq_f32_u32(v_32_high);

    //v12

    v_16_low = vget_low_u16(v12_16);

    v_16_high = vget_high_u16(v12_16);

    v_32_low = vmovl_u16(v_16_low);

    v_32_high = vmovl_u16(v_16_high);

    float32x4_t v12_32f_low = vcvtq_f32_u32(v_32_low);

    float32x4_t v12_32f_high = vcvtq_f32_u32(v_32_high);

    //v21

    v_16_low = vget_low_u16(v21_16);

    v_16_high = vget_high_u16(v21_16);

    v_32_low = vmovl_u16(v_16_low);

    v_32_high = vmovl_u16(v_16_high);

    float32x4_t v21_32f_low = vcvtq_f32_u32(v_32_low);

    float32x4_t v21_32f_high = vcvtq_f32_u32(v_32_high);

    //v22

    v_16_low = vget_low_u16(v22_16);

    v_16_high = vget_high_u16(v22_16);

    v_32_low = vmovl_u16(v_16_low);

    v_32_high = vmovl_u16(v_16_high);

    float32x4_t v22_32f_low = vcvtq_f32_u32(v_32_low);

    float32x4_t v22_32f_high = vcvtq_f32_u32(v_32_high);

    float32_t fx = (float32_t)x;

    float32_t fy = (float32_t)y;

    float32_t one_fx = 1-fx;

    float32_t one_fy = 1-fy;

    float32x4_t tmp1,tmp2,tmp3,tmp4,tmp5,tmp;

    uint32x4_t result_32_low,result_32_high;

    uint16x4_t result_16_low,result_16_high;

    //for low 32x4

    tmp1 = vmulq_n_f32(v11_32f_low, one_fy);

    tmp2 = vmulq_n_f32(v12_32f_low, fy);

    tmp3 = vaddq_f32(tmp1, tmp2);

    tmp4 = vmulq_n_f32(tmp3, one_fx);

    tmp1 = vmulq_n_f32(v21_32f_low, one_fy);

    tmp2 = vmulq_n_f32(v22_32f_low, fy);

    tmp3 = vaddq_f32(tmp1, tmp2);

    tmp5 = vmulq_n_f32(tmp3, fx);

    tmp = vaddq_f32(tmp4, tmp5);

    result_32_low = vcvtq_u32_f32(tmp);

    result_16_low = vqmovn_u32(result_32_low);

    //for high 32x4

    tmp1 = vmulq_n_f32(v11_32f_high, one_fy);

    tmp2 = vmulq_n_f32(v12_32f_high, fy);

    tmp3 = vaddq_f32(tmp1, tmp2);

    tmp4 = vmulq_n_f32(tmp3, one_fx);

    tmp1 = vmulq_n_f32(v21_32f_high, one_fy);

    tmp2 = vmulq_n_f32(v22_32f_high, fy);

    tmp3 = vaddq_f32(tmp1, tmp2);

    tmp5 = vmulq_n_f32(tmp3, fx);

    tmp = vaddq_f32(tmp4, tmp5);

    result_32_high = vcvtq_u32_f32(tmp);

    result_16_high = vqmovn_u32(result_32_high);

    uint16x8_t result_16 = vcombine_u16(result_16_low,result_16_high);

    uint8x8_t result_8 = vqmovn_u16(result_16);

    return result_8;

    }

    使用ARM NEON后,一次可以处理8个像素,成倍提高了运行的速度。实践中需要特别注意对边界的处理(行的开始和结尾处)。

    到这里我们还不能满足。要追求更快!!!

    注意上面的代码中虽然用了ARM NEON,但是在ARM 指令集的操作中用到了浮点操作。所以,还可以继续使用浮点数定点化的优化方式,优化后的代码如下:

    inline uint8x8_t bilinear_interp_NEON_FixedPoint(double x, double y, uint8x8_t v11,uint8x8_t v12,

    uint8x8_t v21,uint8x8_t v22)

    {

    uint16x8_t v11_16 = vmovl_u8(v11);

    uint16x8_t v12_16 = vmovl_u8(v12);

    uint16x8_t v21_16 = vmovl_u8(v21);

    uint16x8_t v22_16 = vmovl_u8(v22);

    uint16x4_t v_16_low = vget_low_u16(v11_16);

    uint16x4_t v_16_high = vget_high_u16(v11_16);

    uint32x4_t v11_32_low = vmovl_u16(v_16_low);

    uint32x4_t v11_32_high = vmovl_u16(v_16_high);

    v_16_low = vget_low_u16(v12_16);

    v_16_high = vget_high_u16(v12_16);

    uint32x4_t v12_32_low = vmovl_u16(v_16_low);

    uint32x4_t v12_32_high = vmovl_u16(v_16_high);

    v_16_low = vget_low_u16(v21_16);

    v_16_high = vget_high_u16(v21_16);

    uint32x4_t v21_32_low = vmovl_u16(v_16_low);

    uint32x4_t v21_32_high = vmovl_u16(v_16_high);

    v_16_low = vget_low_u16(v22_16);

    v_16_high = vget_high_u16(v22_16);

    uint32x4_t v22_32_low = vmovl_u16(v_16_low);

    uint32x4_t v22_32_high = vmovl_u16(v_16_high);

    unsigned int intX = x*4096;

    unsigned int intY = y*4096;

    unsigned int one_x = 4096-intX;

    unsigned int one_y = 4096-intY;

    uint32_t intX_32 = (uint32_t) intX;

    uint32_t intY_32 = (uint32_t) intY;

    uint32_t oneX_32 = (uint32_t) one_x;

    uint32_t oneY_32 = (uint32_t) one_y;

    uint32x4_t tmp1,tmp2,tmp3,tmp4,tmp5,tmp;

    uint16x4_t result_16_low, result_16_high;

    //for low 4 numbers

    tmp1 = vmulq_n_u32(v11_32_low,oneY_32);

    tmp2 = vmulq_n_u32(v12_32_low, intY_32);

    tmp3 = vaddq_u32(tmp1, tmp2);

    tmp4 = vmulq_n_u32(tmp3, oneX_32);

    tmp1 = vmulq_n_u32(v21_32_low, oneY_32);

    tmp2 = vmulq_n_u32(v22_32_low, intY_32);

    tmp3 = vaddq_u32(tmp1, tmp2);

    tmp5 = vmulq_n_u32(tmp3, intX_32);

    tmp = vaddq_u32(tmp4, tmp5);

    result_16_low = vshrn_n_u32(tmp,16); //shift right 16 bytes

    result_16_low = vrshr_n_u16(result_16_low,8); //shift right 8 bytes, totally 24 bytes

    //for high 4 numbers

    tmp1 = vmulq_n_u32(v11_32_high,oneY_32);

    tmp2 = vmulq_n_u32(v12_32_high, intY_32);

    tmp3 = vaddq_u32(tmp1, tmp2);

    tmp4 = vmulq_n_u32(tmp3, oneX_32);

    tmp1 = vmulq_n_u32(v21_32_high, oneY_32);

    tmp2 = vmulq_n_u32(v22_32_high, intY_32);

    tmp3 = vaddq_u32(tmp1, tmp2);

    tmp5 = vmulq_n_u32(tmp3, intX_32);

    tmp = vaddq_u32(tmp4, tmp5);

    result_16_high = vshrn_n_u32(tmp,16); //shift right 16 bytes

    result_16_high = vrshr_n_u16(result_16_high,8); //shift right 8 bytes, totally 24 bytes

    uint16x8_t result_16 = vcombine_u16(result_16_low,result_16_high);

    uint8x8_t result_8 = vqmovn_u16(result_16);

    return result_8;

    }

    加入浮点定点化之后的优化,时间能进一步提升一倍左右。

    展开全文
  • FPGA中实现Bayer模板双线性插值算法的改进.pdf
  • 使用python对2维图像采用最邻近插值和双线性插值算法实现旋转
  • 光流(Optical flow or optic flow)是关于视域中的物体运动检测中的概念。用来描述相对于观察者的运动所造成的观测目标、表面或边缘的运动。 -wikipedia 光流计算所需要满足的两个光学特性假设: ...
  • 针对单板CMOS图像传感器采集的Bayer模板的数据,结合FPGA硬件结构FIFO_DFF构成3×3插值模板,提出一种改进的双线性插值算法。插值过程中利用当前要还原的分量同通道的水平、垂直以及两个对角线方向上的已知分量进行...
  • 最邻近插值和双线性插值源代码,对图像进行缩放
  • 利用灰度级插值的方法来修改秘密信息嵌入点的像素灰度值,为隐藏秘密信息创造出更大的冗余空间;同时采用新的相邻像素差值计算方法以实现秘密信息的嵌入,使得嵌入大量秘密信息后,载密图像的质量得到很好的保证。...
  • 里面包含邻近插值和双线性插值的文档说明以及程序比较,很适合初学者的学习使用,可以很好的理解其中的原理!
  • 双线性插值算法在图片的放大处理方面很实用,效果也很好。本程序实现了这个算法,且可以运行
  • 首先运用双线性插值算法,对低分辨率传感器所成图像进行升采样以提高图像分辨率,然后利用基于OpenCV标定算法对其进行标定,最后将标定结果与传统方法标定结果进行分析比较。实验结果表明,该方法能够将低分辨率...
  • 双线性插值算法的FPGA实现,Verilog代码,分享给大家一起学习!
  • 图像的放大本质上就是增加像素点,目前常用的传统方法是内插法,代表算法有最临近点插值算法、双线性插值算法和双三次插值法,这些算法都是基于相邻像素点的像素值计算所要增加的像素点的像素值,因而在放大时会有...

    图像的放大本质上就是增加像素点,目前常用的传统方法是内插法,代表算法有最临近点插值算法、双线性插值算法和双三次插值法,这些算法都是基于相邻像素点的像素值计算所要增加的像素点的像素值,因而在放大时会有失真的现象存在。在深度学习领域,图像的方法也称为超分辨率,一般采用Gan网络对抗生成高分辨率图片,尽管在一些数据集中取得不错的表现,但是算法的鲁棒性还有待加强。因此,了解传统的内插法还是有很大必要的。

    最临近点插值算法

    这是最简单的一种插值方法,在所求象素的相邻(上下左右)象素中,将距离待求象素最近的邻象素灰度赋给待求象素。设i+u, j+v(i, j为正整数, u, v为大于零小于1的小数,下同)为待求象素坐标,则待求象素灰度的值为f(n(i+u),n( j+v)) ,其中n为最近的一个像素。
    在这里插入图片描述
    优点:简单、计算量小。
    缺点:效果不好,图像放大后失真现象严重。

    双线性插值算法

    双线性内插法是利用待求像素四个相邻像素的灰度,按照其距内插点的距离赋予不同的权重,进行线性内插,如下图所示:

    在这里插入图片描述

    从图中看出,f(x,y)为所求的像素值,其相邻点为图中红点所示分别为f(i,j),f(i+1,j),f(i,j+1),f(i+1,j+1),其像素值如图中绿色线条所示,长度代表值的大小。通过f(x,y)与4点的距离比例,再分别乘以4点的像素值,可以得到所求像素点的值,如图中蓝色线条所示。
    优点:图像连续性较好,是目前最常用的内插法。
    缺点:放大时图像较为模糊,细节损失较严重。
    代码如下:
    "bmp.h"的头文件代码: bmp图片的类以及读写函数 bmp.h

    #include <iostream>
    #include <string.h>   
    #include <math.h>       
    #include <stdlib.h>     
    #include <malloc.h>  
    #include <cstdio> 
    #include "bmp.h"
    using namespace std;
    #define DRAW_HEIGHT 512  //目标图像高度  
    #define DRAW_WIDTH 512  //目标图像宽度  
    
    int main()
    { 
        BMP rbmp;
        BMP wbmp(DRAW_WIDTH,DRAW_HEIGHT);
    	char strFile[50] = "./lena24.bmp";//打开图像路径,BMP图像必须为24位真彩色格式  
    	char strFilesave[50] = "./test.bmp";//处理后图像存储路径 
        //读取位图的数据 
        imread(strFile,rbmp);
        int width = rbmp.cols();
    	int height = rbmp.rows(); 
    	int l_width = WIDTHBYTES(width*24);//计算位图的实际宽度并确保它为4byte的倍数  
        //写位图的数据
        int write_width = WIDTHBYTES(DRAW_WIDTH*24);//计算写位图的实际宽度(字节)并确保它为4byte的倍数   
    	/*******************图像处理部分******************/
        for (int hnum = 0; hnum < DRAW_HEIGHT; hnum++)
    	{
    
        	for (int wnum = 0; wnum < DRAW_WIDTH; wnum++)
    		{
    			double d_original_img_hnum = hnum*height / (double)DRAW_HEIGHT;
    			double d_original_img_wnum = wnum*width / (double)DRAW_WIDTH;
    			int i_original_img_hnum = d_original_img_hnum;
    			int i_original_img_wnum = d_original_img_wnum;
    			double distance_to_a_x = d_original_img_wnum - i_original_img_wnum;//在原图像中与a点的水平距离  
    			double distance_to_a_y = d_original_img_hnum - i_original_img_hnum;//在原图像中与a点的垂直距离  
    			int original_point_a = i_original_img_hnum*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点A    
    			int original_point_b = i_original_img_hnum*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点B  
    			int original_point_c = (i_original_img_hnum + 1)*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点C   
    			int original_point_d = (i_original_img_hnum + 1)*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点D   
    			if (i_original_img_hnum +1== DRAW_HEIGHT - 1)
    			{
    				original_point_c = original_point_a;
    				original_point_d = original_point_b;
    			}
    			if (i_original_img_wnum +1== DRAW_WIDTH - 1)
    			{
    				original_point_b = original_point_a;
    				original_point_d = original_point_c;
    			}                              
     
    			int pixel_point = hnum*write_width + wnum * 3;//映射尺度变换图像数组位置偏移量  
    			wbmp.pColorData[pixel_point] =
    				rbmp.pColorData[original_point_a] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
    				rbmp.pColorData[original_point_b] * distance_to_a_x*(1 - distance_to_a_y) +
    				rbmp.pColorData[original_point_c] * distance_to_a_y*(1 - distance_to_a_x) +
    				rbmp.pColorData[original_point_d] * distance_to_a_y*distance_to_a_x;
    			wbmp.pColorData[pixel_point + 1] =
    				rbmp.pColorData[original_point_a + 1] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
    				rbmp.pColorData[original_point_b + 1] * distance_to_a_x*(1 - distance_to_a_y) +
    				rbmp.pColorData[original_point_c + 1] * distance_to_a_y*(1 - distance_to_a_x) +
    				rbmp.pColorData[original_point_d + 1] * distance_to_a_y*distance_to_a_x;
    			wbmp.pColorData[pixel_point + 2] =
    				rbmp.pColorData[original_point_a + 2] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
    				rbmp.pColorData[original_point_b + 2] * distance_to_a_x*(1 - distance_to_a_y) +
    				rbmp.pColorData[original_point_c + 2] * distance_to_a_y*(1 - distance_to_a_x) +
    				rbmp.pColorData[original_point_d + 2] * distance_to_a_y*distance_to_a_x;
     
    		}
        }
    	/*******************图像处理部分******************/
        std::cout<<"Done!"<<std::endl;
        imwrite(strFilesave,wbmp); 
        system("pause"); 
        return 0;
    }
    

    效果图:
    在这里插入图片描述
    在这里插入图片描述

    双三次插值法

    这个算法原理比较复杂,我另开一章记录,连接如下:
    图像的放大:双三次插值算法(C++实现)

    opencv实现

    opencv自带的resize()函数已经实现了以上算法,仅需要一行代码即可完成。

    void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )
    

    前两个参数分别为输入和输出图像,dsize表示输出图像的大小,fx、fy是沿x轴和y轴的缩放系数。

    dsize=Size(round(fx∗src.cols),round(fy∗src.rows))
    dsize和fx、fy不能同时为0。fx、fy是沿x轴和y轴的缩放系数;默认取0时,计算如下
    其中的参数interpolation表示插值方式,有以下几种:
    INTER_NEAREST - 最近邻插值
    INTER_LINEAR - 线性插值(默认)
    INTER_AREA - 区域插值
    INTER_CUBIC - 三次样条插值
    INTER_LANCZOS4 - Lanczos插值

    展开全文
  • 针对此问题,提出一种基于边缘平滑双线性插值算法的μCGUI高清显示技术,使图片与文字能够更加平滑清晰地显示;并付诸在工程项目中实现,提升了基于嵌入式μCLinux操作系统的高清电视机顶盒显示效果。
  • 看了好几篇关于双线性插值算法的博文,解释得都不好理解,不过下面这篇博文就解释得很好,以下内容均参考这篇: 图像处理+双线性插值法 双线性插值算法 双线性插值算法是解决什么问题的(原理)? 在图像的仿射...

    引言

    看了好几篇关于双线性插值算法的博文,解释得都不好理解,不过下面这篇博文就解释得很好,以下内容均参考这篇:

    双线性插值算法

    双线性插值算法是解决什么问题的(原理)?

    在图像的仿射变换中,很多地方需要用到插值运算,常见的插值运算包括最邻近插值、双线性插值、双三次插值、兰索思插值等方法,OpenCV提供了很多方法,其中,双线性插值由于折中的插值效果和运算速度,运用比较广泛。
      
      越是简单的模型越适合用来举例子,我们就举个简单的图像:3 * 3 的256级灰度图。假如图像的象素矩阵如下图所示(这个原始图把它叫做源图,Source):
    234 38 22
    67 44 12
    89 65 63
      这 个矩阵中,元素坐标(x,y)是这样确定的,x从左到右,从0开始,y从上到下,也是从零开始,这是图象处理中最常用的坐标系。
      如果想把这副图放大为 4 * 4大小的图像,那么该怎么做呢? 那么第一步肯定想到的是先把4 * 4的矩阵先画出来再说,好了矩阵画出来了,如下所示,当然,矩阵的每个像素都是未知数,等待着我们去填充(这个将要被填充的图的叫做目标图,Destination):
      ? ? ? ?
      ? ? ? ?
      ? ? ? ?
      ? ? ? ?
      然后要往这个空的矩阵里面填值了,要填的值从哪里来来呢? 是从源图中来,好,先填写目标图最左上角的象素,坐标为(0,0),那么该坐标对应源图中的坐标可以由如下公式得出
       srcX = dstX * (srcWidth/dstWidth) (括号里srcWidth/dstWidth是两个图的比例关系)
       srcY = dstY * (srcHeight/dstHeight)
      
      好了,套用公式,就可以找到对应的原图的坐标了(0 * (3/4),0 * (3/4))=>(0 * 0.75, 0 * 0.75)=>(0,0),找到了源图的对应坐标,就可以把源图中坐标为(0,0)处的234象素值填进去目标图的(0,0)这个位置了。
      接下来,如法炮制,寻找目标图中坐标为(1,0)的象素对应源图中的坐标,套用公式:
    (1 * 0.75,0 * 0.75)=>(0.75,0) 结果发现,得到的坐标里面竟然有小数,这可怎么办?计算机里的图像可是数字图像,像素就是最小单位了,像素的坐标都是整数,从来没有小数坐标

    这时候采用的一种策略就是采用四舍五入的方法(也可以采用直接舍掉小数位的方法),把非整数坐标转换成整数,好,那么按照四舍五入的方法就得到坐标(1,0),完整的运算过程就是这样的:(1 * 0.75,0 * 0.75)=>(0.75,0)=>(1,0) 那么就可以再填一个象素到目标矩阵中了,同样是把源图中坐标为(1,0)处的像素值38填入目标图中的坐标。
      依次填完每个象素,一幅放大后的图像就诞生了,像素矩阵如下所示:
      234 38 22 22
      67 44 12 12
      89 65 63 63
      89 65 63 63
      这种放大图像的方法叫做最临近插值算法,这是一种最基本、最简单的图像缩放算法,效果也是最不好的,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真;效果不好的根源就是其简单的最临近插值方法引入了严重的图像失真,比如,当由目标图的坐标反推得到的源图的的坐标是一个浮点数的时候,采用了四舍五入的方法,直接采用了和这个浮点数最接近的象素的值,这种方法是很不科学的,当推得坐标值为 0.75的时候,不应该就简单的取为1,既然是0.75,比1要小0.25 ,比0要大0.75 ,那么目标象素值其实应该根据这个源图中虚拟的点四周的四个真实的点来按照一定的规律计算出来的,这样才能达到更好的缩放效果。
      
      双线型内插值算法就是一种比较好的图像缩放算法,它充分的利用了源图中虚拟点四周的四个真实存在的像素值来共同决定目标图中的一个像素值,因此缩放效果比简单的最邻近插值要好很多。
    双线性内插值算法描述如下:
      对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(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)。其中f(i,j)表示源图像(i,j)处的的像素值,以此类推。
      注:比如坐标(1.3,1.4)=> (1+0.3,1+0.4),那么可由原图像中的坐标为(1,1)、(2,1),(1,2),(2,2)所对应的周围四个像素的值决定

    双线性插值算法是怎么解决问题的(计算方法)?

    什么是单线性插值

    已知数据 (x0, y0) 与 (x1, y1),要计算 [x0, x1] 区间内某一位置 x 在直线上的y值。
    在这里插入图片描述
    在这里插入图片描述
    上面比较好理解吧,仔细看就是用x和x0,x1的距离作为一个权重,用于y0和y1的加权。双线性插值本质上就是在两个方向上做线性插值。(其实就是有两个点确定的一次函数,然后在函数上去值呗)

    双线性插值法

    在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。见下图:
    在这里插入图片描述
    假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。最常见的情况,f就是一个像素点的像素值。首先在 x 方向进行线性插值,得到
    在这里插入图片描述
    然后在 y 方向进行线性插值,得到
    在这里插入图片描述
    综合起来就是双线性插值最后的结果:
    在这里插入图片描述
    由于图像双线性插值只会用相邻的4个点,因此上述公式的分母都是1。

    使用双线性插值时要注意什么(存在的问题)?

    这部分的前提是,你已经明白什么是双线性插值并且在给定源图像和目标图像尺寸的情况下,可以用笔计算出目标图像某个像素点的值。当然,最好的情况是你已经用某种语言实现了网上一大堆博客上原创或转载的双线性插值算法,然后发现计算出来的结果和matlab、openCV对应的resize()函数得到的结果完全不一样。
    那这个究竟是怎么回事呢?
    其实答案很简单,就是坐标系的选择问题,或者说源图像和目标图像之间的对应问题。
    按照网上一些博客上写的,源图像和目标图像的原点(0,0)均选择左上角,然后根据插值公式计算目标图像每点像素,假设你需要将一幅5x5的图像缩小成3x3,那么源图像和目标图像各个像素之间的对应关系如下:
    在这里插入图片描述
    只画了一行,用做示意,从图中可以很明显的看到,如果选择右上角为原点(0,0),那么最右边和最下边的像素实际上并没有参与计算,而且目标图像的每个像素点计算出的灰度值也相对于源图像偏左偏上。
    那么,让坐标加1或者选择右下角为原点怎么样呢?很不幸,还是一样的效果,不过这次得到的图像将偏右偏下。
    最好的方法就是,两个图像的几何中心重合(也就是下面要讲的优化策略),并且目标图像的每个像素之间都是等间隔的,并且都和两边有一定的边距,这也是matlab和openCV的做法。如下图:
    在这里插入图片描述
    如果你不懂我上面说的什么,没关系,只要在计算对应坐标的时候改为以下公式即可,

    int x=(i+0.5)*m/a-0.5
    int y=(j+0.5)*n/b-0.5

    instead of

    int x=im/a
    int y=j
    n/b

    利用上述公式,将得到正确的双线性插值结果

    加速及优化策略

    单纯按照上文实现的插值算法只能勉强完成插值的功能,速度和效果都不会理想,在具体代码实现的时候有些小技巧。参考OpenCV源码以及网上博客整理如下两点:
    源图像和目标图像几何中心的对齐
    将浮点运算转换成整数运算

    源图像和目标图像几何中心的对齐

    方法:在计算源图像的虚拟浮点坐标的时候,一般情况:
      srcX=dstX* (srcWidth/dstWidth) ,
      srcY = dstY * (srcHeight/dstHeight)
    中心对齐:
      SrcX=(dstX+0.5)* (srcWidth/dstWidth) -0.5
      SrcY=(dstY+0.5) * (srcHeight/dstHeight)-0.5
    原理:
    双线性插值算法及需要注意事项这篇博客解释说“如果选择右上角为原点(0,0),那么最右边和最下边的像素实际上并没有参与计算,而且目标图像的每个像素点计算出的灰度值也相对于源图像偏左偏上。”我有点保持疑问。
    将公式变形:
      srcX=dstX * (srcWidth/dstWidth)+0.5 * (srcWidth/dstWidth-1)
      相当于我们在原始的浮点坐标上加上了0.5 * (srcWidth/dstWidth-1)这样一个控制因子,这项的符号可正可负,与srcWidth/dstWidth的比值也就是当前插值是扩大还是缩小图像有关,有什么作用呢?看一个例子:假设源图像是33,中心点坐标(1,1)目标图像是99,中心点坐标(4,4),我们在进行插值映射的时候,尽可能希望均匀的用到源图像的像素信息,最直观的就是(4,4)映射到(1,1)现在直接计算srcX=4 * 3/9=1.3333!=1,也就是我们在插值的时候所利用的像素集中在图像的右下方,而不是均匀分布整个图像。现在考虑中心点对齐,srcX=(4+0.5) * 3/9-0.5=1,刚好满足我们的要求。

    将浮点运算转换成整数运算

    参考图像处理界双线性插值算法的优化
      直接进行计算的话,由于计算的srcX和srcY 都是浮点数,后续会进行大量的乘法,而图像数据量又大,速度不会理想,解决思路是:
      浮点运算→→整数运算→→”<<左右移按位运算”。
      放大的主要对象是u,v这些浮点数,OpenCV选择的放大倍数是2048“如何取这个合适的放大倍数呢,要从三个方面考虑,
      第一:精度问题,如果这个数取得过小,那么经过计算后可能会导致结果出现较大的误差。
      第二,这个数不能太大,太大会导致计算过程超过长整形所能表达的范围。
      第三:速度考虑。假如放大倍数取为12,那么算式在最后的结果中应该需要除以12 * 12=144,但是如果取为16,则最后的除数为16 * 16=256,这个数字好,我们可以用右移来实现,而右移要比普通的整除快多了。”我们利用左移11位操作就可以达到放大目的。

    展开全文
  • 双线性插值算法及实现.

    热门讨论 2009-10-31 11:23:46
    双线性插值算法及其实现,有源代码,感觉还不错,共享一下
  • 双线性插值算法的详细总结

    万次阅读 多人点赞 2017-12-17 16:43:30
    里面用到了图像的单应性矩阵变换,在最后的图像重映射,由于目标图像的坐标是非整数的,所以需要用到插值的方法,用的就是双线性插值,下面的博文主要是查看了前辈的博客对双线性插值算法原理进行了一个总结,在这里...
  • JAVA双线性插值算法实现图片的缩写放大功能。本程序根据这个算法实现了图片的缩小功能,而且附带测试图片可以运行测试。
  • Preface 最期待的数字图像课开课啦,然后第一次上机课老师让我们动手写双线性...关于双线性插值的介绍,这里不过多赘述,简单描述一下就是对原图进行缩放时,将多出来或少出来的像素最优处理的算法。我们还可以使用KN
  • 一、算法原理 提出此算法的背景是基于图片的缩放,在图片缩放的过程中,实质上就是将原图像像素矩阵像素值,填到目标图像像素矩阵中,目标图像像素矩阵可能比原图像像素矩阵大(图片放大),也可能小(图片缩小)。...
  • 图像缩放处理-双线性插值算法 一、概念 双线性插值,又称为双线性内插。在数学上,双线性插值是对线性插值在二维直角网格上的扩展,用于对双变量函数(例如 x 和 y)进行插值。其核心思想是在两个方向分别进行一次...
  • 双线性插值算法以及python实现

    万次阅读 2018-09-13 16:24:11
    双线性插值算法【文章主题内容为转载,代码为自己所写】,在这里也感谢一些大牛的博文。 http://www.cnblogs.com/linkr/p/3630902.html http://www.cnblogs.com/funny-world/p/3162003.html 双线性插值 &amp...
  • 里面用到了图像的单应性矩阵变换,在最后的图像重映射,由于目标图像的坐标是非整数的,所以需要用到插值的方法,用的就是双线性插值,下面的博文主要是查看了前辈的博客对双线性插值算法原理进行了一个总结,在这里...
  • 双线性插值算法的详细总结 .

    千次阅读 2017-04-16 16:10:27
    里面用到了图像的单应性矩阵变换,在最后的图像重映射,由于目标图像的坐标是非整数的,所以需要用到插值的方法,用的就是双线性插值,下面的博文主要是查看了前辈的博客对双线性插值算法原理进行了一个总结,在这里...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,242
精华内容 3,296
关键字:

双线性插值算法

友情链接: ejml矩阵包.rar