wangchongwu 5 months ago
parent 24220189b7
commit 72b2d2e155

@ -101,15 +101,13 @@ int main(int, char**)
fread(pFrameIR,2,IMAGE_WIDTH_IR*(IMAGE_HEIGHT_IR + PARA_IR_LINE),file);
if(i % 2 != 0)
{
continue;
}
S729paras_IR Paras_IR = { 0 };
memcpy(&Paras_IR, (unsigned char*)(pFrameIR + IMAGE_WIDTH_IR*IMAGE_HEIGHT_IR), sizeof(S729paras_IR));
FrameInfo info = {0};
info.nFrmID = i;
info.camInfo.nFocus = Paras_IR.Paras_IR.caminfo.nFocal;
info.camInfo.fPixelSize = Paras_IR.Paras_IR.caminfo.nPixleSize;
@ -167,7 +165,7 @@ int main(int, char**)
//<< endl;
stitcher->Updata(frame,info);
stitcher->GeoStitch(frame,info);
}

@ -15,30 +15,7 @@
#define STD_STITCH_API __attribute__ ((visibility("default")))
#endif
#include "Arith_CommonDef.h"
#include "opencv2/opencv.hpp"
#include "PlatformDefine.h"
// 帧内外方位元素
struct FrameInfo
{
AirCraftInfo craft;
CamInfo camInfo;
ServoInfo servoInfo;
int nEvHeight;//相对高差
int nWidth;
int nHeight;
};
// 全景图配置
struct PanInfo
{
int m_pan_width;
int m_pan_height;
float scale;// 比例尺
float map_shiftX;// 平移X
float map_shiftY;// 平移Y
};
#include "StitchStruct.h"
class STD_STITCH_API API_VideoStitch
{
@ -48,8 +25,11 @@ public:
// 初始化拼接
virtual PanInfo Init(FrameInfo info) = 0;
// 输入帧
virtual BYTE8 Updata(GD_VIDEO_FRAME_S img, FrameInfo para) = 0;
// 几何校正快拼
virtual BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) = 0;
// 基于特征点拼接,全局光束平差方法
virtual BYTE8 BAStitch(GD_VIDEO_FRAME_S img, FrameInfo para) = 0;
// 获取全景图
virtual GD_VIDEO_FRAME_S ExportPanAddr() = 0;

@ -1,64 +0,0 @@
#include <opencv2/opencv.hpp>
#include <iostream>
#include <map>
#include <vector>
// 定义相机节点
struct CameraNode {
int cameraId; // 相机 ID
cv::Mat R; // 旋转矩阵
cv::Mat t; // 平移向量
cv::Mat K; // 内参矩阵
};
// 定义三维点节点
struct PointNode {
int pointId; // 三维点 ID
cv::Point3f X; // 三维点坐标
};
// 定义观测边
struct ObservationEdge {
int cameraId; // 相机 ID
int pointId; // 三维点 ID
cv::Point2f x; // 观测到的二维点坐标
};
// 定义 Bundle Adjustment 图结构
class BundleAdjustmentGraph {
public:
// 添加相机节点
void addCameraNode(const CameraNode& camera) {
cameras[camera.cameraId] = camera;
}
// 添加三维点节点
void addPointNode(const PointNode& point) {
points[point.pointId] = point;
}
// 添加观测边
void addObservationEdge(const ObservationEdge& edge) {
observations.push_back(edge);
}
// 获取相机节点
CameraNode getCameraNode(int cameraId) {
return cameras[cameraId];
}
// 获取三维点节点
PointNode getPointNode(int pointId) {
return points[pointId];
}
// 获取观测边
std::vector<ObservationEdge> getObservationEdges() {
return observations;
}
private:
std::map<int, CameraNode> cameras; // 相机节点集合
std::map<int, PointNode> points; // 三维点节点集合
std::vector<ObservationEdge> observations; // 观测边集合
};

