纯C++仿射变换实现

纯C++仿射变换实现

最近需要使用仿射变换进行一些应用,但又不想用到OpenCV或Halcon之类的库进行,就自己写了一个计算和实现函数,大概记录一下这个过程。
基本概念参考:图像变换的基本模型

前言

想要实现的效果:知道坐标系A的3个坐标,和对应坐标系B的3个坐标,得到变换关系,实现输入任意坐标系A的坐标(Xa, Ya),可以计算得出坐标系B对应的坐标(Xb, Yb)。

原理

通过找资料知道公式如下:
仿射变换行列式

x’ = a1*x + a2*y + tx
y’ = a3*x + a4*y + ty

由于输入有6个坐标,代入进去可以得到6个方程,得到2组三元一次方程组,可以计算出未知的a1、a2、 tx、a3、 a4、 ty共6个变量。

为了理解方便,把tx改为c,x’改为z,则:
三元一次方程组
需要求解a, b, c

求解过程
先消去变量a,变成一个二元一次方程组,然后再消去变量b,得到c的值,代入二元一次方程得到b的值,最后代入三元一次方程得到a的值。
最后得到a1、a2、 tx、a3、 a4、 ty 6个变量的值。

代码实现

实现原理的计算,需要输入3个坐标和3个对应的x’或y’的值,输出a1, a2和t 。

由于被除数不能为0,所以当余数为0时,方程无解,return负数;方程组能解时,return 0 。

具体代码如下:

struct Point {
    float x;
    float y;
};

int TernaryEquation(Point input[3], float output[3], float* a1, float* a2, float* t)
{
    float x0 = input[0].x;
    float x1 = input[1].x;
    float x2 = input[2].x;
    float y0 = input[0].y;
    float y1 = input[1].y;
    float y2 = input[2].y;
    float z0 = output[0];
    float z1 = output[1];
    float z2 = output[2];

    float A1 = y0*x1 - y1*x0;
    float A2 = y0*x2 - y2*x0;
    float B1 = x1 - x0;
    float B2 = x2 - x0;
    float C1 = z0*x1 - z1*x0;
    float C2 = z0*x2 - z2*x0;

    float d = B1*A2 - B2*A1;
    if(0 == d)
    {
        return -1;
    }

    float c = (C1*A2 - C2*A1)/d;
    float b;
    if(0 == A1)
    {
        if(0 == A2)
        {
            return -2;
        }
        else
        {
            b = (C2 - c*B2)/A2;
        }
    }
    else
    {
        b = (C1 - c*B1)/A1;
    }

    float a;
    if(0 == x0)
    {
        if(0 == x1)
        {
            if(0 == x2)
            {
                return -3;
            }
            else
            {
                a = (z2 - b*y2 - c)/x2;
            }
        }
        else
        {
            a = (z1 - b*y1 - c)/x1;
        }
    }
    else
    {
        a = (z0 - b*y0 - c)/x0;
    }

    *a1 = a;
    *a2 = b;
    *t = c;

    return 0;
}

输入需要的变量,求输出结果:

int TransPoint(Point input[3], Point output[3], Point inputA, Point* outputB)
{
    float outputx[3], outputy[3];
    outputx[0] = output[0].x;
    outputx[1] = output[1].x;
    outputx[2] = output[2].x;
    outputy[0] = output[0].y;
    outputy[1] = output[1].y;
    outputy[2] = output[2].y;

    float a1, a2, tx, a3, a4, ty;
    int resx = TernaryEquation(input, outputx, &a1, &a2, &tx);
    int resy = TernaryEquation(input, outputy, &a3, &a4, &ty);
    if(0 == resx && 0 == resy)
    {
        outputB->x = a1*inputA.x + a2*inputA.y + tx;
        outputB->y = a3*inputA.x + a4*inputA.y + ty;
        return 0;
    }
    return -1;
}

结果验证

使用坐标测试

Vx:=[18.1, 10.72, 36]
Vy:=[60.21, 39.36, 32.67]
Wx:=[-202.73, -181.22, -189.39]
Wy:=[-43.16, -38, -13.15]

对比代码运行结果和使用Halcon仿射变换的结果
仿射变换结果对比
输出一致,说明仿射变换正确。

大功告成,后面再整理一下代码精简一下就OK了。

  • 13
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值