diff --git a/main.cpp b/main.cpp index a4e7300..e4468a9 100644 --- a/main.cpp +++ b/main.cpp @@ -116,6 +116,7 @@ int main(int, char**) //FILE* file = fopen("/home/wang/data62/729dataset/ir_1280_1024_para40_y16/5.xraw","rb"); GaussianRandom gr(0.0, 1, 0.0); + for (size_t i = 0; i < 600; i++) { @@ -186,37 +187,28 @@ int main(int, char**) << info.servoInfo.fServoAz << " " << info.servoInfo.fServoPt << std::endl; - // 基于地理系的拼接 - //stitcher->GeoStitch(frame,info); + // 基于外参的快拼 + // stitcher->GeoStitch(frame,info); // 基于地理+BA拼接 - auto nNum = stitcher->BAStitch(frame,info); + //auto nNum = stitcher->BAStitch(frame,info); // test接口 - //if (info.nFrmID == 30 || info.nFrmID == 40) - { - //auto a = stitcher->ReceiveFrame(frame,info); - } - - //stitcher->ProcFrame(); + auto a = stitcher->ReceiveFrame(frame,info); - //cout << nNum << endl; - - //imshow("src", mat_src); - //waitKey(1); } - imshow("pan", mat_pan); - waitKey(1); - } + } - // 读入所有帧,执行一次全局BA - stitcher->BAOpt(); + // 处理帧 + stitcher->ProcessFrame(); + imshow("pan", mat_pan); + waitKey(0); //waitKey(0); diff --git a/stitch/src/API_VideoStitch.h b/stitch/src/API_VideoStitch.h index eac4426..d736ceb 100644 --- a/stitch/src/API_VideoStitch.h +++ b/stitch/src/API_VideoStitch.h @@ -28,17 +28,23 @@ public: // 几何校正快拼 virtual BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; + // 缓存接收帧 + virtual SINT32 ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; + // 处理帧 + virtual SINT32 ProcessFrame() = 0; - // 基于特征点拼接,全局光束平差方法,分为更新和优化调整两个接口 - virtual SINT32 BAStitch(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; - virtual SINT32 BAOpt() = 0; // 获取全景图 virtual GD_VIDEO_FRAME_S ExportPanAddr() = 0; - virtual SINT32 ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; + + + // 基于特征点拼接,全局光束平差方法,分为更新和优化调整两个接口 + virtual SINT32 BAStitch(GD_VIDEO_FRAME_S img, FrameInfo para) = 0; + virtual SINT32 BAOpt() = 0; + public: diff --git a/stitch/src/Arith_BAModule.cpp b/stitch/src/Arith_BAModule.cpp new file mode 100644 index 0000000..894187f --- /dev/null +++ b/stitch/src/Arith_BAModule.cpp @@ -0,0 +1,15 @@ +#include "Arith_BAModule.h" + +BA_Module::BA_Module(FileCache* cache) +{ + _cache = cache; +} + +BA_Module::~BA_Module() +{ +} + +bool BA_Module::updateCacheH(KeyType Key, cv::Mat H) +{ + return false; +} diff --git a/stitch/src/Arith_BAModule.h b/stitch/src/Arith_BAModule.h new file mode 100644 index 0000000..7f938f2 --- /dev/null +++ b/stitch/src/Arith_BAModule.h @@ -0,0 +1,32 @@ +// 全局BA +/*********版权所有(C)2025,武汉高德红外股份有限公司*************************************** +* 文件名称: Arith_BAProc.h +* 文件标识:BA +* 内容摘要:光束平差 +* 其它说明: +* 当前版本:V0.5 +* 创建作者:04046wcw +* 创建日期:2025/01/15 +* 包含关系: +*****************************************************************************************/ + +#pragma once + +#include "FileCache.h" + + +class BA_Module +{ +public: + BA_Module(FileCache* cache); + ~BA_Module(); + + +public: + + // 更新缓存中的帧H矩阵,并存储 + bool updateCacheH(KeyType Key, cv::Mat H); + +private: + FileCache* _cache; +}; diff --git a/stitch/src/Arith_BATask.cpp b/stitch/src/Arith_BATask.cpp index b5c6a51..32e6dda 100644 --- a/stitch/src/Arith_BATask.cpp +++ b/stitch/src/Arith_BATask.cpp @@ -95,7 +95,6 @@ SINT32 BA_Task::addFrame(GD_VIDEO_FRAME_S img, FrameInfo para) _paraVec.push_back(para); // 缓存初始H - //Proj t_Proj = _GeoStitcher->AnlayseTform(para); auto H = _GeoStitcher->findHomography(para); _origMatrix.push_back(H.clone()); _currMatrix.push_back(H.clone()); @@ -114,10 +113,10 @@ SINT32 BA_Task::addFrame(GD_VIDEO_FRAME_S img, FrameInfo para) return _imgVec.size(); } -void BA_Task::setPanPara(PanInfo info) -{ - _panPara = info; -} +//void BA_Task::setPanPara(PanInfo info) +//{ +// _panPara = info; +//} @@ -126,7 +125,7 @@ void BA_Task::setPanPara(PanInfo info) void BA_Task::optimizeBA(cv::Mat H_pan) { - remap(_origMatrix, H_pan, "_origMatrix"); + //remap(_origMatrix, H_pan, "_origMatrix"); // 计算匹配性矩阵 CalMatchMat(0.3); diff --git a/stitch/src/Arith_BATask.h b/stitch/src/Arith_BATask.h index 29c8d48..48646dc 100644 --- a/stitch/src/Arith_BATask.h +++ b/stitch/src/Arith_BATask.h @@ -18,9 +18,6 @@ using cv::Mat_; - - - class BA_Task { public: @@ -30,10 +27,6 @@ public: // 加入优化帧 SINT32 addFrame(GD_VIDEO_FRAME_S img, FrameInfo para); - // 设置全景参数 - void setPanPara(PanInfo info); - - // BA优化 void optimizeBA(cv::Mat H_pan); @@ -46,7 +39,7 @@ private: private: GeoSolver* _GeoStitcher;//外参计算 FeatureMatcher* _FeaMatcher;//特征匹配 - PanInfo _panPara;//全景图配置 + private: Mat_ _MatchMat;//配准点邻接表 diff --git a/stitch/src/Arith_VideoStitch.cpp b/stitch/src/Arith_VideoStitch.cpp index 726a8b5..7922b06 100644 --- a/stitch/src/Arith_VideoStitch.cpp +++ b/stitch/src/Arith_VideoStitch.cpp @@ -2,6 +2,7 @@ #include "Arith_VideoStitch.h" #include "Arith_Utils.h" #include "Arith_CoordModule.h" +#include "Arith_FeaMatch.h" #include #include @@ -26,9 +27,13 @@ VideoStitch::VideoStitch(SINT32 nWidth, SINT32 nHeight) _BATask = new BA_Task(_GeoSolver); - _cache = new FileCache(5,"./cache"); + _FeaMatcher = new FeatureMatcher(DetectorType::SIFT, MatcherType::FLANN); + + _cache = new FileCache(50,"./cache"); _panPara = { 0 }; + + _totalFrameCnt = 0; } VideoStitch::~VideoStitch() @@ -51,11 +56,11 @@ PanInfo VideoStitch::InitMap(FrameInfo info) PanInfo panPara = { 0 }; panPara.m_pan_width = 1000;//全景宽 panPara.m_pan_height = 1000;//全景高 - panPara.scale = 1;//比例尺,1m = ?pix + panPara.scale = 0.3;//比例尺,1m = ?pix // 直接无平移解算 - _H_pan = getAffineFromGeo2Pan(panPara); - auto cur = warpPointWithH(_H_pan, ct_geo); + cv::Mat H_0 = getAffineFromGeo2Pan(panPara); + auto cur = warpPointWithH(H_0, ct_geo); // 计算平移到全景图固定点的平移量,从此处开始拼接 int planX = 200; @@ -64,20 +69,21 @@ PanInfo VideoStitch::InitMap(FrameInfo info) panPara.map_shiftX = planX - (cur.x);//平移X panPara.map_shiftY = planY - (cur.y);//平移Y + // 获取全景图的投影矩阵,全景图配置更新前保持不变 + _H_pan = getAffineFromGeo2Pan(panPara); + + return panPara; } -void VideoStitch::Test() -{ -} PanInfo VideoStitch::Init(FrameInfo info) { _panPara = InitMap(info); - _BATask->setPanPara(_panPara); + //_BATask->setPanPara(_panPara); _pan = cv::Mat::zeros(_panPara.m_pan_height, _panPara.m_pan_width, CV_8UC1); @@ -140,14 +146,10 @@ PanInfo VideoStitch::Init(FrameInfo info) BYTE8 VideoStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) { - // uv2Geo H cv::Mat H1 = _GeoSolver->findHomography(para); - // Geo2Pan H - cv::Mat H2 = getAffineFromGeo2Pan(_panPara); - - cv::Mat H = H2 * H1; + cv::Mat H = _H_pan * H1; // 利用H投影当前帧到全景 cv::Mat imagetmp(_pan.size(), CV_8UC3, cv::Scalar(0, 0, 0)); @@ -166,10 +168,7 @@ BYTE8 VideoStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) SINT32 VideoStitch::BAStitch(GD_VIDEO_FRAME_S img, FrameInfo para) { - SINT32 nFrameCnt = _BATask->addFrame(img,para); - - return 0; } @@ -180,10 +179,7 @@ SINT32 VideoStitch::BAOpt() } SINT32 VideoStitch::ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) -{ - cout << "recv:" << para.nFrmID << endl; - - +{ // 构造单帧缓存 auto _t_frame_cache = std::make_shared(); @@ -204,12 +200,101 @@ SINT32 VideoStitch::ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) // 深拷贝图像数据 memcpy(_t_frame_cache->_data,img.u64VirAddr[0],imgSize); - // 加入文件缓存 + // 提取特征点 + std::vector keypoints; + cv::Mat descriptors; + _FeaMatcher->extractFeatures(cv::Mat(img.u32Height, img.u32Width,CV_8UC1, _t_frame_cache->_data), keypoints, descriptors); + + size_t keyNum = MIN(keypoints.size(), FEA_NUM_MAX); + // 保存特征点 + memcpy(_t_frame_cache->_pt, keypoints.data(), sizeof(cv::KeyPoint) * keyNum); + + // 保存描述子 + memcpy(_t_frame_cache->_desp, descriptors.data, sizeof(float) * keyNum * FEA_DES_SIZE); + + cv::Mat_ H0 = _GeoSolver->findHomography(para); + + // 保存初始H + memcpy(_t_frame_cache->H, H0.data, sizeof(double) * 9); + + + // 预处理结果加入文件缓存 _cache->set(para.nFrmID,_t_frame_cache); + _totalFrameCnt++; + + return _totalFrameCnt; +} + +SINT32 VideoStitch::ProcessFrame() +{ + vector vec; + + + vec.push_back(10); + vec.push_back(20); + //vec.push_back(50); + //vec.push_back(70); + vec.push_back(120); + vec.push_back(220); + //vec.push_back(320); + //vec.push_back(420); + //vec.push_back(520); + + mapFrame(vec); + + return SINT32(); } +void VideoStitch::mapFrame(vector frameInd) +{ + // 从文件缓存获取帧 + auto _t_frame_cache = std::make_shared(); + for (size_t i = 0; i < frameInd.size(); i++) + { + KeyType key = frameInd[i]; + bool flag = _cache->get(key, _t_frame_cache); + + if (!flag) + { + continue; + } + + // 读取当前H + cv::Mat H1 = cv::Mat(3,3,CV_64FC1,_t_frame_cache->H); + + // 与全景图的H相乘 + cv::Mat H = _H_pan * H1; + + // 利用H投影当前帧到全景 + cv::Mat imagetmp(_pan.size(), CV_8UC3, cv::Scalar(0, 0, 0)); + + // 获取图像数据 + cv::Mat src(_t_frame_cache->_frame_info.u32Height, _t_frame_cache->_frame_info.u32Width, CV_8UC1, + _t_frame_cache->_data); + + cv::warpPerspective(src, imagetmp, H, imagetmp.size()); + + cv::Mat mask = cv::Mat::ones(src.size(), CV_8UC1) * 255; + cv::Mat warped_mask; + cv::warpPerspective(mask, warped_mask, H, imagetmp.size()); + imagetmp.copyTo(_pan, warped_mask); + + + + + } + + +} + +void VideoStitch::OptFrame(vector frameInd) +{ + + +} + GD_VIDEO_FRAME_S VideoStitch::ExportPanAddr() { diff --git a/stitch/src/Arith_VideoStitch.h b/stitch/src/Arith_VideoStitch.h index 2dea4cb..4284d5c 100644 --- a/stitch/src/Arith_VideoStitch.h +++ b/stitch/src/Arith_VideoStitch.h @@ -12,33 +12,44 @@ public: VideoStitch(SINT32 nWidth, SINT32 nHeight); ~VideoStitch(); - void Test(); - PanInfo Init(FrameInfo info); - PanInfo InitMap(FrameInfo info); + BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para); // 接收帧 SINT32 ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para); + + // 处理帧 + SINT32 ProcessFrame(); + + + // 投影显示 + void mapFrame(vector frameInd); + + // 优化帧 + void OptFrame(vector frameInd); + public: - BYTE8 GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para); + SINT32 BAStitch(GD_VIDEO_FRAME_S img, FrameInfo para); SINT32 BAOpt(); - GD_VIDEO_FRAME_S ExportPanAddr(); private: - - FileCache* _cache;//文件缓存,存储外部传入的原始帧信息以及预处理结果 + + PanInfo InitMap(FrameInfo info); + + + FileCache* _cache;//文件缓存,存储外部传入的原始帧信息以及预处理结果 private: GeoSolver* _GeoSolver;//外参计算 - + FeatureMatcher* _FeaMatcher;//特征匹配 BA_Task* _BATask;//BA @@ -48,6 +59,8 @@ private: cv::Mat getAffineFromGeo2Pan(PanInfo _pan);//计算全景图投影,从地理系到全景地图,统一计算 - cv::Mat _pan; + + int _totalFrameCnt;//处理帧计数 + }; \ No newline at end of file diff --git a/stitch/src/FileCache.cpp b/stitch/src/FileCache.cpp deleted file mode 100644 index 274631c..0000000 --- a/stitch/src/FileCache.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "FileCache.h" -#include -#include -#include - -namespace fs = std::filesystem; - -// 计算哈希值并转成字符串作为文件名 -static std::string hashKey(const KeyType& key) -{ - std::hash hasher; - return std::to_string(hasher(key)); -} - -FileCache::FileCache(size_t max_size, const std::string& cache_dir) - : max_size_(max_size), cache_dir_(cache_dir) -{ - // 确保缓存目录存在 - if (!fs::exists(cache_dir_)) - { - fs::create_directories(cache_dir_); - } -} - -std::string FileCache::getCacheFilePath(const KeyType& key) const -{ - return cache_dir_ + "/" + hashKey(key) + ".cache"; // 使用哈希作为文件名 -} - -void FileCache::saveToFile(const KeyType& key, const FrameCache& frame) -{ - std::string filePath = getCacheFilePath(key); - std::ofstream ofs(filePath, std::ios::binary); - if (ofs) - { - ofs.write(reinterpret_cast(&frame), sizeof(frame)); - } -} - -bool FileCache::loadFromFile(const KeyType& key, FrameCache& frame) -{ - std::string filePath = getCacheFilePath(key); - std::ifstream ifs(filePath, std::ios::binary); - if (!ifs) - { - return false; - } - ifs.read(reinterpret_cast(&frame), sizeof(frame)); - return true; -} - -void FileCache::evictIfNeeded() -{ - if (cache_.size() < max_size_) - return; - - // 删除最早使用的(LRU 末尾) - KeyType oldest = lru_list_.back(); - lru_list_.pop_back(); - cache_.erase(oldest); - - std::cout << "Evicted cache from memory for key: " << oldest << std::endl; -} - -bool FileCache::get(const KeyType& key, std::shared_ptr& pData) -{ - std::lock_guard lock(mutex_); - - // 检查内存缓存 - auto it = cache_.find(key); - if (it != cache_.end()) - { - // 缓存命中,更新 LRU 顺序 - lru_list_.erase(it->second.second); - lru_list_.push_front(key); - it->second.second = lru_list_.begin(); - - pData = it->second.first; - return true; - } - - // 尝试从文件加载 - auto newData = std::make_shared(); - if (loadFromFile(key, *newData)) - { - evictIfNeeded(); // 超出内存容量时删除最早的 - - // 插入新缓存到内存 - lru_list_.push_front(key); - cache_[key] = {newData, lru_list_.begin()}; - pData = newData; - return true; - } - - return false; -} - -void FileCache::set(const KeyType& key, std::shared_ptr pData) -{ - std::lock_guard lock(mutex_); - - // 如果已存在,则更新 LRU 位置 - auto it = cache_.find(key); - if (it != cache_.end()) - { - lru_list_.erase(it->second.second); - } - else - { - evictIfNeeded(); // 超出内存容量时删除最早的 - } - - // 插入新数据到内存 - lru_list_.push_front(key); - cache_[key] = {pData, lru_list_.begin()}; - - saveToFile(key, *pData); // 将数据存储到磁盘 -} - -size_t FileCache::getMemSize() -{ - std::lock_guard lock(mutex_); - return cache_.size(); -} diff --git a/stitch/src/FileCache.h b/stitch/src/FileCache.h index 31e671b..81f0730 100644 --- a/stitch/src/FileCache.h +++ b/stitch/src/FileCache.h @@ -12,27 +12,160 @@ // using KeyType = int; - +template class FileCache { public: explicit FileCache(size_t max_size, const std::string& cache_dir = "./cache"); - bool get(const KeyType& key, std::shared_ptr& pData); - void set(const KeyType& key, std::shared_ptr pData); + bool get(const KeyType& key, std::shared_ptr& pData); + void set(const KeyType& key, std::shared_ptr pData); size_t getMemSize(); private: size_t max_size_; std::string cache_dir_; - std::unordered_map, std::list::iterator>> cache_; + std::unordered_map, std::list::iterator>> cache_; std::list lru_list_; std::mutex mutex_; - bool loadFromFile(const KeyType& key, FrameCache& frame); - void saveToFile(const KeyType& key, const FrameCache& frame); + bool loadFromFile(const KeyType& key, T& frame); + void saveToFile(const KeyType& key, const T& frame); void evictIfNeeded(); std::string getCacheFilePath(const KeyType& key) const; }; + + +namespace fs = std::filesystem; + +// 计算哈希值并转成字符串作为文件名 +static std::string hashKey(const KeyType& key) +{ + std::hash hasher; + return std::to_string(hasher(key)); +} + +template +FileCache::FileCache(size_t max_size, const std::string& cache_dir) + : max_size_(max_size), cache_dir_(cache_dir) +{ + // 确保缓存目录存在 + if (!fs::exists(cache_dir_)) + { + fs::create_directories(cache_dir_); + } +} + +template +std::string FileCache::getCacheFilePath(const KeyType& key) const +{ + return cache_dir_ + "/" + hashKey(key) + ".cache"; // 使用哈希作为文件名 +} + +template +void FileCache::saveToFile(const KeyType& key, const T& frame) +{ + std::string filePath = getCacheFilePath(key); + + if (fs::exists(filePath)) + { + int a = 0; + } + std::ofstream ofs(filePath, std::ios::binary); + if (ofs) + { + ofs.write(reinterpret_cast(&frame), sizeof(frame)); + } +} + +template +bool FileCache::loadFromFile(const KeyType& key, T& frame) +{ + std::string filePath = getCacheFilePath(key); + std::ifstream ifs(filePath, std::ios::binary); + if (!ifs) + { + return false; + } + ifs.read(reinterpret_cast(&frame), sizeof(frame)); + return true; +} + +template +void FileCache::evictIfNeeded() +{ + if (cache_.size() < max_size_) + return; + + // 删除最早使用的(LRU 末尾) + KeyType oldest = lru_list_.back(); + lru_list_.pop_back(); + cache_.erase(oldest); + + std::cout << "Evicted cache from memory for key: " << oldest << std::endl; +} + +template +bool FileCache::get(const KeyType& key, std::shared_ptr& pData) +{ + std::lock_guard lock(mutex_); + + // 检查内存缓存 + auto it = cache_.find(key); + if (it != cache_.end()) + { + // 缓存命中,更新 LRU 顺序 + lru_list_.erase(it->second.second); + lru_list_.push_front(key); + it->second.second = lru_list_.begin(); + + pData = it->second.first; + return true; + } + + // 尝试从文件加载 + auto newData = std::make_shared(); + if (loadFromFile(key, *newData)) + { + evictIfNeeded(); // 超出内存容量时删除最早的 + + // 插入新缓存到内存 + lru_list_.push_front(key); + cache_[key] = { newData, lru_list_.begin() }; + pData = newData; + return true; + } + + return false; +} +template +void FileCache::set(const KeyType& key, std::shared_ptr pData) +{ + std::lock_guard lock(mutex_); + + // 如果已存在,则更新 LRU 位置 + auto it = cache_.find(key); + if (it != cache_.end()) + { + lru_list_.erase(it->second.second); + } + else + { + evictIfNeeded(); // 超出内存容量时删除最早的 + } + + // 插入新数据到内存 + lru_list_.push_front(key); + cache_[key] = { pData, lru_list_.begin() }; + + saveToFile(key, *pData); // 将数据存储到磁盘 +} + +template +size_t FileCache::getMemSize() +{ + std::lock_guard lock(mutex_); + return cache_.size(); +} diff --git a/stitch/src/StitchStruct.h b/stitch/src/StitchStruct.h index 48daa76..ae6a95c 100644 --- a/stitch/src/StitchStruct.h +++ b/stitch/src/StitchStruct.h @@ -51,6 +51,8 @@ struct FrameCache FrameInfo _para; GD_VIDEO_FRAME_S _frame_info; BYTE8 _data[IMG_CACHE_SIZE]; - cv::Point2f _pt[FEA_NUM_MAX]; + cv::KeyPoint _pt[FEA_NUM_MAX]; FLOAT32 _desp[FEA_NUM_MAX * FEA_DES_SIZE]; + + DOUBLE64 H[9];// H矩阵 }; \ No newline at end of file