C++版OpenCV_02_几何变换

几何变换

      • [2.1 仿射变换](#2.1 仿射变换)
      • [2.2 投影变换](#2.2 投影变换)
      • [2.3 极坐标变换](#2.3 极坐标变换)
        • [2.3.1 笛卡尔坐标转极坐标](#2.3.1 笛卡尔坐标转极坐标)
        • [2.3.2 极坐标转换为笛卡儿坐标](#2.3.2 极坐标转换为笛卡儿坐标)
        • [2.3.3 图像极坐标变换](#2.3.3 图像极坐标变换)
        • [2.3.4 线性极坐标函数](#2.3.4 线性极坐标函数)
        • [2.3.5 对数极坐标函数 logPolar](#2.3.5 对数极坐标函数 logPolar)

几何变换:

  1. 仿射变换:平移、放大缩小、旋转、计算仿射矩阵(方程法、矩阵法)、插值(最近邻、双线性插值)、
  2. 投影变换
  3. 极坐标变换

2.1 仿射变换

平移

c++ 复制代码
x_ = 1*x + 0*y+ tx
y_ = 0*x + 1*y+ ty

放大缩小

c++ 复制代码
/*
x_ = sx*x + 0*y+ 0*tx
y_ = 0*x + sy*y+ 0*ty

void resize(InputArray scr,outputArray dst,Size dsize,double fx=0,double fy=0,int interpolation=INTER_LINEAR)
scr: 输入图像
dst: 输出图像
dsize:(宽高)
fx: 水平方向上的缩放比例
fy: 垂直方向上的缩放比例
interpolation: 插值法 INTER_NEAREST、INTER_LINEAR

*/
#include<opencv/core/core.hpp>
#include<opencv/highgui/highgui.hpp>
#include<opencv/imgproc/imgproc.hpp>
using namespace cv;
int main(int argv,char*argv[])
{
    Mat I = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);
    if(!I.data)
        return -1;
    Mat s = (Mat_<float>(2,2)<<0.5,0,0,0,0.5,0);
    Mat dst;
    warpAffine(I,dst,s,Size(I.cols/2,I.rows/2));
    Mat dst1;
    resize(I,dst1,Size(I.cols/2,I.rows/2),0.5,0.5);
}

旋转

c++ 复制代码
/*
x_ = cosa*x + sina*y+ 0*tx
y_ = -sina*x + cosa*y+ 0*ty
void rotate(InputArray scr,outputArray dst,int rotateCode)
rotateCode: ROTATE_90_CLOCKWISE,ROTATE_180,ROTATE_90_COUNTERCLOCKWISE,270度
*/

#include<opencv/core/core.hpp>
#include<opencv/highgui/highgui.hpp>

using namespace cv;
int main(int argv,char*argv[])
{
    Mat I = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);
    if(!I.data)
        return -1;
 
    Mat dst;
    rotate(I,dst,ROTATE_90_CLOCKWISE);

}

计算仿射矩阵

方程法求仿射矩阵

c++ 复制代码
// 仿射矩阵有6个自由度,因此需要src,dst3对不共线的点求解
// 把对应点存在数组中
Point2f src[]={Point2f(0,0),Point2f(10,24),Point2f(60,120)};
Point2f dst[]={Point2f(0,0),Point2f(30,64),Point2f(50,98)};
Mat A = getAffineTransform(src,dst)

// 把对应点存在矩阵中
Mat src = (Mat_<float>(3,2)<<0,0,10,24,60,120);
Mat dst = (Mat_<float>(3,2)<<0,0,30,64,50,98);
Mat A = getAffineTransform(src,dst)

计算仿射矩阵

矩阵法:

c++ 复制代码
// 获取旋转矩阵
Mat A = getRotationMatrixD(Point2f(x,y),angle,scale);

2.2 投影变换

c++ 复制代码
/*
Point2f src[]={Point2f(0,0),Point2f(100,0),Point2f(0,100),Point2f(100,100)};
Point2f dst[]={Point2f(100,30),Point2f(200,30),Point2f(70,80),Point2f(230,90)};
Mat P=getPerspectiveTransform(src,dst);


Point2f src=(Mat_<float>(4,2)<<0,0,20,10,40,89,100,100);
Point2f dst=(Mat_<float>(4,2)<<10,20,30,80,80,90,200,150);
Mat P=getPerspectiveTransform(src,dst);
*/

2.3 极坐标变换

2.3.1 笛卡尔坐标转极坐标
c++ 复制代码
/*
笛卡尔坐标转极坐标
已知任意一点(x,y),中心(x',y'),(a,r)
r = ((x-x')**2+(y-y')**2)**0.5
a = 2pi+arctan2(y-y',x-x') 当y-y' <=0  or  arctan2(y-y',x-x')  当y-y' >0

cartToPolar(x,y magnitude,angle,angleInDegrees)
angleInDegrees: ture 返回角度,反之,返回弧度。


*/
// 笛卡儿坐标转换为极坐标
Mat x = (Mat_<float>(1,8)<<0,1,2,0,2,0,1,2)-1;
Mat y = (Mat_<float>(1,8)<<0,0,0,1,1,2,2,2)-1;
Mat r,theta;
cartToPolar(x,y,r,theta,True);
/* 结果
1.41   3.93
1.0    4.71
1.41   5.5
1.0    3.14
1.0    0.0
1.41   2.36
1.0    1.57
1.41   0.79
*/
2.3.2 极坐标转换为笛卡儿坐标
c++ 复制代码
/*
x = x'+r*cosa
y = y'+r*sina
polarTocart(magnitude,angle,x,y,angleInDegrees));
返回的是以(0,0)为中心的笛卡尔坐标,已知(r,theta)和(x',y')得到(x-x',y-y')
*/
Mat angle = (Mat_<float>(2,2)<<30,31,30,31);
Mat r = (Mat_<float>(2,2)<<10,10,11,11);
Mat x,y;
polarTocart(r,angle,x,y,true);
2.3.3 图像极坐标变换
c++ 复制代码
/*
O(i,j) = I(x'+(r_min+r_step*i)*cos(a_min+a_step*j),  y'+(r_min+r_step*i)*sin(a_min+a_step*j))
*/
python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt


def polar(img, center, r, theta=(0, 360), rstep=1.0, thetastep=360.0 / (180 * 8)):
    cx, cy = center
    r_min, r_max = r
    theta_min, theta_max = theta
    H = int((r_max - r_min) / rstep) + 1
    W = int((theta_max - theta_min) / thetastep) + 1
    out = np.ones((H, W), img.dtype) * 125

    r = np.linspace(r_min, r_max, H)
    r = np.tile(r, (W, 1)).T  # (H,W)
    theta = np.linspace(theta_min, theta_max, W)
    theta = np.tile(theta, (H, 1))  # (H,W)
    x, y = cv2.polarToCart(r, theta, True)

    for i in range(H):
        for j in range(W):
            px = int(round(x[i, j]) + cx)
            py = int(round(y[i, j]) + cy)
            if (px >= 0 and px <= W - 1) and (py >= 0 and px <= H - 1):
                out[i, j] = img[px, py]
    return out


if __name__ == "__main__":
    img = np.zeros([300, 300, ], np.uint8)
    img = cv2.circle(img, (150, 150), 80, (255), -1)
    plt.imshow(img, 'gray')
    o = polar(img, center=(150, 150), r=(0, 100), theta=(0, 360), rstep=0.25)
    plt.imshow(o, 'gray')
c++ 复制代码
/*
根据中心(cx,cy)、最小半径、最小角度、半径步长、角度步长获取最大半径和最大步长,把r、theta转换成x,y。把(x,y)对应的像素值赋值给对应坐标(r、theta)。
*/
Mat polar(Mat I,Point2f center,Size size,float minr = 0,float mintheta=0,float thetaStep = 1.0/4,float rStep;=1.0)
{
    // 构建 r[size.height,size.width]
    Mat ri = Mat::zeroes(Size(1,size.height),CV_32FC1);
    for (int i = 0;i <size.height;++i)
    {
        ri.at<float>(i,0) = minr+i*rStep;
    }
    Mat r = repeat(ri,1,size.width);
    // 构建 theta[size.height,size.width]
    Mat  thetaj = Mat::zeroes(Size(size.width,1),CV_32FC1);
    for (int j = 0;j <size.width;++j)
    {
        thetaj.at<float>(0,j) = mintheta+j*thetaStep;
    }
    Mat theta = repeat(thetaj,size.height,1
    // 把极坐标转换为笛卡尔坐标
    Mat x,y;
    polarToCart(r,theta,x,y,true);
    x += center.x;
    y += center.y;
    // 最近邻插值
    Mat dst = 125*Mat::ones(size,CV_8UC1);
    for (int i=0;i<size.height,++i)
    {
        for (int j=0;j<size.width,++j)
        {
            float xij = x.at<float>(i,j);
            float yij = y.at<float>(i,j);
            
            int x_near = int(round(xij));
            int y_near = int(round(yij));
        }
        if((x_near>=0&&x_near<=I.cols)&&(y_near>=0&&y_near<=I.rows))
        {
            dst.at<uchar>(i,j)=I.at<uchar>(y_near,x_near)
        }
    }
    return dst;
}

int main(int argc,char*argv[])
{
    Mat I = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);
    if(!I.data)
        return -1;
    float thetaStep=1.0/4;
    float minr = 270;
    Size size(int(360/thetaStep),80);
    Mat dst = polar(I,Point2f(500,508),size,minr);
    flip(dst,dst,0);
}
2.3.4 线性极坐标函数
c++ 复制代码
/*
void linearPolar( InputArray src, OutputArray dst,Point2f center, double
maxRadius, int flags );
src :输入图像矩阵(单、多通道矩阵都可以)
dst :输出图像矩阵,其尺寸和 src 是相同的
center :极坐标变换中心
maxRadius :极坐标变换的最大距离
flags :插值算法,同函数 resize、warpAffine 的插值算法
角度 𝜃 的变换步长大约为 36/0𝐻
,𝑟 的变换步长大约为 maxRadius/𝑊
;
*/
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
using namespace cv;
int main(int argc, char*argv[])
{
    //输入图像
    Mat src = imread(argv[1], IMREAD_ANYCOLOR);
    if (!src.data)
    return -1;
    //极坐标变换
    Mat dst;
    linearPolar(src, dst, Point2f(508, 503), 550, CV_INTER_LINEAR);
    //显示原图和极坐标变换图
    imshow("原图", src);
    imshow("极坐标变换图", dst);
    waitKey(0);
    return 0;
}
2.3.5 对数极坐标函数 logPolar
c++ 复制代码
/*
void logPolar(InputArray src,OutputArray dst,Point2f center, double M, int
flags )
src: 输入图像矩阵(单、多通道矩阵都可以)
dst: 输出图像矩阵,其尺寸和 src 是相同的
center: 极坐标变换中心
M: 系数,该值大一点效果会好一些
flags:
WARP_FILL_OUTLIERS:笛卡儿坐标向对数极坐标变换
WARP_INVERSE_MAP:对数极坐标向笛卡儿坐标变换

笛卡儿坐标转换为对数极坐
标:
r = M*log(((x-cx)**2+(y-cy)**2)**0.5)
theta = actan2(y-cy,x-cx); if y>cy,theta=theta else theta+=2*pi
将对数极坐标转换为笛卡儿坐标:
x = cx+exp(r/M)cosa;y = cy+exp(r/M)sina
*/
int main(int argc, char*argv[])
{
    //读入图像
    Mat src = imread(argv[1], IMREAD_ANYCOLOR);
    //对数极坐标变换
    Mat dst;
    Point2f center(508, 503);
    float M = 100;
    logPolar(src, dst, center, M, WARP_FILL_OUTLIERS);
    //显示对数极坐标变换的结果
    imshow("对数极坐标变换", dst);
    imshow("原图", src);
    waitKey(0);
    return 0;
}
相关推荐
hope_wisdom4 分钟前
C++网络编程之SSL/TLS加密通信
网络·c++·ssl·tls·加密通信
erxij9 分钟前
【游戏引擎之路】登神长阶(十四)——OpenGL教程:士别三日,当刮目相看
c++·经验分享·游戏·3d·游戏引擎
Lizhihao_22 分钟前
JAVA-队列
java·开发语言
林开落L39 分钟前
前缀和算法习题篇(上)
c++·算法·leetcode
远望清一色40 分钟前
基于MATLAB边缘检测博文
开发语言·算法·matlab
何曾参静谧1 小时前
「Py」Python基础篇 之 Python都可以做哪些自动化?
开发语言·python·自动化
Prejudices1 小时前
C++如何调用Python脚本
开发语言·c++·python
单音GG1 小时前
推荐一个基于协程的C++(lua)游戏服务器
服务器·c++·游戏·lua
我狠狠地刷刷刷刷刷1 小时前
中文分词模拟器
开发语言·python·算法
wyh要好好学习1 小时前
C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中
开发语言·c#·wpf