#include <opencv2/opencv.hpp>
#include <opencv2/calib3d.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
// 投影矩阵结构体
struct ProjectionMatrix {
double data[3][4];
};
// 读取投影矩阵
ProjectionMatrix readProjectionMatrix1() {
ProjectionMatrix P;
P.data[0][0] = 5526.4864457012472; P.data[0][1] = 6363.7183421283298;
P.data[0][2] = -4131.0482340017224; P.data[0][3] = -24448406087.578186;
P.data[1][0] = 6172.8397894815880; P.data[1][1] = -5588.8214670529014;
P.data[1][2] = -3384.5650572725663; P.data[1][3] = 15591209748.279184;
P.data[2][0] = -0.0319353657001; P.data[2][1] = 0.0213700694115;
P.data[2][2] = -0.9992614535500; P.data[2][3] = -54202.4500385644710;
return P;
}
ProjectionMatrix readProjectionMatrix2() {
ProjectionMatrix P;
P.data[0][0] = 5544.3514690660313; P.data[0][1] = 6327.0017140488953;
P.data[0][2] = -4163.3807394948353; P.data[0][3] = -24333678727.601723;
P.data[1][0] = 6125.8241039199602; P.data[1][1] = -5628.1100012630295;
P.data[1][2] = -3404.8221606458665; P.data[1][3] = 15747662227.637783;
P.data[2][0] = -0.0362355312611; P.data[2][1] = 0.0203282471373;
P.data[2][2] = -0.9991365015065; P.data[2][3] = -48380.1370322157820;
return P;
}
// 分解投影矩阵获取相机参数
void decomposeProjectionMatrix(const Mat& P, Mat& K, Mat& R, Mat& t) {
// 分解P = K[R|t]
Mat M = P(Rect(0, 0, 3, 3));
Mat K_temp, R_temp;
RQDecomp3x3(M, K_temp, R_temp);
// 归一化内参矩阵
K_temp = K_temp / K_temp.at<double>(2, 2);
K_temp.copyTo(K);
R_temp.copyTo(R);
// 计算平移向量 t = K^{-1} * P的第4列
Mat P4 = P.col(3);
t = K.inv() * P4;
}
// 计算相机中心(Kop, Rop)
Point3d computeCameraCenter(const Mat& R, const Mat& t) {
// 相机中心 C = -R^T * t
Mat C = -R.t() * t;
return Point3d(C.at<double>(0), C.at<double>(1), C.at<double>(2));
}
// 提取图像角点并计算新坐标系
void calculateNewCoordinateSystem(const Mat& img, const Mat& mapx, const Mat& mapy,
vector<Point2f>& newCorners, Rect& boundingRect) {
// 原始图像的四个角点
vector<Point2f> originalCorners = {
Point2f(0, 0),
Point2f(img.cols, 0),
Point2f(img.cols, img.rows),
Point2f(0, img.rows)
};
// 计算校正后的角点位置
perspectiveTransform(originalCorners, newCorners,
getPerspectiveTransform(originalCorners, originalCorners));
// 计算边界框
vector<Point2f> mappedCorners;
for (const auto& corner : originalCorners) {
float x = mapx.at<float>(corner.y, corner.x);
float y = mapy.at<float>(corner.y, corner.x);
mappedCorners.push_back(Point2f(x, y));
}
// 计算包围盒
float minX = FLT_MAX, maxX = FLT_MIN;
float minY = FLT_MAX, maxY = FLT_MIN;
for (const auto& pt : mappedCorners) {
minX = min(minX, pt.x);
maxX = max(maxX, pt.x);
minY = min(minY, pt.y);
maxY = max(maxY, pt.y);
}
boundingRect = Rect(floor(minX), floor(minY),
ceil(maxX - minX), ceil(maxY - minY));
}
int main() {
// 输入文件路径
string img1_path = "D:/data1/data1/017ER030.tif";
string img2_path = "D:/data1/data1/017ER031.tif";
string output_dir = "D:/data1/shuchu/";
// 读取图像(保持原始位深)
cout << "加载图像..." << endl;
Mat img1 = imread(img1_path, IMREAD_ANYCOLOR | IMREAD_ANYDEPTH);
Mat img2 = imread(img2_path, IMREAD_ANYCOLOR | IMREAD_ANYDEPTH);
if (img1.empty() || img2.empty()) {
cerr << "错误: 无法加载图像!" << endl;
return -1;
}
Size originalSize = img1.size();
cout << "原始图像尺寸: " << originalSize << endl;
// 读取投影矩阵
ProjectionMatrix P1_struct = readProjectionMatrix1();
ProjectionMatrix P2_struct = readProjectionMatrix2();
Mat P1(3, 4, CV_64F);
Mat P2(3, 4, CV_64F);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
P1.at<double>(i, j) = P1_struct.data[i][j];
P2.at<double>(i, j) = P2_struct.data[i][j];
}
}
// ==================== 1. 分解投影矩阵 ====================
cout << "\n==== 分解投影矩阵 ====" << endl;
Mat K1, R1, t1, K2, R2, t2;
decomposeProjectionMatrix(P1, K1, R1, t1);
decomposeProjectionMatrix(P2, K2, R2, t2);
cout << "相机1内参矩阵K1:\n" << K1 << endl;
cout << "相机1旋转矩阵R1:\n" << R1 << endl;
cout << "相机1平移向量t1:\n" << t1 << endl;
// ==================== 2. 计算相机中心 ====================
Point3d C1 = computeCameraCenter(R1, t1);
Point3d C2 = computeCameraCenter(R2, t2);
cout << "\n相机1中心(Kop1): (" << C1.x << ", " << C1.y << ", " << C1.z << ")" << endl;
cout << "相机2中心(Kop2): (" << C2.x << ", " << C2.y << ", " << C2.z << ")" << endl;
// ==================== 3. 计算相对位姿 ====================
Mat rel_R = R2 * R1.t();
Mat rel_t = t2 - rel_R * t1;
// ==================== 4. 立体校正 ====================
cout << "\n==== 立体校正 ====" << endl;
Mat R1_rect, R2_rect, P1_rect, P2_rect, Q;
Rect validRoi[2];
stereoRectify(K1, noArray(), K2, noArray(), originalSize,
rel_R, rel_t, R1_rect, R2_rect, P1_rect, P2_rect, Q,
CALIB_ZERO_DISPARITY, 0, Size(0, 0), &validRoi[0], &validRoi[1]);
// 生成校正映射
Mat map1x, map1y, map2x, map2y;
initUndistortRectifyMap(K1, noArray(), R1_rect, P1_rect, originalSize,
CV_32FC1, map1x, map1y);
initUndistortRectifyMap(K2, noArray(), R2_rect, P2_rect, originalSize,
CV_32FC1, map2x, map2y);
// ==================== 5. 角点提取与坐标系重建 ====================
cout << "\n==== 角点提取与坐标系重建 ====" << endl;
vector<Point2f> corners1, corners2;
Rect rect1, rect2;
calculateNewCoordinateSystem(img1, map1x, map1y, corners1, rect1);
calculateNewCoordinateSystem(img2, map2x, map2y, corners2, rect2);
// 计算统一的新坐标系边界
Rect unifiedRect = rect1 | rect2;
cout << "新坐标系边界: x=" << unifiedRect.x << " y=" << unifiedRect.y
<< " 宽度=" << unifiedRect.width << " 高度=" << unifiedRect.height << endl;
// ==================== 6. 生成核线影像 ====================
cout << "\n==== 生成核线影像 ====" << endl;
// 调整映射到新坐标系
Mat new_map1x = map1x - unifiedRect.x;
Mat new_map1y = map1y - unifiedRect.y;
Mat new_map2x = map2x - unifiedRect.x;
Mat new_map2y = map2y - unifiedRect.y;
// 应用校正映射
Mat rectified1, rectified2;
remap(img1, rectified1, new_map1x, new_map1y, INTER_LINEAR);
remap(img2, rectified2, new_map2x, new_map2y, INTER_LINEAR);
// 裁剪到新坐标系
Mat final1 = rectified1(unifiedRect);
Mat final2 = rectified2(unifiedRect);
// 保存结果
imwrite(output_dir + "rectified_left.tif", final1);
imwrite(output_dir + "rectified_right.tif", final2);
// ==================== 7. 结果可视化 ====================
// 创建水平拼接图像
Mat canvas;
hconcat(final1, final2, canvas);
// 绘制核线
for (int i = 0; i < canvas.rows; i += 30) {
line(canvas, Point(0, i), Point(canvas.cols, i), Scalar(0, 255, 0), 1);
}
// 显示并保存结果
imshow("核线影像", canvas);
imwrite(output_dir + "epipolar_result.jpg", canvas);
waitKey(0);
cout << "\n==== 处理完成 ====" << endl;
cout << "核线影像已保存至: " << output_dir << endl;
return 0;
}
这是你刚刚给我的代码,运行过程中出现了红X
最新发布