cache改为模板类

main
wangchongwu 5 months ago
parent fdd364253d
commit a855e91aed

@ -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);

@ -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:

@ -0,0 +1,15 @@
#include "Arith_BAModule.h"
BA_Module::BA_Module(FileCache<FrameCache>* cache)
{
_cache = cache;
}
BA_Module::~BA_Module()
{
}
bool BA_Module::updateCacheH(KeyType Key, cv::Mat H)
{
return false;
}

@ -0,0 +1,32 @@
// 全局BA
/*********版权所有C2025武汉高德红外股份有限公司***************************************
* Arith_BAProc.h
* BA
*
*
* V0.5
* 04046wcw
* 2025/01/15
*
*****************************************************************************************/
#pragma once
#include "FileCache.h"
class BA_Module
{
public:
BA_Module(FileCache<FrameCache>* cache);
~BA_Module();
public:
// 更新缓存中的帧H矩阵并存储
bool updateCacheH(KeyType Key, cv::Mat H);
private:
FileCache<FrameCache>* _cache;
};

@ -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);

@ -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_<int> _MatchMat;//配准点邻接表

@ -2,6 +2,7 @@
#include "Arith_VideoStitch.h"
#include "Arith_Utils.h"
#include "Arith_CoordModule.h"
#include "Arith_FeaMatch.h"
#include <opencv2/opencv.hpp>
#include <omp.h>
@ -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<FrameCache>(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<FrameCache>();
@ -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<cv::KeyPoint> 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_<double> 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<KeyType> 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<KeyType> frameInd)
{
// 从文件缓存获取帧
auto _t_frame_cache = std::make_shared<FrameCache>();
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<KeyType> frameInd)
{
}
GD_VIDEO_FRAME_S VideoStitch::ExportPanAddr()
{

@ -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<KeyType> frameInd);
// 优化帧
void OptFrame(vector<KeyType> 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<FrameCache>* _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;//处理帧计数
};

@ -1,124 +0,0 @@
#include "FileCache.h"
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
// 计算哈希值并转成字符串作为文件名
static std::string hashKey(const KeyType& key)
{
std::hash<KeyType> 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<const char*>(&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<char*>(&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<FrameCache>& pData)
{
std::lock_guard<std::mutex> 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<FrameCache>();
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<FrameCache> pData)
{
std::lock_guard<std::mutex> 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<std::mutex> lock(mutex_);
return cache_.size();
}

@ -12,27 +12,160 @@
//
using KeyType = int;
template <typename T>
class FileCache
{
public:
explicit FileCache(size_t max_size, const std::string& cache_dir = "./cache");
bool get(const KeyType& key, std::shared_ptr<FrameCache>& pData);
void set(const KeyType& key, std::shared_ptr<FrameCache> pData);
bool get(const KeyType& key, std::shared_ptr<T>& pData);
void set(const KeyType& key, std::shared_ptr<T> pData);
size_t getMemSize();
private:
size_t max_size_;
std::string cache_dir_;
std::unordered_map<KeyType, std::pair<std::shared_ptr<FrameCache>, std::list<KeyType>::iterator>> cache_;
std::unordered_map<KeyType, std::pair<std::shared_ptr<T>, std::list<KeyType>::iterator>> cache_;
std::list<KeyType> 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<KeyType> hasher;
return std::to_string(hasher(key));
}
template <typename T>
FileCache<T>::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 <typename T>
std::string FileCache<T>::getCacheFilePath(const KeyType& key) const
{
return cache_dir_ + "/" + hashKey(key) + ".cache"; // 使用哈希作为文件名
}
template <typename T>
void FileCache<T>::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<const char*>(&frame), sizeof(frame));
}
}
template <typename T>
bool FileCache<T>::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<char*>(&frame), sizeof(frame));
return true;
}
template <typename T>
void FileCache<T>::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 <typename T>
bool FileCache<T>::get(const KeyType& key, std::shared_ptr<T>& pData)
{
std::lock_guard<std::mutex> 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<T>();
if (loadFromFile(key, *newData))
{
evictIfNeeded(); // 超出内存容量时删除最早的
// 插入新缓存到内存
lru_list_.push_front(key);
cache_[key] = { newData, lru_list_.begin() };
pData = newData;
return true;
}
return false;
}
template <typename T>
void FileCache<T>::set(const KeyType& key, std::shared_ptr<T> pData)
{
std::lock_guard<std::mutex> 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 <typename T>
size_t FileCache<T>::getMemSize()
{
std::lock_guard<std::mutex> lock(mutex_);
return cache_.size();
}

@ -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矩阵
};
Loading…
Cancel
Save