@ -0,0 +1,67 @@
#include "Arith_BATask.h"
#include "ceres/ceres.h"
using namespace ceres;
struct CostFunctor {
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = 10.0 - x[0];
return true;
}
};
BA_Task::BA_Task()
{
// 来个100帧
_imgVec.reserve(100);
}
BA_Task::~BA_Task()
{
}
SINT32 BA_Task::addFrame(GD_VIDEO_FRAME_S img, FrameInfo para)
{
// 缓存图像帧
if (img.enPixelFormat == GD_PIXEL_FORMAT_E::GD_PIXEL_FORMAT_GRAY_Y8)
{
_imgVec.emplace_back(Mat(img.u32Height, img.u32Width, CV_8UC1, img.u64VirAddr[0]));
}
return _imgVec.size();
}
void BA_Task::Test()
{
google::InitGoogleLogging("ceres");
// The variable to solve for with its initial value. It will be
// mutated in place by the solver.
double x = 0.5;
const double initial_x = x;
// Build the problem.
ceres::Problem problem;
// Set up the only cost function (also known as residual). This uses
// auto-differentiation to obtain the derivative (jacobian).
ceres::CostFunction* cost_function =
new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, nullptr, &x);
// Run the solver!
ceres::Solver::Options options;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x << " -> " << x << "\n";
}

@ -0,0 +1,44 @@
// 全局BA
/*********版权所有C2025武汉高德红外股份有限公司***************************************
* Arith_BAProc.h
* BA
*
*
* V0.5
* 04046wcw
* 2025/01/15
*
*****************************************************************************************/
#pragma once
#include "StitchStruct.h"
using cv::Mat_;
class BA_Task
{
public:
BA_Task();
~BA_Task();
SINT32 addFrame(GD_VIDEO_FRAME_S img, FrameInfo para);
void Test();
private:
Mat_<int> _similarityMat;//配准点邻接表
//超大空间考虑文件cache todo
private:
vector<cv::Mat> _imgVec;//图像缓存
vector<cv::Point2d> _FeaPtVec;//特征点缓存
};

