From 3b8d55e36fc26f53f70e1961fbaf0f3a6978ed60 Mon Sep 17 00:00:00 2001 From: wangchongwu <759291707@qq.com> Date: Tue, 29 Apr 2025 08:57:24 +0800 Subject: [PATCH] UPDATE --- .gitignore | 3 +- CMakeLists.txt | 9 + ProcDJ.cpp | 336 ++++++++++++++++++ doc/吊舱扫描景像拼接算法方案.docx | Bin 8425230 -> 8426617 bytes outputSrt.py | 9 + public_include/Arith_CommonDef.h | 2 +- stitch/CMakeLists.txt | 2 +- stitch/src/API_FrontStitch.h | 2 + stitch/src/API_UnderStitch.h | 5 + stitch/src/Arith_BATask.cpp | 5 +- stitch/src/Arith_FeaMatch.cpp | 2 +- stitch/src/Arith_UnderStitch.cpp | 95 +++-- stitch/src/Arith_UnderStitch.h | 6 +- stitch/src/StitchStruct.h | 2 +- stitch/src/Version.h | 2 +- stitch/src/utils/Arith_Utils.cpp | 2 +- 16 files changed, 442 insertions(+), 40 deletions(-) create mode 100644 ProcDJ.cpp create mode 100644 outputSrt.py diff --git a/.gitignore b/.gitignore index abdb027..b0bc5fc 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,5 @@ build install *.xraw - +.vscode +.vs diff --git a/CMakeLists.txt b/CMakeLists.txt index 507664d..9d25c50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,5 +26,14 @@ add_executable(stitch main.cpp "3rdParty/my_ceres_vc17/include/ceres/version.h target_link_libraries(stitch ${OpenCV_LIBS} ${LIB_STITCH}) + +add_executable(stitch_DJ "ProcDJ.cpp") +target_link_libraries(stitch_DJ ${OpenCV_LIBS} ${LIB_STITCH}) + + + + + + # 可执行文件输出路径 set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/Bin) diff --git a/ProcDJ.cpp b/ProcDJ.cpp new file mode 100644 index 0000000..d4254fa --- /dev/null +++ b/ProcDJ.cpp @@ -0,0 +1,336 @@ +#include +#include +#include +#include +#include +#include +#include "API_UnderStitch.h" +#include "API_FrontStitch.h" +#include "PlatformDefine.h" +#include +#include "opencv2/opencv.hpp" +#include +struct FrameData { + int frameNumber; + std::string timeRange; + int frameCnt; + std::string timestamp; + float focal_len = 0; + float dzoom_ratio = 0; + double latitude = 0; + double longitude = 0; + float rel_alt = 0; + float abs_alt = 0; + float gb_yaw = 0; + float gb_pitch = 0; + float gb_roll = 0; + + + // 衍生参数 + float real_focal_mm = 0; + float pixel_size_um = 0; +}; + +float extractValueAfter(const std::string& line, const std::string& key) { + size_t pos = line.find(key); + if (pos == std::string::npos) return 0; + + pos += key.length(); + size_t end = line.find(' ', pos); + if (end == std::string::npos) end = line.length(); + + return std::stof(line.substr(pos, end - pos)); +} + +double extractDoubleAfter(const std::string& line, const std::string& key) { + size_t pos = line.find(key); + if (pos == std::string::npos) return 0; + + pos += key.length(); + size_t end = line.find(' ', pos); + if (end == std::string::npos) end = line.length(); + + return std::stod(line.substr(pos, end - pos)); +} + +// 获取真实焦距和像元尺寸 +void inferCameraParams_H20(FrameData& frame, const std::string& filename) +{ + const float full_frame_diag = 43.3f; + float sensor_diag = 0.0f; + + if (filename.find("_W") != std::string::npos) { + sensor_diag = 9.4f; + frame.pixel_size_um = 1.98f; + } + else if (filename.find("_Z") != std::string::npos) { + sensor_diag = 7.7f; + frame.pixel_size_um = 2.4f; + } + else if (filename.find("_T") != std::string::npos) { + sensor_diag = 10.9f; + frame.pixel_size_um = 12.0f; + } + else { + sensor_diag = 9.4f; + frame.pixel_size_um = 1.98f; + } + + frame.real_focal_mm = frame.focal_len * (sensor_diag / full_frame_diag); +} +// 获取真实焦距和像元尺寸 +void inferCameraParams_H30(FrameData& frame, const std::string& filename) +{ + const float full_frame_diag = 43.3f; + float sensor_diag = 0.0f; + + if (filename.find("_W") != std::string::npos) { + frame.real_focal_mm = 6.72; + frame.pixel_size_um = 2.4; + } + else if (filename.find("_Z") != std::string::npos) { + + } + else if (filename.find("_T") != std::string::npos) { + frame.real_focal_mm = 24; + frame.pixel_size_um = 12; + } + else { + + } + + //frame.real_focal_mm = frame.focal_len * (sensor_diag / full_frame_diag); +} +std::vector parseDJISRT(const std::string& filename) { + std::vector frames; + std::ifstream file(filename); + + if (!file.is_open()) { + std::cerr << "Error: Could not open file " << filename << std::endl; + return frames; + } + + std::string lines[5]; + while (std::getline(file, lines[0])) { // Frame number line + // Read next 4 lines + for (int i = 1; i < 5; ++i) { + if (!std::getline(file, lines[i])) break; + } + + FrameData frame; + + // Line 1: Frame number + frame.frameNumber = std::stoi(lines[0]); + + // Line 2: Time range (00:00:00,000 --> 00:00:00,033) + frame.timeRange = lines[1]; + + // Line 3: FrameCnt and timestamp + std::istringstream iss(lines[2]); + std::string temp; + iss >> temp >> frame.frameCnt >> frame.timestamp; + + // Line 4: Metadata (direct field extraction) + const std::string& meta = lines[3]; + frame.focal_len = extractValueAfter(meta, "focal_len: "); + frame.dzoom_ratio = extractValueAfter(meta, "dzoom_ratio: "); + frame.latitude = extractDoubleAfter(meta, "latitude: "); + frame.longitude = extractDoubleAfter(meta, "longitude: "); + frame.rel_alt = extractValueAfter(meta, "rel_alt: "); + frame.abs_alt = extractValueAfter(meta, "abs_alt: "); + frame.gb_yaw = extractValueAfter(meta, "gb_yaw: "); + frame.gb_pitch = extractValueAfter(meta, "gb_pitch: "); + frame.gb_roll = extractValueAfter(meta, "gb_roll: "); + + inferCameraParams_H30(frame, filename); + + frames.push_back(frame); + + // Skip the empty line (line 5) + } + + file.close(); + return frames; +} + + +void ProcDJVideo(vector videoPathList, vector srtPathList) +{ + auto stitcher = API_UnderStitch::Create(); + + stitcher->SetOutput("DJI", "D:/google_tiles"); + + + // dsample + int nDownSample = 1; + + GD_VIDEO_FRAME_S frame = { 0 };//输入帧 + GD_VIDEO_FRAME_S pan = { 0 };//输出全景 + + cv::Mat mat_pan;//全景显示 + + + cv::VideoCapture cap(videoPathList[0]); + + // Get video properties + double fps = cap.get(cv::CAP_PROP_FPS); + int width = static_cast(cap.get(cv::CAP_PROP_FRAME_WIDTH)); + int height = static_cast(cap.get(cv::CAP_PROP_FRAME_HEIGHT)); + int frame_count = static_cast(cap.get(cv::CAP_PROP_FRAME_COUNT)); + + std::vector srt_init = parseDJISRT(srtPathList[0]); + + FrameInfo info = { 0 }; + info.nFrmID = 0; + info.camInfo.nFocus = srt_init[0].real_focal_mm; + info.camInfo.fPixelSize = srt_init[0].pixel_size_um * nDownSample; + + info.craft.stAtt.fYaw = srt_init[0].gb_yaw; + info.craft.stAtt.fPitch = srt_init[0].gb_pitch + 90; + info.craft.stAtt.fRoll = srt_init[0].gb_roll; + + info.craft.stPos.B = srt_init[0].latitude; + info.craft.stPos.L = srt_init[0].longitude; + info.craft.stPos.H = srt_init[0].abs_alt; + + + info.nEvHeight = srt_init[0].abs_alt - srt_init[0].rel_alt; + + info.servoInfo.fServoAz = 0; + info.servoInfo.fServoPt = 0; + + info.nWidth = width / nDownSample; + info.nHeight = height / nDownSample; + + // 初始化 + stitcher->Init(info); + + cap.release(); + + for (size_t vid = 0; vid < videoPathList.size(); vid++) + { + printf("Proc %s\n", videoPathList[vid].c_str()); + cv::VideoCapture cap(videoPathList[vid]); + std::vector srt = parseDJISRT(srtPathList[vid]); + + int frmID = 0; + while (true) + { + cv::Mat mat; + + // Read a new frame + cap >> mat; + + // Check if frame is empty (end of video) + if (mat.empty()) { + std::cout << "End of video\n"; + cap.release(); + break; + } + + frmID++; + Mat mat_ds2; + + cv::resize(mat, mat_ds2, cv::Size(width / nDownSample, height / nDownSample)); + + + + FrameInfo info = { 0 }; + info.nFrmID = frmID; + info.camInfo.nFocus = srt[frmID].real_focal_mm; + info.camInfo.fPixelSize = srt[frmID].pixel_size_um * nDownSample; + + info.craft.stAtt.fYaw = srt[frmID].gb_yaw; + info.craft.stAtt.fPitch = srt[frmID].gb_pitch + 90; + info.craft.stAtt.fRoll = srt[frmID].gb_roll; + + info.craft.stPos.B = srt[frmID].latitude; + info.craft.stPos.L = srt[frmID].longitude; + info.craft.stPos.H = srt[frmID].abs_alt; + + + info.nEvHeight = srt[frmID].abs_alt; + + info.servoInfo.fServoAz = 0; + info.servoInfo.fServoPt = 0; + + info.nWidth = mat_ds2.cols; + info.nHeight = mat_ds2.rows; + + + frame.enPixelFormat = GD_PIXEL_FORMAT_RGB_PACKED; + frame.u32Width = mat_ds2.cols; + frame.u32Height = mat_ds2.rows; + frame.u64VirAddr[0] = mat_ds2.data; + + if (frmID % 100 != 0) + { + continue; + } + std::cout << info.craft.stPos.B << " " << info.craft.stPos.L << " " << info.craft.stPos.H << " " + << info.craft.stAtt.fYaw << " " << info.craft.stAtt.fPitch << " " << info.craft.stAtt.fRoll << " " + << info.servoInfo.fServoAz << " " << info.servoInfo.fServoPt + << std::endl; + + cv::TickMeter tm; + tm.start(); + // 基于外参的快拼 + stitcher->Run(frame, info); + + tm.stop(); + + mat_pan = stitcher->ExportPanMat(); + Mat pan_rgb, pan_rgb_ds; + cv::cvtColor(mat_pan, pan_rgb, cv::COLOR_BGRA2BGR); + + cv::resize(pan_rgb, pan_rgb_ds, cv::Size(pan_rgb.cols / 8, pan_rgb.rows / 8)); + + imshow("pan_rgb", pan_rgb_ds); + cv::waitKey(1); + + } + + cv::TickMeter tm; + tm.start(); + // 处理帧 + stitcher->OptAndOutCurrPan(); + + tm.stop(); + + std::cout << "time opt:" << tm.getTimeMilli() << std::endl; + + + + } +} + + + + + +using std::string; + +int main() +{ + vector videoPathList; + vector srtPathList; + + string folder = "F:/DJI_202504181507_016/"; + + // + videoPathList.push_back(folder + "DJI_20250418152649_0005_W.MP4"); + srtPathList.push_back(folder + "DJI_20250418152649_0005_W.srt"); + + //videoPathList.push_back(folder + "DJI_20250418153043_0006_T.MP4"); + //srtPathList.push_back(folder + "DJI_20250418153043_0006_T.srt"); + + //videoPathList.push_back(folder + "DJI_20250418152649_0005_T.MP4"); + //srtPathList.push_back(folder + "DJI_20250418152649_0005_T.srt"); + + + + ProcDJVideo(videoPathList, srtPathList); + return 0; +} + + diff --git a/doc/吊舱扫描景像拼接算法方案.docx b/doc/吊舱扫描景像拼接算法方案.docx index 43a3f0a1a25ebf35a2ed2d870a32c1c0012e3e3f..87dc516ee4c593e907d598675682317c318076a2 100644 GIT binary patch delta 29565 zcmYIvV{l+iv~6tLwkEbGwr$&!UP{F7%-5kYr7_l61oNc zfox(J-KYRp3^C??d{BqT9@2>1tL<~dXCVvikp z;ur8@B0}$s%2YaxAb{DW+Fb)RU=Z$k!tOCabCOJJoW;9#@Ev~Mq>$yUy>yr{vV}g? z&taz*gE7%M;)wevPDDiR7mL2;AcG# z`qJOwC%0`m(ef;0?wU1;HewPsmMuD7{Sgw6^6UfT_Rl;DGvJAA+tXNT$dgHmNxzB3 zOr0Njey*;f+h8lNC*cE?9T1iK6=oim)Yk;=0WM$ucEL2Vu+9UamV5No!BEGk50N+Tmv41--b{%KoZn1z_WIyg1?|5}XTK>sZZjoRe!E1T?V}KR zG`q7X(|-p~V`1aNXuyIX0f)_Gwr@NK0|9w#5Q1g|1?1y1nNd15Pl1S^$5jEN*p0Fp z+V*r8#^3C99>NIhf;x;;*H#=}&(0|1MLUe=Qy8Am2Ek);bB;Q3Tig9@PJ78yqF{5p zX(IlB9)yy_)UaLM-S)2y;M2tN^fqm?-!-dwFEuRHR141H+1~vu*Q$V`g4fK@wBG1~ z|E{jq2=vmSFdiJr(3%A|Y5#R!-rWVQvBr^{p-A2!*gTKV3g%1nzKzSv=hAY}ef>5n zu3aCr8D%o3RQ>H7Rf8(25*J{WuG3TXld6#0%*7<QEVYD|AdW@Rq!{I0#LKCB7VtviH^*T`^X$IjQMz}%2oIf zKb>-XXTQN#1#+H8CoYNZEaN<$ir~>#g#HYt(AOnEPK<}iImT~aL9+Z|$YD<*STb1d zH!?{QSxn#KYgkh1yCzMCU^ILRjG%T9&SMENNnaIHhBHnV>gTQu50svl1$Pkx2eZb} z1{N>|i)8zaV@dEzIG;+hoWB3zCFhptNveenbo_;xGQ>88qd*D+;ZhU@OEWQ|EH6O< zS1}8rMA6%l`q+n~jrp5%%ERb9Eu4e~xdJCDcDCTf#)EGMCdifD>=!2qUIj<{-AMPm z4_sg}H|wOaaAtjrMAhrzmGW;>-656{2jEs^M}WRasbKyE+d`s&e`;@AIib`*vc<;o z+jq{81nq~{F-ER1I!m*KO&PWa#+&lXpRRBsG((&s?|Bu9YG)hXS;lTbc|R-3POxWj z8dsK2)sR~SDlH|GSbhbWAyo05yGHhW43&!+91`VulSqCSfm0ZZ(@`W4X|id0_-$=@ z=^P_$zI)7U5&>nF67G*ezT8#WtlPtF;$+smssoCFzTBnPDOALaP!W4^E6d1j)oMeP zr>X4@+ga5S{A!HInfS#WM%J3dJ^L2}qq1-XKDGzXnf=G0Q?X9Un0Z@{;9#gegv}%T z|6T#Ob))XA7gZ3DwU;Cvcsf9$147k<+BUVczJC4WJSXEHrSbXc+!2hO zaJu+1RIoMzHw&44@IHhoBf}S^>^HLeQNZ}p?;8bKh;WA%L0g{EK(yyo$6Ciz*ISPN z*A%jz!h&DN)YWyXBfE8VMW&iZ%YvzE>kmive>GxbX#vOhqAZ7v>KbT>_1)<4&D5NPBMU!B0}wfN{w zAFKqH}->m#Q>5W(Q&hGb^6q% zJIGXhFx{i6gNwH-`G{yp>$F0jO@>K3V3E54%k8!PDHzTr38z`y+1uY`NBuN~H{h4X zw&u`NF{3#=tT2?Yha@XvXjV8j$}H3&8QTsKXN29xB_kq�Er1j_o=TgI7neqwU%t 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 oV+5o!8O->f4_V0M-y*QlV8|CkFbNhn3^z; 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 t->88pjv(k{3WSdA--{y*4CwzVVGn_7q(VqA* frameInd,cv::Mat H_map) cv::KeyPoint keypoint_i = _FeaPtVec[i][mc.queryIdx]; cv::KeyPoint keypoint_j = _FeaPtVec[j][mc.trainIdx]; - ceres::LossFunction* loss_function = new ceres::HuberLoss(35); + ceres::LossFunction* loss_function = new ceres::HuberLoss(30); cv::Mat H1 = _origMatrix[i]; cv::Mat H2 = _origMatrix[j]; @@ -275,7 +276,7 @@ int BA_Task::readFrameInfo(vector frameInd) #ifdef SHOW_MATCH // 读取图像 - cv::Mat img = cv::Mat(_t_frame_cache->_frame_info.u32Height, _t_frame_cache->_frame_info.u32Width,CV_8UC1, _t_frame_cache->_data); + cv::Mat img = getRGBAMatFromGDFrame(_t_frame_cache->_frame_info, _t_frame_cache->_data); _imgVec.push_back(img.clone()); #endif diff --git a/stitch/src/Arith_FeaMatch.cpp b/stitch/src/Arith_FeaMatch.cpp index 2a8432b..e68c430 100644 --- a/stitch/src/Arith_FeaMatch.cpp +++ b/stitch/src/Arith_FeaMatch.cpp @@ -67,7 +67,7 @@ void FeatureMatcher::matchFeatures_WithH(vector keypoints1, cv::Mat& d auto warp_pt1 = warpPointWithH(H1, keypoints1[mc.queryIdx].pt); auto warp_pt2 = warpPointWithH(H2, keypoints2[mc.trainIdx].pt); - if (fabs(warp_pt1.x - warp_pt2.x) + fabs(warp_pt1.y - warp_pt2.y) < 800) + if (fabs(warp_pt1.x - warp_pt2.x) + fabs(warp_pt1.y - warp_pt2.y) < 20) { matches.push_back(mc); } diff --git a/stitch/src/Arith_UnderStitch.cpp b/stitch/src/Arith_UnderStitch.cpp index d2a5fec..2f3d707 100644 --- a/stitch/src/Arith_UnderStitch.cpp +++ b/stitch/src/Arith_UnderStitch.cpp @@ -6,6 +6,18 @@ #include #include +#ifdef _WIN32 +#include +#include +#define MKDIR(dir) _mkdir(dir) +#define ACCESS _access +#else +#include +#include +#define MKDIR(dir) mkdir(dir, 0777) +#define ACCESS access +#endif + using namespace std; using namespace cv; @@ -62,9 +74,9 @@ UPanInfo UnderStitch::InitMap(FrameInfo info) // 全景图初始化 UPanInfo panPara = { 0 }; - panPara.m_pan_width = MIN(info.nWidth * 5,3000);//全景宽 - panPara.m_pan_height = MIN(info.nWidth * 5, 3000);//全景高 - panPara.scale = gsd;//比例尺,1m = ?pix + panPara.m_pan_width = MIN(info.nWidth * 5,8000);//全景宽 + panPara.m_pan_height = MIN(info.nWidth * 5, 8000);//全景高 + panPara.scale = 6;//比例尺,1m = ?pix // 直接无平移解算 @@ -72,8 +84,8 @@ UPanInfo UnderStitch::InitMap(FrameInfo info) auto cur = warpPointWithH(H_0, ct_geo); // 计算平移到全景图固定点的平移量,从此处开始拼接 - int planX = panPara.m_pan_width/2; - int planY = panPara.m_pan_height/2; + int planX = panPara.m_pan_width/2 + 500; + int planY = panPara.m_pan_height - 500; panPara.map_shiftX = planX - (cur.x);//平移X @@ -130,6 +142,12 @@ void UnderStitch::SetOutput(std::string filename, std::string outdir) _filename = filename; _outDir = outdir; _kmlPath = _outDir + "/" + _filename + ".kml"; + + // 创建输出目录 + if (ACCESS(_outDir.c_str(), 0) != 0) + { + MKDIR(_outDir.c_str()); + } } void UnderStitch::SetConfig(UPanConfig config) @@ -140,16 +158,8 @@ void UnderStitch::SetConfig(UPanConfig config) SINT32 UnderStitch::Run(GD_VIDEO_FRAME_S img, FrameInfo para) { // 快拼 - auto dst = GeoStitch(img, para); + GeoStitch(img, para); - //imshow("dst", dst); - //waitKey(1); - - if (_config.bOutGoogleTile) - { - // 实时裁切瓦片输出 - CutTileRealTime(); - } if (_config.bUseBA) { @@ -174,7 +184,7 @@ SINT32 UnderStitch::OptAndOutCurrPan() if (_config.bUseBA) { // 优化所有帧 - ProcessFrame(_recvFrameKey); + //ProcessFrame(_recvFrameKey); } // 输出当前所有瓦片 @@ -250,7 +260,13 @@ SINT32 UnderStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) // 结合全景图投影H cv::Mat H = _H_pan * H1; - cv::Mat Orth = getOrthImage(img, para); + TileInfo info = { 0 }; + cv::Mat Orth_Image = getOrthImage(src, para, info); + + // 输出单帧谷歌瓦片 + _googleProduct.ExportGeoPng(Orth_Image, info, _outDir); + + // 利用H投影当前帧到全景 cv::Mat imagetmp(_panImage.size(), CV_8UC3, cv::Scalar(0, 0, 0)); @@ -258,8 +274,6 @@ SINT32 UnderStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) cv::Mat mask = cv::Mat::ones(src.size(), CV_8UC1); - mask.colRange(0, 200).setTo(0); - cv::Mat warped_mask; cv::warpPerspective(mask, warped_mask, H, imagetmp.size(), cv::INTER_LINEAR); @@ -268,12 +282,11 @@ SINT32 UnderStitch::GeoStitch(GD_VIDEO_FRAME_S img, FrameInfo para) // 覆盖区域掩码更新 _panMask = _panMask | warped_mask; - // 生产快拼瓦片 - CutTileRealTime(); return 0; } +// 废弃,改为输出单帧正射后的瓦片 void UnderStitch::CutTileRealTime() { // 在4倍降采样图上计算瓦片覆盖情况 @@ -361,6 +374,7 @@ SINT32 UnderStitch::ReceiveFrame(GD_VIDEO_FRAME_S img, FrameInfo para) cv::Mat src = getRGBAMatFromGDFrame(img, img.u64VirAddr[0]); + _FeaMatcher->extractFeatures(src, keypoints, descriptors); size_t keyNum = MIN(keypoints.size(), FEA_NUM_MAX); @@ -448,15 +462,13 @@ bool UnderStitch::ExportGoogleTile() return 0; } -cv::Mat UnderStitch::getOrthImage(GD_VIDEO_FRAME_S img, FrameInfo para) +cv::Mat UnderStitch::getOrthImage(cv::Mat src, FrameInfo para,TileInfo& tile) { cv::Mat H = _GeoSolver->findHomography(para); - cv::Mat src = getRGBAMatFromGDFrame(img, img.u64VirAddr[0]); - cv::Rect2f roi = warpRectWithH_2Rect(H, src.size()); - float scale = img.u32Width / MAX(roi.width, roi.height); + float scale = src.cols / MAX(roi.width, roi.height); float shiftX = -roi.x * scale; float shiftY = (roi.y + roi.height)* scale; @@ -469,14 +481,32 @@ cv::Mat UnderStitch::getOrthImage(GD_VIDEO_FRAME_S img, FrameInfo para) cv::Mat dst; warpPerspective(src, dst, H_proj * H, cv::Size(roi2.width, roi2.height)); - //imshow("Orth", dst); - //imshow("src", src); - //waitKey(0); - imwrite("Orth.jpg", dst); - imwrite("src.jpg", src); + // 计算全景图的坐标范围 + auto P1 = _GeoSolver->getBLHFromFrame(H,cv::Point2f(0, 0)); + auto P2 = _GeoSolver->getBLHFromFrame(H, cv::Point2f(src.cols, 0)); - return cv::Mat(); + auto P3 = _GeoSolver->getBLHFromFrame(H, cv::Point2f(src.cols, src.rows)); + auto P4 = _GeoSolver->getBLHFromFrame(H, cv::Point2f(0, src.rows)); + + auto minL = min(min(min(P1.L, P2.L), P3.L), P4.L); + auto maxL = max(max(max(P1.L, P2.L), P3.L), P4.L); + + auto minB = min(min(min(P1.B, P2.B), P3.B), P4.B); + auto maxB = max(max(max(P1.B, P2.B), P3.B), P4.B); + + + + tile.boxLatLon.north = maxB; + tile.boxLatLon.south = minB; + tile.boxLatLon.west = minL; + tile.boxLatLon.east = maxL; + tile.tileName = _filename + std::to_string(para.nFrmID); + tile.href = _filename + std::to_string(para.nFrmID) + ".png"; + + + + return dst; } GD_VIDEO_FRAME_S UnderStitch::ExportPanAddr() @@ -491,6 +521,11 @@ GD_VIDEO_FRAME_S UnderStitch::ExportPanAddr() return pan_out; } +cv::Mat UnderStitch::ExportPanMat() +{ + return _panImage; +} + PointBLH UnderStitch::getBLHFromPan(cv::Point2f ptInPan, cv::Mat _H_panPara) { cv::Mat H_inv = _H_panPara.inv(); diff --git a/stitch/src/Arith_UnderStitch.h b/stitch/src/Arith_UnderStitch.h index 4abd19f..eeea0fb 100644 --- a/stitch/src/Arith_UnderStitch.h +++ b/stitch/src/Arith_UnderStitch.h @@ -46,12 +46,16 @@ private: bool ExportGoogleTile(); // 正射校正 - cv::Mat getOrthImage(GD_VIDEO_FRAME_S img, FrameInfo para); + cv::Mat getOrthImage(cv::Mat src, FrameInfo para, TileInfo& tile); + + public: GD_VIDEO_FRAME_S ExportPanAddr(); + cv::Mat ExportPanMat(); + // 全景图地理信息计算 PointBLH getBLHFromPan(cv::Point2f ptInPan, cv::Mat _H_panPara); cv::Point2f getPanXYFromBLH(PointBLH ptInBLH, cv::Mat _H_panPara); diff --git a/stitch/src/StitchStruct.h b/stitch/src/StitchStruct.h index 346cc5a..81814c2 100644 --- a/stitch/src/StitchStruct.h +++ b/stitch/src/StitchStruct.h @@ -49,7 +49,7 @@ struct Match_Net }; -#define IMG_CACHE_SIZE (1920 * 1080 * 2) //图像缓存尺寸 +#define IMG_CACHE_SIZE (3840 * 2160 * 3) //图像缓存尺寸 #define FEA_NUM_MAX 500 // 单帧特征点数量 #define FEA_DES_SIZE 128 // 特征点描述子尺度 diff --git a/stitch/src/Version.h b/stitch/src/Version.h index de60ae4..822627e 100644 --- a/stitch/src/Version.h +++ b/stitch/src/Version.h @@ -2,5 +2,5 @@ #pragma once #include -std::string BUILD_TIME = "BUILD_TIME 2025_03_26-10.45.34"; +std::string BUILD_TIME = "BUILD_TIME 2025_04_29-08.56.38"; std::string VERSION = "BUILD_VERSION 1.0.1"; diff --git a/stitch/src/utils/Arith_Utils.cpp b/stitch/src/utils/Arith_Utils.cpp index be553a1..ccf3fd9 100644 --- a/stitch/src/utils/Arith_Utils.cpp +++ b/stitch/src/utils/Arith_Utils.cpp @@ -329,7 +329,7 @@ cv::Mat getRGBAMatFromGDFrame(GD_VIDEO_FRAME_S frame, void* pArr) { cv::Mat mat(frame.u32Height, frame.u32Width, CV_8UC3, pArr); cv::cvtColor(mat, dst, cv::COLOR_BGR2BGRA); - return mat.clone(); + return dst.clone(); } return cv::Mat();