几何校正是指遥感成像过程中,受多种因素的综合影响,原始图像上地物的几何位置、形状、大小、尺寸、方位等特征与其对应的地面地物的特征往往是不一致的,这种不一致就是几何变形,也称几何畸变。
几何校正是遥感中的专业名词。一般是指通过一系列的数学模型来改正和消除遥感影像成像时因摄影材料变形、物镜畸变、大气折光、地球曲率、地球自转、地形起伏等因素导致的原始图像上各地物的几何位置、形状、尺寸、方位等特征与在参照系统中的表达要求不一致时产生的变形。
———— 百度百科
参考博客:https://blog.csdn.net/weixin_37195422/article/details/53930891
不过此博客未给出相应实践,所以自己实践一个
因为要使用图像处理,以及矩阵和求解线性方程组,所以需要外部库(也可以纯自己弄,不过很麻烦)
图像库:stb_image ,我的这篇博有说https://blog.csdn.net/qq_40953281/article/details/87902580
矩阵计算库:Eigen, 推荐的教程https://zzk.cnblogs.com/s?w=blog%3Ahoukai%20Eigen
这两个都是只需要导入头文件就可以,不需要配置其他的东西,简单易用
参考博客里面的图片是CSDN压缩过的了,像素信息已经改变,新参数如下
规格 383*268
x0
39 82
32 106
266 90
270 54
x1
38 55
38 100
270 100
270 55
#include
#include
#include
#include
#include
#define STB_IMAGE_IMPLEMENTATION
#include
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include
using namespace std;
using namespace Eigen;
string filePath;
int w, h, n;
const int points = 4;
vector<pair<int, int>> rectBefore; // 变换前的四边形
vector<pair<int, int>> rectAfter; // 变换后的矩形位置
Vector4d cX,cY; // x,y对于的四个参数
void copyTo(unsigned char *src, int x0, int y0, unsigned char *des, int x1, int y1) {
if ((x1 < 0 || x1 >= w) || (y1 < 0 || y1 >= h)) return; // 出界不考虑
if ((x0 < 0 || x0 >= w) || (y0 < 0 || y0 >= h)) return; // 出界不考虑
for (int i = 0; i < n; i++) {
des[w*n*y1 + n * x1 + i] = src[w*n*y0 + n * x0 + i];
}
}
pair<int,int> getPos(int x, int y) {
int x1 = cX[0] * x + cX[1] * y + cX[2] * x*y + cX[3];
int y1 = cY[0] * x + cY[1] * y + cY[2] * x*y + cY[3];
return make_pair(x1, y1);
}
int main()
{
cin >> filePath;
unsigned char *data = stbi_load(filePath.c_str(), &w, &h, &n, 0);
unsigned char *copy = NULL;
if (data == NULL) {
cout << stbi_failure_reason() << endl;
}
else {
// 复制一份变换用
copy = (unsigned char*)malloc(w*n*h);
memset(copy, 0, w*n*h);
// 获取变换前坐标
for (int i = 0; i < points; i++) {
int x, y; cin >> x >> y;
rectBefore.push_back(make_pair(x, y));
}
// 获取变换后坐标,与上一一对应
for (int i = 0; i < points; i++) {
int x, y; cin >> x >> y;
rectAfter.push_back(make_pair(x, y));
}
Matrix4d mid; // 中间矩阵
Vector4d resX, resY; // 转换后的xy坐标
for (int i = 0; i < 4; i++) {
mid(i, 0) = rectBefore[i].first;
mid(i, 1) = rectBefore[i].second;
mid(i, 2) = rectBefore[i].first*rectBefore[i].second;
mid(i, 3) = 1;
resX(i) = rectAfter[i].first;
resY(i) = rectAfter[i].second;
}
// 求解线性方程组
cX = mid.lu().solve(resX);
cY = mid.lu().solve(resY);
// 开始转换
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
pair<int, int> newPos = getPos(i, j);
copyTo(data, newPos.first, newPos.second, copy, i, j);
}
}
stbi_write_png("out.png", w, h, n, copy, 0);
stbi_image_free(data);
free(copy);
}
system("pause");
return 0;
}