首页 > 其他分享 >opencv中自定义的双线性二次插值的图像旋转及缩放

opencv中自定义的双线性二次插值的图像旋转及缩放

时间:2024-05-02 22:23:00浏览次数:24  
标签:src rad np4Corner 自定义 缩放 double dst 双线性 borders

#include <iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

void coordinateTransform(Point2d*p4Corner,Point2d*np4Corner,double rotAngle,double gamma,Point2d center)
{
    double cx=center.x,cy=center.y;
    double rad=rotAngle*CV_PI/180;
    double alpha=std::cos(rad)*gamma;
    double beta=std::sin(rad)*gamma;
    for(int i=0;i<4;i++)
    {
        np4Corner[i].x= alpha*p4Corner[i].x+beta*p4Corner[i].y+(1-alpha)*cx-beta*cy;
        np4Corner[i].y=-beta*p4Corner[i].x+alpha*p4Corner[i].y+beta*cx+(1-alpha)*cy;
    }
}
void find4Borders(Point2d* np4Corner,double borders[4])
{
    borders[0]=np4Corner[0].y;
    borders[1]=np4Corner[0].y;
    borders[2]=np4Corner[0].x;
    borders[3]=np4Corner[0].x;
    for(int i=1;i<4;i++)
    {
        borders[0]=np4Corner[i].y<borders[0]?np4Corner[i].y:borders[0];
        borders[1]=np4Corner[i].y>borders[1]?np4Corner[i].y:borders[1];
        borders[2]=np4Corner[i].x<borders[2]?np4Corner[i].x:borders[2];
        borders[3]=np4Corner[i].x>borders[3]?np4Corner[i].x:borders[3];
    }
    for(int i=0;i<4;i++)
    {
        if(borders[i]<0)
            borders[i]=floor(borders[i]);
        else
            borders[i]=ceil(borders[i]);

    }
}
//    Mat mat=(Mat_<double>(2,3)<<alpha,  beta,  (1-alpha)*x+beta*y,
//                                -beta,  alpha,   beta*x+(1-alpha)*y);
void rotImg(const Mat&src,Mat&dst,double rotAngle,double gamma,Point2d center)
{
    double rad=rotAngle*CV_PI/180;
    double cosRad=std::cos(rad) ;
    double sinRad=std::sin(rad);
    int oldRows=src.rows, oldCols=src.cols;
    //逆向旋转的矩阵描述
    double x=center.x,y=center.y;
    double alpha=cosRad*gamma,beta=sinRad*gamma;//正向缩放
    //计算新图像的大小
    //1、获取原图像的四个角点坐标p4Corner,以及变换后的四个角点坐标np4Corner
    Point2d p4Corner[]={ Point2d(0,0),              Point2d(src.cols,0),
                      Point2d(0,src.rows) ,  Point2d(src.cols,src.rows)};
    Point2d np4Corner[4];
    coordinateTransform(p4Corner,np4Corner,rotAngle,gamma,center);//对原图像四个角点做坐标正向变换
    //根据np4Corner,找到变换后新图像的上、下、左、右边界坐标
    double borders[4];
    find4Borders(np4Corner,borders);
    //计算新图的行数、列数
    int newRows=borders[1]-borders[0];
    int newCols=borders[3]-borders[2];
    //为目标图像分配内存
    dst=Mat::zeros(newRows,newCols,src.type());

    //计算二维插值
    int step0=src.step[0],step1=src.step[1];
    int channels=src.channels();
    alpha =cosRad/gamma;//逆向缩放
    beta=sinRad/gamma;//逆向缩放
    for(int i=0;i<newRows;i++)
        for(int j=0;j<newCols;j++)
        {
            //注意:在新图中,原点坐标偏移了(borders[2],borders[0])。所以要把每个像素坐标偏移回来(j+borders[2])、(i+borders[0])
            double x_inv=alpha*(j+borders[2])-beta*(i+borders[0])+(1-alpha)*x+beta*y;//逆映射回原图坐标
            double y_inv=beta*(j+borders[2])+alpha*(i+borders[0])-beta*x+(1-alpha)*y;//逆映射回原图坐标
            int j_inv=floor(x_inv);
            int i_inv=floor(y_inv);
            if(j_inv>=0&&j_inv<oldCols&&i_inv>=0&&i_inv<oldRows)
            {
                double a=x_inv-j_inv, b=y_inv-i_inv;
                //找到四个坐标点
                uchar* p1=src.data+step0*i_inv+step1*j_inv;
                uchar* p2=src.data+step0*i_inv+step1*(j_inv+1);
                uchar* p3=src.data+step0*(i_inv+1)+step1*j_inv;
                uchar* p4=src.data+step0*(i_inv+1)+step1*(j_inv+1);
                //获取目标图像中的第i、j坐标
                uchar* pdst=dst.data+dst.step[0]*i+dst.step[1]*j;
                for(int k=0;k<channels;k++)
                {
                    pdst[k]=static_cast<uchar>((1-a)*(1-b)*p1[k]+a*(1-b)*p2[k]+b*(1-a)*p3[k]+a*b*p4[k]) ;
                }
            }
        }
}