@ -25,7 +25,7 @@ enum MatcherType
class FeatureMatcher
{
public:
// 构造函数
FeatureMatcher(DetectorType detectorType, MatcherType matcherType);

@ -1,19 +1,19 @@
#include "Arith_ExtrinsicStitcher.h"
#include "Arith_GeoStitcher.h"
#include "Arith_VideoStitch.h"
#include "Arith_Utils.h"
#include "Arith_CoordModule.h"
#include "Arith_SysStruct.h"
using namespace cv;
ExtrinsicStitcher::ExtrinsicStitcher()
GeoStitcher::GeoStitcher()
{
}
ExtrinsicStitcher::~ExtrinsicStitcher()
GeoStitcher::~GeoStitcher()
{
}
PanInfo ExtrinsicStitcher::InitMap(FrameInfo info)
PanInfo GeoStitcher::InitMap(FrameInfo info)
{
// 设置拼接原点
SetOriginPoint(info);
@ -45,14 +45,14 @@ PanInfo ExtrinsicStitcher::InitMap(FrameInfo info)
cv::Point2f ExtrinsicStitcher::project(cv::Point2f pos_pan, Proj m_Proj, PanInfo pan)
cv::Point2f GeoStitcher::project(cv::Point2f pos_pan, Proj m_Proj, PanInfo pan)
{
cv::Point2f pos_geo = Trans_pan2Geo(pos_pan, pan);
cv::Point2f pos_frame = Trans_Geo2uv(pos_geo, m_Proj.tf_g2p);
return pos_frame;
}
cv::Point2f ExtrinsicStitcher::back_project(cv::Point2f pos_frame, Proj m_Proj, PanInfo pan)
cv::Point2f GeoStitcher::back_project(cv::Point2f pos_frame, Proj m_Proj, PanInfo pan)
{
cv::Point2f pos_geo = Trans_uv2Geo(pos_frame, m_Proj.tf_p2g);
@ -61,12 +61,12 @@ cv::Point2f ExtrinsicStitcher::back_project(cv::Point2f pos_frame, Proj m_Proj,
return pos_pan;
}
void ExtrinsicStitcher::SetOriginPoint(FrameInfo info)
void GeoStitcher::SetOriginPoint(FrameInfo info)
{
originPoint = getXYZFromBLH(info.craft.stPos);
}
cv::Point2f ExtrinsicStitcher::Trans_uv2Geo(cv::Point2f pos_frame, TForm form)
cv::Point2f GeoStitcher::Trans_uv2Geo(cv::Point2f pos_frame, TForm form)
{
Mat point = (Mat_<double>(3, 1) << pos_frame.x, pos_frame.y, 1);
Mat result = form.R * point;
@ -80,7 +80,7 @@ cv::Point2f ExtrinsicStitcher::Trans_uv2Geo(cv::Point2f pos_frame, TForm form)
return cv::Point2f(warpedX, warpedY);
}
cv::Point2f ExtrinsicStitcher::Trans_Geo2uv(cv::Point2f pos_geo, TForm form_inv)
cv::Point2f GeoStitcher::Trans_Geo2uv(cv::Point2f pos_geo, TForm form_inv)
{
// 先平移到当前相机位置
cv::Point2f pos_cam = pos_geo;
@ -97,7 +97,7 @@ cv::Point2f ExtrinsicStitcher::Trans_Geo2uv(cv::Point2f pos_geo, TForm form_inv)
return cv::Point2f(warpedX, warpedY);
}
cv::Point2f ExtrinsicStitcher::Trans_pan2Geo(cv::Point2f pos_pan, PanInfo panPara)
cv::Point2f GeoStitcher::Trans_pan2Geo(cv::Point2f pos_pan, PanInfo panPara)
{
double x = (pos_pan.x - panPara.map_shiftX) / panPara.scale;
double y = (panPara.m_pan_height - (pos_pan.y - panPara.map_shiftY)) / panPara.scale;
@ -105,7 +105,7 @@ cv::Point2f ExtrinsicStitcher::Trans_pan2Geo(cv::Point2f pos_pan, PanInfo panPar
return cv::Point2f(x, y);
}
cv::Point2f ExtrinsicStitcher::Trans_Geo2pan(cv::Point2f pos_geo, PanInfo panPara)
cv::Point2f GeoStitcher::Trans_Geo2pan(cv::Point2f pos_geo, PanInfo panPara)
{
double pan_x = pos_geo.x * panPara.scale + panPara.map_shiftX;
double pan_y = (panPara.m_pan_height - pos_geo.y * panPara.scale) + panPara.map_shiftY;
@ -114,7 +114,7 @@ cv::Point2f ExtrinsicStitcher::Trans_Geo2pan(cv::Point2f pos_geo, PanInfo panPar
Mat ExtrinsicStitcher::Mat_TransENGMove(FrameInfo info)
Mat GeoStitcher::Mat_TransENGMove(FrameInfo info)
{
PointXYZ ptCurr = getXYZFromBLH(info.craft.stPos);
PointXYZ diff = getNUEXYZFromCGCSXYZ(ptCurr, originPoint);
@ -127,7 +127,7 @@ Mat ExtrinsicStitcher::Mat_TransENGMove(FrameInfo info)
return move;
}
Mat ExtrinsicStitcher::Mat_TransENG2uv(FrameInfo info)
Mat GeoStitcher::Mat_TransENG2uv(FrameInfo info)
{
//从地理坐标系转像素坐标
@ -198,7 +198,7 @@ Mat ExtrinsicStitcher::Mat_TransENG2uv(FrameInfo info)
Proj ExtrinsicStitcher::AnlayseTform(FrameInfo info)
Proj GeoStitcher::AnlayseTform(FrameInfo info)
{
Proj projection;
// 从像方->地理
@ -213,3 +213,36 @@ Proj ExtrinsicStitcher::AnlayseTform(FrameInfo info)
}
// 计算多边形的面积
double polygonArea(const vector<cv::Point2f>& points)
{
double area = 0.0;
int n = points.size();
for (int i = 0; i < n; i++) {
int j = (i + 1) % n;
area += points[i].x * points[j].y - points[j].x * points[i].y;
}
return abs(area) / 2.0;
}
// 计算两个四边形的 IOU
double computeQuadrilateralIOU(const vector<cv::Point2f>& quad1, const vector<cv::Point2f>& quad2)
{
// 将四边形转换为多边形
vector<Point2f> poly1 = quad1;
vector<Point2f> poly2 = quad2;
// 计算交集多边形
vector<Point2f> intersectionPolygon;
intersectConvexConvex(poly1, poly2, intersectionPolygon);
// 计算面积
double area1 = polygonArea(poly1);
double area2 = polygonArea(poly2);
double intersectionArea = polygonArea(intersectionPolygon);
double unionArea = area1 + area2 - intersectionArea;
// 计算 IOU
if (unionArea == 0) return 0.0; // 避免除零错误
return intersectionArea / unionArea;
}

@ -10,9 +10,8 @@
*
*****************************************************************************************/
#pragma once
#include <opencv2/opencv.hpp>
#include "Arith_CommonDef.h"
#include "API_VideoStitch.h"
#include "StitchStruct.h"
// 像方-物方转换关系
@ -30,12 +29,15 @@ struct Proj
TForm tf_g2p;//从地理坐标系到帧的Rt矩阵
};
class ExtrinsicStitcher
class GeoStitcher
{
public:
// 构造函数
ExtrinsicStitcher();
~ExtrinsicStitcher();
GeoStitcher();
~GeoStitcher();
// 初始化地理参数和全景图参数
PanInfo InitMap(FrameInfo info);
@ -76,4 +78,10 @@ private:
void SetOriginPoint(FrameInfo info);
PointXYZ originPoint;//成图初始点的地心地固坐标,作为拼接参考
};
};
// 多边形面积
double polygonArea(const vector<cv::Point2f>& points);
// 计算两个四边形的 IOU
double computeQuadrilateralIOU(const vector<cv::Point2f>& quad1, const vector<cv::Point2f>& quad2);

@ -22,78 +22,41 @@ void API_VideoStitch::Destroy(API_VideoStitch * obj)
VideoStitch::VideoStitch(SINT32 nWidth, SINT32 nHeight)
{
m_GeoStitcher = new ExtrinsicStitcher();
_GeoStitcher = new GeoStitcher();
m_FeaMatcher = new FeatureMatcher(DetectorType::ORB, MatcherType::FLANN);
memset(&m_pan, 0, sizeof(GD_VIDEO_FRAME_S));
_FeaMatcher = new FeatureMatcher(DetectorType::ORB, MatcherType::FLANN);
memset(&_pan, 0, sizeof(GD_VIDEO_FRAME_S));
}
VideoStitch::~VideoStitch()
{
delete m_GeoStitcher;
delete _GeoStitcher;
}
#include "ceres/ceres.h"
using namespace ceres;
struct CostFunctor {
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = 10.0 - x[0];
return true;
}
};
void VideoStitch::Test()
{
google::InitGoogleLogging("ceres");
// The variable to solve for with its initial value. It will be
// mutated in place by the solver.
double x = 0.5;
const double initial_x = x;
// Build the problem.
ceres::Problem problem;
// Set up the only cost function (also known as residual). This uses
// auto-differentiation to obtain the derivative (jacobian).
ceres::CostFunction* cost_function =
new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, nullptr, &x);
// Run the solver!
ceres::Solver::Options options;
options.minimizer_progress_to_stdout = true;
ceres::Solver::Summary summary;
ceres::Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x << " -> " << x << "\n";
}
PanInfo VideoStitch::Init(FrameInfo info)
{
m_panPara = m_GeoStitcher->InitMap(info);
_panPara = _GeoStitcher->InitMap(info);
m_pan = cv::Mat::zeros(m_panPara.m_pan_height, m_panPara.m_pan_width, CV_8UC1);
_pan = cv::Mat::zeros(_panPara.m_pan_height, _panPara.m_pan_width, CV_8UC1);
return m_panPara;
return _panPara;
}
BYTE8 VideoStitch::Updata(GD_VIDEO_FRAME_S img, FrameInfo para)
BYTE8 VideoStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para)
{
Proj t_Proj = m_GeoStitcher->AnlayseTform(para);
cv::Mat frame(img.u32Height, img.u32Width, CV_8UC1, img.u64VirAddr[0]);
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
m_FeaMatcher->extractFeatures(frame, keypoints, descriptors);
Proj t_Proj = _GeoStitcher->AnlayseTform(para);
// 计算帧的map四至
cv::Point2f leftTop_map = m_GeoStitcher->back_project(cv::Point2f(0,0), t_Proj, m_panPara);
cv::Point2f rightTop_map = m_GeoStitcher->back_project(cv::Point2f(img.u32Width,0), t_Proj, m_panPara);
cv::Point2f rightBottom_map = m_GeoStitcher->back_project(cv::Point2f(img.u32Width,img.u32Height), t_Proj, m_panPara);
cv::Point2f leftBottom_map = m_GeoStitcher->back_project(cv::Point2f(0,img.u32Height), t_Proj, m_panPara);
cv::Point2f leftTop_map = _GeoStitcher->back_project(cv::Point2f(0,0), t_Proj, _panPara);
cv::Point2f rightTop_map = _GeoStitcher->back_project(cv::Point2f(img.u32Width,0), t_Proj, _panPara);
cv::Point2f rightBottom_map = _GeoStitcher->back_project(cv::Point2f(img.u32Width,img.u32Height), t_Proj, _panPara);
cv::Point2f leftBottom_map = _GeoStitcher->back_project(cv::Point2f(0,img.u32Height), t_Proj, _panPara);
// 计算全景图的范围
@ -108,9 +71,9 @@ BYTE8 VideoStitch::Updata(GD_VIDEO_FRAME_S img, FrameInfo para)
//反映射到像素坐标
int valid_top = std::max(0, top);
int valid_bottom = std::min(m_pan.cols, bottom);
int valid_bottom = std::min(_pan.cols, bottom);
int valid_left = std::max(0, left);
int valid_right = std::min(m_pan.rows, right);
int valid_right = std::min(_pan.rows, right);
#pragma omp parallel for
for (int i = valid_top; i < valid_bottom; i++)
@ -118,11 +81,11 @@ BYTE8 VideoStitch::Updata(GD_VIDEO_FRAME_S img, FrameInfo para)
for (int j = valid_left; j < valid_right; j++)
{
//转换为pixel坐标
cv::Point2f p_img = m_GeoStitcher->project(Point2f(j, i), t_Proj, m_panPara);
cv::Point2f p_img = _GeoStitcher->project(Point2f(j, i), t_Proj, _panPara);
if (p_img.x >= 0 && p_img.y >= 0 && p_img.x < img.u32Width && p_img.y < img.u32Height)
{
m_pan.data[i * m_pan.rows + j] =
_pan.data[i * _pan.rows + j] =
FourPointInterpolation(img.u64VirAddr[0], img.u32Width, img.u32Height, p_img.x, p_img.y);
}
}
@ -132,14 +95,20 @@ BYTE8 VideoStitch::Updata(GD_VIDEO_FRAME_S img, FrameInfo para)
return 0;
}
BYTE8 VideoStitch::BAStitch(GD_VIDEO_FRAME_S img, FrameInfo para)
{
return BYTE8();
}
GD_VIDEO_FRAME_S VideoStitch::ExportPanAddr()
{
GD_VIDEO_FRAME_S pan_out;
pan_out.enPixelFormat = GD_PIXEL_FORMAT_GRAY_Y8;
pan_out.u32Width = m_panPara.m_pan_width;
pan_out.u32Height = m_panPara.m_pan_height;
pan_out.u64VirAddr[0] = m_pan.data;
pan_out.u32Width = _panPara.m_pan_width;
pan_out.u32Height = _panPara.m_pan_height;
pan_out.u64VirAddr[0] = _pan.data;
return pan_out;
}

@ -1,7 +1,8 @@
#include "API_VideoStitch.h"
#include "opencv2/opencv.hpp"
#include "Arith_ExtrinsicStitcher.h"
#include "Arith_GeoStitcher.h"
#include "Arith_FeaMatch.h"
#include "StitchStruct.h"
class VideoStitch:public API_VideoStitch
{
@ -15,7 +16,9 @@ public:
public:
PanInfo Init(FrameInfo info);
BYTE8 Updata(GD_VIDEO_FRAME_S img, FrameInfo para);
BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para);
BYTE8 BAStitch(GD_VIDEO_FRAME_S img, FrameInfo para);
GD_VIDEO_FRAME_S ExportPanAddr();
private:
@ -24,13 +27,13 @@ private:
private:
ExtrinsicStitcher* m_GeoStitcher;//外参计算
GeoStitcher* _GeoStitcher;//外参计算
FeatureMatcher* m_FeaMatcher;//特征匹配
FeatureMatcher* _FeaMatcher;//特征匹配
PanInfo m_panPara;//全景图配置
cv::Mat m_pan;
PanInfo _panPara;//全景图配置
cv::Mat _pan;
};

@ -0,0 +1,41 @@
#pragma once
#include "Arith_CommonDef.h"
#include "opencv2/opencv.hpp"
#include "PlatformDefine.h"
using std::vector;
using cv::Point2d;
using cv::Point2f;
using cv::Mat;
using cv::Mat_;
// 帧内外方位元素
struct FrameInfo
{
int nFrmID;//帧编号唯一ID
AirCraftInfo craft;
CamInfo camInfo;
ServoInfo servoInfo;
int nEvHeight;//相对高差
int nWidth;
int nHeight;
};
// 全景图配置
struct PanInfo
{
int m_pan_width;
int m_pan_height;
float scale;// 比例尺
float map_shiftX;// 平移X
float map_shiftY;// 平移Y
};
// 匹配关系网BA的边
struct Match_Net
{
int imgNo; //! image no. start from 0
vector<int> relatedImgs; //! the position index of overlap-image in visitOrder
vector<vector<Point2d> > PointSet;
};
Loading…
Cancel
Save