惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
腾讯CDC
G
Google Developers Blog
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
有赞技术团队
有赞技术团队
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
美团技术团队
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志

博客园 - 凤凰_1

多边形近似:最小周长多边形算法MPP 多阈值otsu的opencv实现 在Opencv中自定义了一个相位函数,获取复数矩阵的相位 cvIsInf与cvIsNan函数 Mandelbrot set 以parallel_for_实现 opencv的并行操作parallel_for_的问题 CV_WRAP和CV_EXPORTS_W opencv超级像素示例 在Qt中,如何在sheets末端添加新的sheet opencv4.x 中的plot函数绘制二维Mat C++版DNN最简主体框架 C++版全连接神经网络 C++版加载MNIST图像集合 C++版的神经网络训练用的图像集合加载 c\c++宏定义,四个参数求最大值 - 凤凰_1 - 博客园 自定义c++二维动态数组 用Cmake 编译OpenCV常见的错误 Opencv中的dft()和idft()示例 C++仿Matlab的bsxfun函数
opencv中自定义的双线性二次插值的图像旋转及缩放
凤凰_1 · 2024-05-02 · via 博客园 - 凤凰_1
#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;
}