int main()
{
    Mat src=imread("D:/Qt/MyImage/baboon.jpg",1);

    Mat dst;
    rotImg(src,dst,315,0.5,Point(100,100));
    imshow("rotated image",dst);
    imshow("original image",src);
    waitKey();

    return 0;
}



 





 

标签:src,rad,np4Corner,自定义,缩放,double,dst,双线性,borders
From: https://www.cnblogs.com/phoenixdsg/p/18170647

相关文章

  • springboot+MDCAdapter自定义starter实现日志全链路追踪
    MDCMDC(MappedDiagnosticContext,映射调试上下文)是日志系统提供的一种方便在多线程条件下记录日志的功能使用场景一个常用的场景就是Web服务器中给每个请求都分配一个独特的请求id,所有的日志都会打印这个请求id,这样一个请求下的所有日志信息都可以很方便的找到。欢迎关注个人公......
  • 使用Colab_LLaMA_Factory_LoRA微调_Llama3(可自定义数据)
    使用LLaMAFactory微调Llama-3中文对话模型项目主页: https://github.com/hiyouga/LLaMA-Factory这个过程超级简单,半个多小时在T4上就能跑完。完全可以替换成自己的数据,支持中文数据。安装LLaMAFactory依赖 1%cd/content/2%rm-rfLLaMA-Factory3!gitclo......
  • 从自定义一个作用域开始来了解SpringBean的作用域
    你好,这里是codetrend专栏“Spring6全攻略”。在Spring框架中,Bean的作用域(Scope)定义了Bean实例在容器中如何创建、管理和销毁的策略。Spring提供了多种Bean作用域,每种作用域都有其特定的生命周期和适用场景。先试试不同的BeanScope下面通过一个简单的SpringMVCCon......
  • dbt 自定义schema 简单说明
    dbt的schema我们是可以灵活进行自定义的,可以实现一个比较有意思的事情使用场景模型级别的schema自定义seed数据schema自定义不同env或者vars的schema自定义不同targetschema的自定义schema自定义核心是generate_schema_name这个macro,我们可以自己定义参考自......
  • dbt 自定义AdapterPlugin 中dependencies 简单说明
    结合dbt-redshift的对于dependencies部分的定义以及使用简单说明下参考代码Plugin:AdapterPlugin=AdapterPlugin(adapter=RedshiftAdapter,#type:ignorecredentials=RedshiftCredentials,include_path=redshift.PACKAGE_PATH,dep......
  • 06-混入-自定义插件-插槽-本地存储-vuex组件通信-页面跳转
    混入mixin在Vue中,混入(mixin)是一种可以在多个组件中重复使用的对象。它允许您将组件中的一些选项提取出来,然后在多个组件中进行重复使用。混入可以包含组件中的任何选项,例如数据、计算属性、方法等。使用步骤在src文件夹下新建一个文件夹,比如mixin,然后再这个文件夹下面新建一......
  • Java实现自定义指标数据远程写入Prometheus
    主要的流程如下:1>prometheus添加启动参数2>调用http请求来远程写,数据格式是protobuf(一种自定义的编码格式),编码格式是snappy(一种压缩格式)3>远程写通过snappy先压缩,然后将通过protobuf编码的字节数组发送请求;prometheus官网文档远程写提供remote.proto(包含编码和解码),remote.pr......
  • Go语言系列——自定义错误、panic和recover、函数是一等公民(头等函数)、反射、读取文件
    文章目录31-自定义错误使用New函数创建自定义错误使用Errorf给错误添加更多信息使用结构体类型和字段提供错误的更多信息使用结构体类型的方法来提供错误的更多信息32-panic和recover什么是panic?什么时候应该使用panic?panic示例发生panic时的deferrecoverpanic,re......
  • Go语言系列——数组和切片、可变参数函数、Maps、字符串、指针、结构体、方法、接口(一
    文章目录11-数组和切片数组数组的声明数组是值类型数组的长度使用range迭代数组多维数组切片创建一个切片切片的修改切片的长度和容量使用make创建一个切片追加切片元素切片的函数传递多维切片内存优化12-可变参数函数什么是可变参数函数语法通过一些例子理解可变参......
  • zabbi添加自定义监控项——检查文件是否存在
    1、检查脚本D:/check.pyimportosimportdatetimeimportargparse#获取文件名parser=argparse.ArgumentParser()parser.add_argument('filename')args=parser.parse_args()file_name=args.filename#获取今天日期today=datetime.datetime.today().strftime......