Ex5: Projective Transform & Image Morphing

透视变换:

这里写图片描述
这个问题主要就是求出右边那个3X3的矩阵,只要求出来了,问题就解决了,我认为有两种方法,一种是代进去求通解,已知8个顶点解8个未知数,就是笔算计算复杂了点;第二种是最小二乘法,这里我采用了后者,当然这里偷懒调用了矩阵库来进行矩阵运算,但还有个问题要解决,那就是怎么把上面的矩阵形式写成Ax=b形式,其中x是[a b c d e f g h]向量,是我需要求的,至于这里i为什么不用是因为i就是等于1,而b是[x1 y1 x2 y2 x3 y3 x4 y4]向量,对应的是原图中我们需要做变换的A4纸的顶点坐标。重点就是这个A要怎么求出来。
(以下是关于求这个矩阵的paper)
这里写图片描述
如图,A对应的就是这个形式。既然需要的东西都有了,那么就可以用最小二乘法求出这8个参数了。
然后再利用
这里写图片描述
求出对应的原图坐标(u, v),把它的RGB值赋给新图中的(x, y),对所有的xy遍历一遍即可完成变换。

(也可以解8个方程求出通解来完成这个变换)


测试结果:
这里写图片描述


这是我这个方法的实现代码:

#include "stdafx.h"
#include <iostream>
#include <Eigen/Dense>
#include <CImg.h>
#include <canny.hpp>

using namespace cimg_library;
using namespace std;
using namespace Eigen;
using namespace Eigen::internal;
using namespace Eigen::Architecture;

int main()
{
    string str;
    cin >> str;
    CImg<float> img(str.c_str());
    MatrixXd A(8, 8);
    MatrixXd b(8, 1);
    float x1, x2, x3, x4, y1, y2, y3, y4;
    float u1, u2, u3, u4, v1, v2, v3, v4;
    //经过hough变换得到的四个顶点坐标
    cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4;
    //预设的A4纸尺寸和顶点坐标
    u1 = 0, v1 = 0, u2 = 2100, v2 = 0, u3 = 0, v3 = 2970, u4 = 2100, v4 = 2970;
    //写成矩阵A形式
    A << u1, v1, 1, 0, 0, 0, -u1*x1, -v1*x1,
        0, 0, 0, u1, v1, 1, -u1*y1, -v1*y1,
        u2, v2, 1, 0, 0, 0, -u2*x2, -v2*x2,
        0, 0, 0, u2, v2, 1, -u2*y2, -v2*y2,
        u3, v3, 1, 0, 0, 0, -u3*x3, -v3*x3,
        0, 0, 0, u3, v3, 1, -u3*y3, -v3*y3,
        u4, v4, 1, 0, 0, 0, -u4*x4, -v4*x4,
        0, 0, 0, u4, v4, 1, -u4*y4, -v4*y4;
    // b为原图顶点坐标向量
    b << x1, y1, x2, y2, x3, y3, x4, y4;
    // A的转置
    MatrixXd A_t = A.transpose();
    //利用Ax=b计算x 其中这里x为h h只是8*1的向量,因为a33默认为1,后面补上
    //计算h 用的最小二乘法 h = (A的转置*A)^-1 *A的转置*b
    MatrixXd h = (A_t*A).inverse() * A_t * b;
    //cout << h.rows() << " " << h.cols() << endl;
    float H[9]; // 用来存储变换矩阵的9个值
    for (int i = 0; i < 8; i++) {
        if (h(i, 0) > -0.000001 && h(i, 0) < 0.000001) // 一些精度问题
            H[i] = 0;
        else
            H[i] = h(i, 0);
    }
    H[8] = 1; // 不能忘记第九个参数
    CImg<float> img_(2100, 2970, 1, 3); //预设结果图
    cimg_forXY(img_, x, y) {
        //根据公式计算透视变换 这里采用后向,可以避免一些映射问题
        float srcx = H[0] * x + H[1] * y + H[2];
        float srcy = H[3] * x + H[4] * y + H[5];
        float srcw = H[6] * x + H[7] * y + H[8];
        int u = srcx / srcw; 
        int v = srcy / srcw;
        img_(x, y, 0) = img(u, v, 0);
        img_(x, y, 1) = img(u, v, 1);
        img_(x, y, 2) = img(u, v, 2);
    }
    //img_.display("result");
    img_.save("res.bmp");
    system("pause");
    return 0;
}


图像变形:

这里写图片描述
主要用了特征线来完成,算法如下:
这里写图片描述
这里写图片描述
简单来说就是根据算出X’和P’Q’的关系u和v,根据u和v和PQ算出X的位置。
但要做到多个特征线变换才有“意义”,需要算出每个特征线对应的X位置,并且保存一个对应的权重用于最后确定X具体的位置,如下:
这里写图片描述
这里a,b,p是参数,参考别的测试结果认为a = 1, b = 2, p = 0效果比较好,可以根据自己测试改。


我的测试结果如下
其中一帧:
这里写图片描述
动图:
这里写图片描述

代码核心部分:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值