// ImgShowDlg.cpp : 实现文件 // #include "stdafx.h" #include "ImgShowDlg.h" #include "GlobalFunc.h" #include "QB_ImgProcessFun.h" #include "CvvImage.h" #include "Markup.h" // tif 图像 #include #include #include #include // 文字编辑窗口 #include "AddTextDlg.h" #include "MapPrj.h" /*#include "GoogleTileOperation.h"*/ #include "TgtLocCalibrateDlg.h" // CImgShowDlg 对话框 IMPLEMENT_DYNAMIC(CImgShowDlg, CDialog) CImgShowDlg::CImgShowDlg(CWnd* pParent /*=NULL*/): CDialog(CImgShowDlg::IDD, pParent) { m_lpSendCoordinate = NULL; m_lpSendPixInfoProc = NULL; m_lpSendFilePath = NULL; m_lpSendTgrLocLeadLonLat = NULL; m_lpSendArtilleryReviseInfo = NULL; m_ShowRegion = CRect(0,0,0,0); m_ShowRegionOnScreen.left = 0; m_ShowRegionOnScreen.right = 0; m_ShowRegionOnScreen.top = 0; m_ShowRegionOnScreen.bottom = 0; m_PicCtrlWidth = 0; m_PicCtrlHeight = 0; m_LButtonDownPixelCoordinate = CPoint(0,0); m_bStaisfyRoamImg = FALSE; m_LatestPlotRect = CRect(0,0,0,0); m_LButtonDblClkPixelCoordinate = CPoint(-1, -1); m_bPlotRectOnPaint = TRUE; m_NorthDirectionCenter.x = 0; m_NorthDirectionCenter.y = 0; m_bPlotDirectionOnPaint = TRUE; m_LeftButtonDown.x = 0; m_LeftButtonDown.y = 0; m_RButtonPt.x = 0; m_RButtonPt.y = 0; m_SrcFrame = NULL; m_ImgRatioOnScreen = 1.0F; m_ImgShowShift.x = 0L; m_ImgShowShift.y = 0L; m_bFirstSignal = FALSE; m_bSecondSignal = FALSE; m_bSatisfyMove = FALSE; m_iLatest = 0; m_iPreLatest = 0; m_bMemPreMultiFrame = FALSE; m_LatestQuadrangle = CRect(0,0,0,0); // 像素信息 m_imgPixel_XY_Coordinate.x = -1; m_imgPixel_XY_Coordinate.y = -1; m_imgPixel_LBH_Coordinate.x = -200.0; m_imgPixel_LBH_Coordinate.y = -200.0; m_imgPixel_LBH_Coordinate.z = -200.0; m_bPlotRect = FALSE; // 当前显示的图像序号 m_currentImgOrder = 0; // 图像编辑类型 m_iImgEditType = 0; m_bHaveOnPt = false; m_bEnhanceEdit = true; // 增强 m_pFastLookUpDlg = NULL; m_sSaveCurrentImgFolder = ""; m_sSavePreMultiImgFolder = ""; m_TargetCenter = cv::Point(-100, -100); m_bDrawSquareOnImg = TRUE; m_deltaLon = 0; m_deltaLat = 0; m_bCloseRughtBtnMenu = false; m_sThemeText = ""; m_bGetTgtImgOn = false; m_clipImgFirstPt = CPoint(0,0); m_clipImgSecondPt = CPoint(0,0); m_haveValidFirstPt = false; // 图像裁剪开关 m_bClipImgOn = false; m_hMutex_ProcessData = nullptr; } CImgShowDlg::~CImgShowDlg() { try { // 如果有图像 需要释放该图像 if (m_SrcFrame != NULL) { cvReleaseImage(&m_SrcFrame); m_SrcFrame = NULL; } // 当前情报数据结构体:LatestQBData ReleaseQBData(&m_LatestQBData); WaitForSingleObject(m_hMutex_ProcessData, INFINITE); // 情报队列销毁 if(m_QBDataDeque.size() > 0) { for (size_t i = 0; i < m_QBDataDeque.size(); ++i) { SAFE_DELETE_ARRAY(m_QBDataDeque[i].image.srcImg.buff); SAFE_DELETE_ARRAY(m_QBDataDeque[i].image.dstImg.buff); SAFE_DELETE_ARRAY(m_QBDataDeque[i].image.geoImg.buff); } m_QBDataDeque.clear(); } ReleaseMutex(m_hMutex_ProcessData); // midImg 释放 SAFE_DELETE_ARRAY(m_midImg.buff); // 释放快速查找图像对话框 if (m_pFastLookUpDlg != NULL) { delete m_pFastLookUpDlg; m_pFastLookUpDlg = NULL; } } catch(cv::Exception &e) { e.what(); std::abort(); } catch(...) { std::abort(); } } void CImgShowDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CImgShowDlg, CDialog) ON_WM_ERASEBKGND() ON_WM_PAINT() ON_WM_RBUTTONDOWN() ON_COMMAND(ID_ZOOM_IN_IMG, &CImgShowDlg::OnZoomInImg) ON_COMMAND(ID_ZOOM_OUT_IMG, &CImgShowDlg::OnZoomOutImg) ON_COMMAND(ID_ZOOM_FIT_IMG, &CImgShowDlg::OnZoomFitImg) ON_COMMAND(ID_CONCEL_TARGET_PLOT, &CImgShowDlg::OnConcelTargetPlot) ON_COMMAND(ID_SAVE_CURRENT_FRAME, &CImgShowDlg::OnSaveCurrentFrame) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONDBLCLK() ON_WM_MOUSEMOVE() ON_WM_MOUSEWHEEL() ON_COMMAND(ID_CLEAR_MEMORY, &CImgShowDlg::OnClearMemory) ON_COMMAND(ID_SAVE_IMG_TO_TIFF, &CImgShowDlg::OnSaveImgToTiff) ON_COMMAND(ID_FAST_LOOKUP_IMGS, &CImgShowDlg::OnFastLookupImgs) ON_COMMAND(ID_TGT_LOC_LEAD, &CImgShowDlg::OnTgtLocLead) ON_COMMAND(ID_GEO_CORRECT_AND_SHOW, &CImgShowDlg::OnGeoCorrectAndShow) ON_COMMAND(ID_DRAW_SQUARE_ON_IMG, &CImgShowDlg::OnDrawSqureOnImg) ON_COMMAND(ID_OPEN_ONE_IMG, &CImgShowDlg::OnOpenOneImg) ON_COMMAND(ID_TGTLOC_calibrate, &CImgShowDlg::OnTgtloccalibrate) ON_COMMAND(ID_VIEW_DELTA_LON_LAT, &CImgShowDlg::OnViewDeltaLonLat) ON_COMMAND(ID_GET_TARGET_IMG, &CImgShowDlg::OnGetTargetImg) ON_COMMAND(ID_CLIP_IMG, &CImgShowDlg::OnClipImg) END_MESSAGE_MAP() // 1.1 功能:设置回调函数 BOOL CImgShowDlg::SetCallBackFun(SendCoordinateProc proc) { // 输入数据有效性判断 if (proc != NULL) { m_lpSendCoordinate = proc; return TRUE; } return FALSE; } // 2 功能:设置回调函数,像素信息传递到外部CSU中 // 输入: // 1.proc: 函数指针 // // 输出: 设置成功返回TRUE,否则返回FALSE BOOL CImgShowDlg::SetCallBackFun(SendPixInfoProc proc) { // 输入数据有效性判断 if (proc != NULL) { m_lpSendPixInfoProc = proc; return TRUE; } return FALSE; } // 3 功能:设置回调函数,传递保存文件路径到外部CSU中 // 输入: // 1.proc: 函数指针 // // 输出: 设置成功返回TRUE,否则返回FALSE BOOL CImgShowDlg::SetCallBackFun(SendFilePath proc) { // 输入数据有效性判断 if (proc != NULL) { m_lpSendFilePath = proc; return TRUE; } return FALSE; } BOOL CImgShowDlg::SetCallBackFun(SendTgrLocLeadLonLatProc proc) { // 输入数据有效性判断 if (proc != NULL) { m_lpSendTgrLocLeadLonLat = proc; return TRUE; } return FALSE; } // 功能:设置回调函数,目标定位导引经纬度到外部CSU中 // 输入: // 1.proc: 函数指针 // // 输出: 设置成功返回TRUE,否则返回FALSE BOOL CImgShowDlg::SetCallBackFun(SendArtilleryReviseInfoProc proc) { // 输入数据有效性判断 if (proc != NULL) { m_lpSendArtilleryReviseInfo = proc; return TRUE; } return FALSE; } // 1.2 功能:在对话框中显示一帧图像 BOOL CImgShowDlg::ShowOneImage(const BITMAPINFO* pImgInfo, BYTE* pImgData, BOOL isNeedClip, const CRect &ShowRegion, BOOL isNeedFlip, float StrecthRatio, POINT xyShift) { BOOL ret = FALSE; try { // 数据有效性判断 if ( (pImgInfo == NULL) || (pImgData == NULL) ) { return FALSE; } // 图像显示拉伸比例 有效性判定和修正 if ((StrecthRatio < 0.0F) || (StrecthRatio > 1.0F)) { StrecthRatio = 1.0F; } // 图像属性提取 int imgWidth = static_cast(pImgInfo->bmiHeader.biWidth); int imgHeight = static_cast(pImgInfo->bmiHeader.biHeight); int nBitCount = static_cast(pImgInfo->bmiHeader.biBitCount); // 图像属性判断 if ( (imgWidth <= 0) || (imgHeight <= 0) ) { return FALSE; } // 步长:每行像素所占字节数,必须扩展成4的倍数 int lineByte = (imgWidth * nBitCount / 8 + 3) / 4 * 4; // 位图数据缓冲区的大小,即图像大小 unsigned int imgBufSize = static_cast(imgHeight * lineByte); // 将图像数据转换到 m_SrcFrame 再显示 if (m_SrcFrame != NULL) // 如果有图像 { // 情况1:如果图像属性没有变化 直接更换原始图像数据即可,即复制图像数据,不需要再去创建一幅图像 // 情况2:如果图像属性发生了变化,需要先释放图像,再创建图像 // 情况1 if ((m_SrcFrame->width == imgWidth) && (m_SrcFrame->height == imgHeight) && (m_SrcFrame->depth * m_SrcFrame->nChannels == nBitCount) ) { // 内存复制机制 int RealLineByte = (imgWidth * nBitCount / 8); if (RealLineByte == lineByte) { memcpy(m_SrcFrame->imageData, pImgData, imgBufSize); // 图像数据复制 } else { for (int i = 0; i < imgHeight; i++) { memcpy(m_SrcFrame->imageData + i * lineByte, pImgData + i * RealLineByte, RealLineByte); } } } else // 情况2 { // 释放图像 cvReleaseImage(&m_SrcFrame); m_SrcFrame = NULL; // 创建 m_SrcFrame = cvCreateImage(cvSize(imgWidth, imgHeight), 8, nBitCount/8); // 创建图像 if (m_SrcFrame != NULL) // 创建成功 { // 内存复制机制 int RealLineByte = (imgWidth * nBitCount / 8); if (RealLineByte == lineByte) { memcpy(m_SrcFrame->imageData, pImgData, imgBufSize); // 图像数据复制 } else { for (int i = 0; i < imgHeight; i++) { memcpy(m_SrcFrame->imageData + i * lineByte, pImgData + i * RealLineByte, RealLineByte); } } } else { return FALSE; } } } else // 如果没有图像 需要先创建图像 { m_SrcFrame = cvCreateImage(cvSize(imgWidth, imgHeight), 8, nBitCount/8); // 创建图像 if (m_SrcFrame != NULL) // 创建成功 { // 内存复制机制 int RealLineByte = (imgWidth * nBitCount / 8); if (RealLineByte == lineByte) { memcpy(m_SrcFrame->imageData, pImgData, imgBufSize); // 图像数据复制 } else { for (int i = 0; i < imgHeight; i++) { memcpy(m_SrcFrame->imageData + i * lineByte, pImgData + i * RealLineByte, RealLineByte); } } } else { return FALSE; } } // 如果需要反转 把 SrcFrame 反转 后面的函数就再也不用考虑反转的问题 if (isNeedFlip == TRUE) { cvFlip(m_SrcFrame); // 上下反转,改变自身 } // 保存图像显示属性,如果该值不合理,会在随后的重载图像显示函数中被修改 this->m_ShowRegion = ShowRegion; // 设置图像显示拉伸系数 if (StrecthRatio >= 0.0F && StrecthRatio <= 1.0F) { m_ImgRatioOnScreen = StrecthRatio; } else { m_ImgRatioOnScreen = 1.0F; } // 转到函数1.3(重载)进行图像显示 ret = ShowOneImage(m_SrcFrame, isNeedClip, ShowRegion, m_ImgRatioOnScreen, xyShift); return ret; } catch(cv::Exception &e) { e.msg; return FALSE; } catch(...) { return FALSE; } } // 1.3 功能:在对话框中显示一帧图像 BOOL CImgShowDlg::ShowOneImage(const IplImage* src, BOOL isNeedClip, const CRect &ShowRegion, float StrecthRatio, POINT xyShift) { BOOL ret = FALSE; // 返回值 try { // 图像数据有效性判断 if (src == NULL) { return FALSE; } // 定义变量,用于标识是否显示整个图像 // 原因:即使 isNeedClip 设置为TURE,ShowRegion不合理时,也要显示整个图像 BOOL ShowWholeImg = TRUE; // 判断是否需要裁剪 if (isNeedClip == TRUE) // 如果需要裁剪 { // 判断 ShowRegion 是否合理 // 如果 ShowRegion 出现任何不合理,则显示整个图像 if ((ShowRegion.left >= 0) && (ShowRegion.left < src->width) && (ShowRegion.right >= 0) && (ShowRegion.right < src->width) && (ShowRegion.top >= 0) && (ShowRegion.top < src->height) && (ShowRegion.bottom >= 0) && (ShowRegion.bottom < src->height) && (ShowRegion.right - ShowRegion.left > 0) && (ShowRegion.bottom - ShowRegion.top > 0) ) { // 特殊情况:裁剪整个图像 if ((ShowRegion.right - ShowRegion.left + 1 == src->width) && (ShowRegion.bottom - ShowRegion.top + 1 == src->height)) { ShowWholeImg = TRUE; } else { ShowWholeImg = FALSE; } } else { // 显示区域设置不合理,显示全部图像 ShowWholeImg = TRUE; } } // 判断是否需要显示整个图像 if (ShowWholeImg == TRUE) // 如果显示整个图像 { // 显示整个图像 ret = ShowWholeImage(src, StrecthRatio, xyShift); // 更新图像显示区域 m_ShowRegion // 目的:用于图像放大缩小等操作 this->m_ShowRegion.left = 0; this->m_ShowRegion.right = src->width - 1; this->m_ShowRegion.top = 0; this->m_ShowRegion.bottom = src->height - 1; } else { // 裁剪出显示区域 IplImage* validPart = NULL; // 这时,ShowRegion肯定是有效的,可以直接创建图像 validPart = cvCreateImage(cvSize(ShowRegion.Width(), ShowRegion.Height()), src->depth, src->nChannels); if (validPart != NULL) // 创建成功 { cvZero(validPart); // 清零 // 设置 感兴趣区 cvSetImageROI( const_cast(src), cvRect( static_cast(ShowRegion.left), static_cast(ShowRegion.top), ShowRegion.Width(), ShowRegion.Height()) ); // 叠加 cvAdd( src, validPart, validPart, NULL ); // 释放 感兴趣区 cvResetImageROI( const_cast(src) ); // 显示图像 validPart ret = ShowWholeImage(validPart, StrecthRatio, xyShift); // 释放 validPart cvReleaseImage(&validPart); validPart = NULL; } else { return FALSE; } } return ret; } catch(cv::Exception &e) { e.msg; return FALSE; } catch(...) { return FALSE; } } // 1.4 功能:在对话框中显示一帧图像 BOOL CImgShowDlg::ShowWholeImage(const IplImage* src, float StrecthRatio, POINT &shift) { try { // 数据有效性判断 if (src == NULL) { return FALSE; } // 图像显示拉伸比例 有效性判定和修正 if ((abs(StrecthRatio) <= 0.0F) || (StrecthRatio > 1.0F)) { StrecthRatio = 1.0F; } // 计算当前显示图像对话框尺寸 CRect clientRect; GetClientRect(&clientRect); // 获得 pictrue 控件窗口的句柄 CWnd *pWnd = NULL; pWnd = GetDlgItem(IDC_IMG_SHOW_PIC_CTRL); // 后面程序无需再判定 if (pWnd == NULL) { return FALSE; } // 让图像控件填满对话框 pWnd->MoveWindow(&clientRect); // 设置图像控件尺寸 m_PicCtrlWidth = clientRect.Width(); // 图像控件宽 m_PicCtrlHeight = clientRect.Height(); // 图像控件高 // 获取图像控件HDC CDC *pDC = NULL; // 函数退出时需要释放 ReleaseDC(pDC); pDC = pWnd->GetDC(); // 后面程序无需再判定 if (pDC == NULL) { return FALSE; } HDC hdc = NULL; hdc = pDC->GetSafeHdc(); // 当前图像尺寸 int imgWidth = src->width; int imgHeight = src->height; // 显示图像 IplImage* fitSizeImg = NULL; // 显示图像尺寸 int fitSizeImgWidth = 0; int fitSizeImgHeight = 0; // 图像尺寸小于窗口尺寸 if ((imgWidth <= m_PicCtrlWidth) && (imgHeight <= m_PicCtrlHeight)) { // 拉伸图像 double Ratio = 1.0; double Ratio_Width = static_cast(m_PicCtrlWidth) / static_cast(imgWidth); double Ratio_Height = static_cast(m_PicCtrlHeight) / static_cast(imgHeight); Ratio = (Ratio_Width < Ratio_Height) ? Ratio_Width : Ratio_Height; // Ratio 大于 1 // 拉伸比例控制 Ratio *= StrecthRatio; // 显示图像尺寸 fitSizeImgWidth = static_cast(imgWidth * Ratio + 0.5); fitSizeImgHeight = static_cast(imgHeight * Ratio + 0.5); } else { // 压缩图像 double Ratio = 1.0; double Ratio_Img = static_cast(imgWidth) / static_cast(imgHeight); double Ratio_ClientRect = static_cast(m_PicCtrlWidth) / static_cast(m_PicCtrlHeight); // 计算比例系数 if ( Ratio_Img > Ratio_ClientRect ) { Ratio = static_cast(m_PicCtrlWidth) / static_cast(imgWidth); // Ratio 小于 1 } else { Ratio = static_cast(m_PicCtrlHeight) / static_cast(imgHeight); // Ratio 小于 1 } // 拉伸比例控制 Ratio *= StrecthRatio; // 显示图像尺寸 fitSizeImgWidth = static_cast(imgWidth * Ratio + 0.5); fitSizeImgHeight = static_cast(imgHeight * Ratio + 0.5); } // 最低尺寸判断,小于一个像素时直接返回 if(min(fitSizeImgWidth, fitSizeImgHeight) <= 1) { // 释放 ReleaseDC(pDC); return FALSE; } // 创建fitSizeImg fitSizeImg = cvCreateImage(cvSize(fitSizeImgWidth, fitSizeImgHeight), src->depth, src->nChannels); if (fitSizeImg == NULL) { return FALSE; } // 改变图像尺寸 cvResize(src, fitSizeImg); // 为使显示界面不闪烁 增加中间变量 边界充满黑色 IplImage* fillblackImg = NULL; fillblackImg = cvCreateImage(cvSize(clientRect.Width(), clientRect.Height()), src->depth, src->nChannels); if (fillblackImg != NULL) { cvZero(fillblackImg); // 清零 } else { // 释放缩放后图像 cvReleaseImage(&fitSizeImg); fitSizeImg = NULL; // 释放pdc ReleaseDC(pDC); return FALSE; } // 叠加 fitSizeImg 图像 到 fillblackImg // 左上 起始点 cv::Point LeftUpBefore; LeftUpBefore.x = static_cast((m_PicCtrlWidth - fitSizeImgWidth)/2); LeftUpBefore.y = static_cast((m_PicCtrlHeight - fitSizeImgHeight)/2); // 加上偏移量之后 cv::Point LeftUpAfter = LeftUpBefore; LeftUpBefore.x += shift.x; LeftUpBefore.y += shift.y; // 修改全局变量 设计的不好 if (LeftUpAfter.x < 0) { LeftUpAfter.x = 0; } if (LeftUpAfter.x > m_PicCtrlWidth - fitSizeImgWidth) { LeftUpAfter.x = m_PicCtrlWidth - fitSizeImgWidth; } if (LeftUpAfter.y < 0) { LeftUpAfter.y = 0; } if (LeftUpAfter.y > m_PicCtrlHeight - fitSizeImgHeight) { LeftUpAfter.y = m_PicCtrlHeight - fitSizeImgHeight; } // 实际偏移量 shift.x = LeftUpAfter.x - LeftUpBefore.x; shift.y = LeftUpAfter.y - LeftUpBefore.y; cvSetImageROI(fillblackImg, cvRect(static_cast(LeftUpAfter.x), static_cast(LeftUpAfter.y), fitSizeImgWidth, fitSizeImgHeight)); cvAdd(fillblackImg, fitSizeImg, fillblackImg); cvResetImageROI( fillblackImg ); // 设置 ShowRegionOnScreen : 图像显示部分在dialog中的坐标 m_ShowRegionOnScreen.left = LeftUpAfter.x; m_ShowRegionOnScreen.right = LeftUpAfter.x + fitSizeImgWidth; m_ShowRegionOnScreen.top = LeftUpAfter.y; m_ShowRegionOnScreen.bottom = LeftUpAfter.y + fitSizeImgHeight; // 在图像中写字、添加信息示例 if (m_LatestQBData.image.bValid == true) { cv::Mat fillblackImgMat(fillblackImg, false); cv::Scalar color(0, 255, 0); if (fillblackImgMat.type() == CV_8UC1) { color = cv::Scalar(255); } // 图像显示比例 CString scale = 0; scale.Format("%.1f", double(fitSizeImgWidth) / imgWidth * 100); scale = scale + "%"; cv::putText(fillblackImgMat, scale.GetBuffer(0), cv::Point(10, fillblackImgMat.rows - 20), 2, 0.5, color); } // 释放 fitSizeImg cvReleaseImage(&fitSizeImg); fitSizeImg = NULL; // 绘图 CvvImage img; img.CopyOf(fillblackImg); img.Show(hdc, 0, 0, fillblackImg->width, fillblackImg->height); // 释放fillblackImg cvReleaseImage(&fillblackImg); fillblackImg = NULL; // 释放 ReleaseDC(pDC); return TRUE; } catch(cv::Exception &e) { e.msg; return FALSE; } catch(...) { return FALSE; } } // 1.5 功能:设置目标点像素坐标,如果设置合理,在在显示窗口中标绘目标 BOOL CImgShowDlg::SetTargetPixelCoordinate(const CPoint &point) { try { // 设置目标点 m_LButtonDblClkPixelCoordinate = point; // 赋值给私有成员变量 if ((point.x >= m_ShowRegion.left) && (point.x <= m_ShowRegion.right) && (point.y >= m_ShowRegion.top) && (point.y <= m_ShowRegion.bottom) ) { // 标绘目标:当目标点未显示到屏幕时,不标绘 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate)); } else { // 先全景显示 再标绘 OnZoomFitImg(); // 标绘目标:当目标点未显示到屏幕时,不标绘 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate)); } return TRUE; } catch(cv::Exception &e) { e.msg; return FALSE; } catch(...) { return FALSE; } } // 功能:标绘目标,其中输入为经纬度坐标 void CImgShowDlg::SetTgtLocLeadLonLat(double lon, double lat) { if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { return; } if (m_SrcFrame != NULL && m_SrcFrame->width > 0 && m_SrcFrame->height > 0) { if (m_boundbingBox.EastLon - m_boundbingBox.WestLon > 0 && m_boundbingBox.WestLon >= -180 && m_boundbingBox.WestLon <= 180 && m_boundbingBox.EastLon >= -180 && m_boundbingBox.EastLon <= 180 && m_boundbingBox.NorthLat - m_boundbingBox.SouthLat > 0 && m_boundbingBox.SouthLat >= -90 && m_boundbingBox.SouthLat <= 90 && m_boundbingBox.NorthLat >= -90 && m_boundbingBox.NorthLat <= 90) { if (lon >= m_boundbingBox.WestLon && lon <= m_boundbingBox.EastLon && lat >= m_boundbingBox.SouthLat && lat <= m_boundbingBox.NorthLat) { double LonResolution = (m_boundbingBox.EastLon - m_boundbingBox.WestLon) / m_SrcFrame->width; double LatResolution = (m_boundbingBox.NorthLat - m_boundbingBox.SouthLat) / m_SrcFrame->height; CPoint pixelCord; pixelCord.x = static_cast((lon - m_boundbingBox.WestLon) / LonResolution); pixelCord.y = static_cast((m_boundbingBox.NorthLat - lat) / LatResolution); SetTargetPixelCoordinate(pixelCord); } } else { ::MessageBoxA(NULL, _T("目标可能不在当前图像中!"),_T("操作提示"), MB_OK); } } } // 绘制四个角点连成的区域 BOOL CImgShowDlg::SetQuadrangleCorners(const POINT* pts) { try { if (pts != NULL) { m_corners[0] = pts[0]; m_corners[1] = pts[1]; m_corners[2] = pts[2]; m_corners[3] = pts[3]; POINT CornersOnScreen[4]; for (int i = 0; i < 4; i++) { CornersOnScreen[i] = GetScreenCoordinateBasedOnPixelCoordinate(m_corners[i]); } if (CornersOnScreen[0].x >= 0 && CornersOnScreen[0].y >= 0 && CornersOnScreen[1].x >= 0 && CornersOnScreen[1].y >= 0 && CornersOnScreen[2].x >= 0 && CornersOnScreen[2].y >= 0 && CornersOnScreen[3].x >= 0 && CornersOnScreen[3].y >= 0) { DrawQuadrangleOnScreen(CornersOnScreen); } return TRUE; } } catch(cv::Exception &e) { e.msg; return FALSE; } catch(...) { return FALSE; } return FALSE; } // 1.6 功能:绘制指北针 // void CImgShowDlg::DrawNorthDirection(const POINT ¢er, double angle) // { // try // { // int r = 20; // 中心点到底角的长度 // int R = 30; // 中心点到顶点的长度 // // double LocalAngle = 50.0; // 控制指北针尖锐程度 // LocalAngle = LocalAngle/180.0 * 3.1415926535; // // CDC* pDC = NULL; // pDC = this->GetDC(); // // // 判断,若pDC为空,直接返回,后面程序也无需再判定pDC // if (pDC == NULL) // { // return; // } // // // 创建并选择画笔 // CPen aPen; // aPen.CreatePen(PS_SOLID, 2, RGB(0,255,0)); // // CPen * pOldPen = NULL; // pOldPen = pDC->SelectObject(&aPen); // // // 设置背景透明 用于写字 // pDC->SetBkMode(TRANSPARENT); // pDC->SetTextColor(RGB(0,255,0)); // // // 绘制图形需要的五个点 // POINT point[5]; // // // 零度时各点相对于中心点的位置 // point[0].x = - static_cast(r * cos(LocalAngle)); // point[0].y = static_cast(r * sin(LocalAngle)); // // point[1].x = 0L; // point[1].y = - static_cast(R); // // point[2].x = static_cast(r * cos(LocalAngle)); // point[2].y = static_cast(r * sin(LocalAngle)); // // point[3].x = 0L; // point[3].y = 0L; // // point[4].x = - 4L; // point[4].y = - static_cast(R + 16); // // // 各点旋转一定角度,并平移至以center为中心的坐标 // for(int i = 0; i < 5; i++) // { // point[i] = RotateShiftPoint(point[i],angle,center); // } // // // 绘图 // pDC->MoveTo(point[0]); // pDC->LineTo(point[1]); // pDC->LineTo(point[2]); // pDC->LineTo(point[3]); // pDC->LineTo(point[0]); // // // 画圆圈 // CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); // CBrush* pOldBrush = pDC->SelectObject(pBrush); // R = R + 2; // pDC->Ellipse(point[3].x - R, point[3].y - R, point[3].x + R, point[3].y + R); // pDC->SelectObject(pOldBrush); // // // 写字:N // // 转换为【0,360】 // angle = (angle/360.0 - static_cast(angle/360.0)) * 360.0; // if (angle < 0) // { // angle += 360; // } // // // 判断并修正,经验值 // if (angle <= 45) // { // point[4].y -= 3; // } // // if ((angle > 45) && (angle <= 135)) // { // point[4].x -= 8; // point[4].y -= 3; // } // // if ((angle > 135) && (angle <= 225)) // { // point[4].x -= 8; // point[4].y -= 10; // } // // if ((angle > 225) && (angle <= 315)) // { // point[4].y -= 10; // } // // if (angle > 315) // { // point[4].y -= 6; // } // // // 写N // pDC->TextOutA(static_cast(point[4].x), static_cast(point[4].y), "N"); // // // 选回旧画笔 // pDC->SelectObject(pOldPen); // // // 释放pDC // ReleaseDC(pDC); // pDC = NULL; // } // catch(cv::Exception &e) // { // e.msg; // return; // } // catch(...) // { // return; // } // } // // //1.7 功能:设置指北针中心 // void CImgShowDlg::SetNorthDirectionCenter(const POINT ¢er) // { // CRect rect; // GetClientRect(&rect); // // if ((center.x > 0) && (center.x < rect.Width()) && // (center.y > 0) && (center.y < rect.Height())) // { // m_NorthDirectionCenter = center; // } // } // 1.8 功能:基于私有成员变量LatestQBData 显示图像和指北针 // 说明:当dst有效时,优先显示dst,否则显示src void CImgShowDlg::ShowLatestQBData() { try { // geoImg if ((m_LatestQBData.image.bValid == true) && // 图像数据有效 (m_LatestQBData.image.geoImg.buff != nullptr) && // 图像有数据 (m_LatestQBData.image.geoImg.ImgWidth > 0) && (m_LatestQBData.image.geoImg.ImgHeight > 0) && // 图像尺寸有效 (m_LatestQBData.image.geoImg.bitcount > 0)) // 数据位数有效 { // 创建临时变量:图像头 BITMAPINFO imgheader; imgheader.bmiHeader.biWidth = static_cast(m_LatestQBData.image.geoImg.ImgWidth); imgheader.bmiHeader.biHeight = static_cast(m_LatestQBData.image.geoImg.ImgHeight); imgheader.bmiHeader.biBitCount = static_cast(m_LatestQBData.image.geoImg.bitcount); // 显示图像 ShowOneImage(&imgheader, m_LatestQBData.image.geoImg.buff, FALSE, NULL, FALSE, m_ImgRatioOnScreen, m_ImgShowShift); if (min(m_ShowRegionOnScreen.Width(), m_ShowRegionOnScreen.Height()) <= 10) { m_ImgRatioOnScreen = m_ImgRatioOnScreen / 0.9F; } } // dstImg else if ((m_LatestQBData.image.bValid == true) && // 图像数据有效 (m_LatestQBData.image.dstImg.buff != nullptr) && // 图像有数据 (m_LatestQBData.image.dstImg.ImgWidth > 0) && (m_LatestQBData.image.dstImg.ImgHeight > 0) && // 图像尺寸有效 (m_LatestQBData.image.dstImg.bitcount > 0)) // 数据位数有效 { // 创建临时变量:图像头 BITMAPINFO imgheader; imgheader.bmiHeader.biWidth = static_cast(m_LatestQBData.image.dstImg.ImgWidth); imgheader.bmiHeader.biHeight = static_cast(m_LatestQBData.image.dstImg.ImgHeight); imgheader.bmiHeader.biBitCount = static_cast(m_LatestQBData.image.dstImg.bitcount); // 显示图像 ShowOneImage(&imgheader, m_LatestQBData.image.dstImg.buff, FALSE, NULL, FALSE, m_ImgRatioOnScreen, m_ImgShowShift); if (min(m_ShowRegionOnScreen.Width(), m_ShowRegionOnScreen.Height()) <= 10) { m_ImgRatioOnScreen = m_ImgRatioOnScreen / 0.9F; } } // srcImg else if ((m_LatestQBData.image.bValid == true) && // 图像数据有效 (m_LatestQBData.image.srcImg.buff != nullptr) && // 图像有数据 (m_LatestQBData.image.srcImg.ImgWidth > 0) && (m_LatestQBData.image.srcImg.ImgHeight > 0) && // 图像尺寸有效 (m_LatestQBData.image.srcImg.bitcount > 0)) // 数据位数有效 { // 创建临时变量:图像头 BITMAPINFO imgheader; imgheader.bmiHeader.biWidth = static_cast(m_LatestQBData.image.srcImg.ImgWidth); imgheader.bmiHeader.biHeight = static_cast(m_LatestQBData.image.srcImg.ImgHeight); imgheader.bmiHeader.biBitCount = static_cast(m_LatestQBData.image.srcImg.bitcount); // 显示图像 ShowOneImage(&imgheader, m_LatestQBData.image.srcImg.buff, FALSE, NULL, FALSE, m_ImgRatioOnScreen, m_ImgShowShift); if (min(m_ShowRegionOnScreen.Width(), m_ShowRegionOnScreen.Height()) <= 10) { m_ImgRatioOnScreen = m_ImgRatioOnScreen / 0.9F; } } else // 图像数据无效 { // 如果当前帧图像数据无效,则释放上一帧保存的图像 cvReleaseImage(&m_SrcFrame); m_SrcFrame = NULL; // 重绘窗口 CRect clientRect; GetClientRect(&clientRect); InvalidateRect(&clientRect); UpdateWindow(); // 显示指北针 if (m_LatestQBData.framePart.bValid == TRUE) // 复接数据有效 { // 设置在OnPaint中不绘制指北针 m_bPlotDirectionOnPaint = FALSE; // 清除上次绘制的指北针 CRect rect; rect.left = m_NorthDirectionCenter.x - 100; rect.right = m_NorthDirectionCenter.x + 100; rect.top = m_NorthDirectionCenter.y - 100; rect.bottom = m_NorthDirectionCenter.y + 100; InvalidateRect(&rect); UpdateWindow(); // 恢复设置 OnPaint中重绘 m_bPlotDirectionOnPaint = TRUE; } } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 1.9 功能:获取双击目标点坐标 m_LButtonDblClkPixelCoordinate CPoint CImgShowDlg::GetTargetCoordinate() { return m_LButtonDblClkPixelCoordinate; } // 1.10 功能:在对话框左上角显示信息 void CImgShowDlg::ShowMessageOnDialog(CString msg) { try { // 获取窗口句柄 CWnd *pWnd = GetDlgItem(IDC_IMG_SHOW_PIC_CTRL); CRect Rect; pWnd->GetClientRect(&Rect); // 获得控件的 DC CDC *pDC=pWnd->GetDC(); // 设置背景透明 pDC->SetBkMode(TRANSPARENT); // 设置字体颜色 pDC->SetTextColor(RGB(255,0,0)); // 输出信息 pDC->TextOutA(Rect.Width() - 130, Rect.Height() - 50, msg); ReleaseDC(pDC); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 3.1 功能:基于当前图像显示状态 和 像素坐标(图像某点的像素坐标),求该像素坐标对应的客户区坐标 CPoint CImgShowDlg::GetScreenCoordinateBasedOnPixelCoordinate(const POINT &PixelCoordinate) { // 返回值 CPoint screenCoordinate = CPoint(-100, -100); try { // 如果该像素坐标显示在当前窗口中 if ((PixelCoordinate.x >= m_ShowRegion.left) && (PixelCoordinate.x <= m_ShowRegion.right) && (PixelCoordinate.y >= m_ShowRegion.top) && (PixelCoordinate.y <= m_ShowRegion.bottom) ) { double ratio = 1.0; // 计算屏幕坐标 if(m_ShowRegionOnScreen.Width() > 0) { ratio = m_ShowRegion.Width() * 1.0 / m_ShowRegionOnScreen.Width(); if (ratio > 0.0) { screenCoordinate.x = static_cast((PixelCoordinate.x - m_ShowRegion.left) / ratio) + m_ShowRegionOnScreen.left; screenCoordinate.y = static_cast((PixelCoordinate.y - m_ShowRegion.top) / ratio) + m_ShowRegionOnScreen.top; } } } return screenCoordinate; } catch(cv::Exception &e) { e.msg; return screenCoordinate; } catch(...) { return screenCoordinate; } } // 3.2 功能:给定屏幕坐标,在屏幕中绘制标框, (可能)同时清除上次绘制的标框 void CImgShowDlg::DrawSquareOnScreen(const POINT &screenCoordinate, BOOL bErase) { try { // 如果该点在图像显示区域中,则清除上次绘制的标框,同时标绘该点 int X = static_cast(screenCoordinate.x); // X坐标 int Y = static_cast(screenCoordinate.y); // Y坐标 if (X > m_ShowRegionOnScreen.left && X < m_ShowRegionOnScreen.right && Y > m_ShowRegionOnScreen.top && Y < m_ShowRegionOnScreen.bottom ) // 鼠标在图像上 { // 绘制标框 if (bErase == TRUE) { // 去掉上次标绘的框 InvalidateRect(&m_LatestPlotRect, FALSE); UpdateWindow(); } CDC* pDC = this->GetDC(); CPen newPen; // 创建新画笔 newPen.CreatePen(PS_SOLID, 2, RGB(0, 255, 0)); CPen* pOldPen = NULL; if (pDC != NULL) { pDC->SelectObject(&newPen); // 绘图 pDC->MoveTo(X - 50, Y); pDC->LineTo(X - 20, Y); pDC->MoveTo(X + 20, Y); pDC->LineTo(X + 50, Y); pDC->MoveTo(X, Y - 50); pDC->LineTo(X, Y - 20); pDC->MoveTo(X, Y + 20); pDC->LineTo(X, Y + 50); pDC->MoveTo(X + 30, Y - 15); pDC->LineTo(X + 30, Y - 30); pDC->LineTo(X + 15, Y - 30); pDC->MoveTo(X - 30, Y - 15); pDC->LineTo(X - 30, Y - 30); pDC->LineTo(X - 15, Y - 30); pDC->MoveTo(X - 30, Y + 15); pDC->LineTo(X - 30, Y + 30); pDC->LineTo(X - 15, Y + 30); pDC->MoveTo(X + 30, Y + 15); pDC->LineTo(X + 30, Y + 30); pDC->LineTo(X + 15, Y + 30); // 中心点 pDC->MoveTo(X - 1, Y); pDC->LineTo(X + 1, Y); pDC->MoveTo(X , Y - 1); pDC->LineTo(X , Y + 1); // 回收旧画笔 pDC->SelectObject(pOldPen); // 释放设备上下文指针 ReleaseDC(pDC); pDC = NULL; // 更新latestRect m_LatestPlotRect.left = X - 51; m_LatestPlotRect.right = X + 50; m_LatestPlotRect.top = Y - 51; m_LatestPlotRect.bottom = Y + 50; } // 设置为目标标绘状态 m_bPlotRect = TRUE; } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 3.2 功能:给定屏幕4个坐标,在屏幕中绘制四边形, (可能)同时清除上次绘制 // 输入: // 1: screenCoordinate: 屏幕坐标 // 返回值:无 void CImgShowDlg::DrawQuadrangleOnScreen(const POINT screenCoordinate[4], BOOL bErase) { try { // 如果该点在图像显示区域中,则清除上次绘制的标框,同时标绘该点 // 绘制标框 if (bErase == TRUE) { // 去掉上次标绘的框 InvalidateRect(&m_LatestPlotRect, FALSE); UpdateWindow(); } CDC* pDC = this->GetDC(); CPen newPen; // 创建新画笔 newPen.CreatePen(PS_SOLID, 2, RGB(0, 255, 0)); CPen* pOldPen = NULL; if (pDC != NULL) { pDC->SelectObject(&newPen); // 绘图 pDC->MoveTo(screenCoordinate[0].x, screenCoordinate[0].y); pDC->LineTo(screenCoordinate[1].x, screenCoordinate[1].y); pDC->LineTo(screenCoordinate[2].x, screenCoordinate[2].y); pDC->LineTo(screenCoordinate[3].x, screenCoordinate[3].y); pDC->LineTo(screenCoordinate[0].x, screenCoordinate[0].y); // 回收旧画笔 pDC->SelectObject(pOldPen); // 释放设备上下文指针 ReleaseDC(pDC); pDC = NULL; } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::DoZoomInImg() { try { /************************************************************************/ /* 设计思路: 分两种情况: 情况1:当前图像的全部内容已经全部显示出来 情况2:当前只显示出部分图像 针对情况1:也存在两种情况: (1.1) 全景显示: 此时 StrecthRatio = 1.0f (1.2) 图像已经经过缩小显示,此时,StrecthRatio <= 0.901(考虑到存储精度),这时,放大10%显示即可,即StrecthRatio /= 0.9f; 针对情况2:只显示出部分图像,此时 StrecthRatio = 1.0f /************************************************************************/ if ((m_ShowRegion.Width() == m_SrcFrame->width - 1) && (m_ShowRegion.Height() == m_SrcFrame->height - 1)) // 情况1 { // 拉伸比例计算 if (m_ImgRatioOnScreen <= 0.901F) // (1.2) 目前图像是缩小显示 { m_ImgRatioOnScreen /= 0.9F; } else // (1.1) 目前图像是充满显示,正好 { m_ImgRatioOnScreen = 1.0F; // 继续放大时要求继续填满显示才符合逻辑,故设为:ImgRatioOnScreen = 1.0F if (max(m_ShowRegion.Width(), m_ShowRegion.Height()) >= 100) { m_ShowRegion = GetNewRegionWhenZoom(true); } } } else // 图像尚未完整显示 情况2 { m_ImgRatioOnScreen = 1.0F; // 此时,无需拉伸比例控制 if (max(m_ShowRegion.Width(), m_ShowRegion.Height()) >= 100) { m_ShowRegion = GetNewRegionWhenZoom(true); } } // 显示图像 ShowOneImage(m_SrcFrame, TRUE, m_ShowRegion, m_ImgRatioOnScreen, m_ImgShowShift); int a = 5; } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } CRect CImgShowDlg::GetNewRegionWhenZoom(bool in) { CRect newShowRegion = m_ShowRegion; try { double ratio = 0.1; if (in == true) { ratio = -ratio; } // 在当前显示区域的基础上,以中心点为基准点放大 int ShowRegionWidth = m_ShowRegion.Width() + 1; int ShowRegionHeight = m_ShowRegion.Height() + 1; newShowRegion.left = m_ShowRegion.left - static_cast(ratio / 2 * ShowRegionWidth); newShowRegion.right = m_ShowRegion.right + static_cast(ratio / 2 * ShowRegionWidth); newShowRegion.top = m_ShowRegion.top - static_cast(ratio / 2 * ShowRegionHeight); newShowRegion.bottom = m_ShowRegion.bottom + static_cast(ratio / 2 * ShowRegionHeight); // 在此修正,确保返回值有效 if (newShowRegion.left < 0) { newShowRegion.left = 0; } int _Width = m_SrcFrame->width; int _Height = m_SrcFrame->height; if (newShowRegion.right > _Width - 1) { newShowRegion.right = _Width - 1; } if (newShowRegion.top < 0) { newShowRegion.top = 0; } if (newShowRegion.bottom > _Height - 1) { newShowRegion.bottom = _Height - 1; } // 若无效,返回原始值 if (newShowRegion.right - newShowRegion.left <= 0 || newShowRegion.bottom - newShowRegion.top <= 0) { return m_ShowRegion; } // 调整 newShowRegion 目的:填充图像控件 double newShowRegion_WH_Ration = 1.0; // 当前 newShowRegion 的“宽高” 比例 double PicCtrl_WH_Ration = 1.0; // 当前图像控件的“宽高”比例 double newShowRegion_HW_Ration = 1.0; // 当前 newShowRegion 的“高宽”比例 double PicCtrl_HW_Ration = 1.0; // 当前图像控件的“高宽”比例 // 分母不为0判断 if ((newShowRegion.Height() > 0) && (m_PicCtrlHeight > 0)) { newShowRegion_WH_Ration = static_cast(newShowRegion.Width()) / static_cast(newShowRegion.Height()); PicCtrl_WH_Ration = static_cast(m_PicCtrlWidth) / static_cast(m_PicCtrlHeight); } else { return m_ShowRegion; } // 分母不为0判断 if ((newShowRegion_WH_Ration > 0.0) && (PicCtrl_WH_Ration > 0.0)) { newShowRegion_HW_Ration = 1.0 / newShowRegion_WH_Ration; PicCtrl_HW_Ration = 1.0 / PicCtrl_WH_Ration; } else { return m_ShowRegion; } if (newShowRegion_WH_Ration > PicCtrl_WH_Ration) // 宽度已经填满时 { // 图像上下填充 int newShowRegion_ideal_Height = 0; // 在现有图像显示宽度的基础上,图像显示区域的理想高度 newShowRegion_ideal_Height = static_cast(newShowRegion.Width() * PicCtrl_HW_Ration); // 上下补齐 newShowRegion.top -= static_cast((newShowRegion_ideal_Height - newShowRegion.Height() + 1)/ 2); // + 1 是考虑到 0.5 误差影响 newShowRegion.bottom += static_cast((newShowRegion_ideal_Height - newShowRegion.Height() + 1)/ 2); // + 1 是考虑到 0.5 误差影响 // 补齐后有可能越界 需进行修正 if (newShowRegion.top < 0) // 可能上边界越出图像边界 { newShowRegion.bottom -= newShowRegion.top; newShowRegion.top = 0L; if (newShowRegion.bottom > static_cast(_Height - 1)) { newShowRegion.bottom = static_cast(_Height - 1); } } if (newShowRegion.bottom > static_cast(_Height - 1)) // 可能下边界越出图像边界 { newShowRegion.top -= static_cast((newShowRegion.bottom - _Height + 1)); newShowRegion.bottom = static_cast(_Height - 1); if (newShowRegion.top < 0L) { newShowRegion.top = 0L; } } } else // 高度已经填满 { // 图像左右填充 int newShowRegion_ideal_Width = 0; // 在现有图像显示高度的基础上,图像显示区域的理想宽度 newShowRegion_ideal_Width = static_cast(newShowRegion.Height() * PicCtrl_WH_Ration); // 左右补齐 newShowRegion.left -= static_cast((newShowRegion_ideal_Width - newShowRegion.Width() + 1)/ 2); // + 1 是考虑到 0.5 误差影响 newShowRegion.right += static_cast((newShowRegion_ideal_Width - newShowRegion.Width() + 1)/ 2); // + 1 是考虑到 0.5 误差影响 // 补齐后有可能越界 需进行修正 if (newShowRegion.left < 0L) // 可能左边界越出图像边界 { newShowRegion.right -= newShowRegion.left; newShowRegion.left = 0L; if (newShowRegion.right > static_cast(_Width - 1)) { newShowRegion.right = static_cast(_Width - 1); } } if (newShowRegion.right > static_cast(_Width - 1)) // 可能右边界越出图像边界 { newShowRegion.left -= static_cast((newShowRegion.right - _Width + 1)); newShowRegion.right = static_cast(_Width - 1); if (newShowRegion.left < 0L) { newShowRegion.left = 0L; } } } // 在此修正,确保返回值有效 if (newShowRegion.left < 0) { newShowRegion.left = 0; } if (newShowRegion.right > _Width - 1) { newShowRegion.right = _Width - 1; } if (newShowRegion.top < 0) { newShowRegion.top = 0; } if (newShowRegion.bottom > _Height - 1) { newShowRegion.bottom = _Height - 1; } return newShowRegion; } catch(cv::Exception &e) { e.msg; return newShowRegion; } catch(...) { return newShowRegion; } } // 3.6 功能: 执行图像缩小操作 void CImgShowDlg::DoZoomOutImg() { try { // 计算图像显示区域,更新:ShowRegion /************************************************************************/ /* 设计思路: 分两种情况: 情况1:当前图像的全部内容已经全部显示出来,继续拉伸比例缩小显示即可 情况2:当前只显示出部分图像,计算新的显示区域 /************************************************************************/ // 是否已经显示全部图像内容 if ((m_ShowRegion.Width() == m_SrcFrame->width - 1) && (m_ShowRegion.Height() == m_SrcFrame->height - 1)) { if (max(m_ShowRegionOnScreen.Width(), m_ShowRegionOnScreen.Height()) > 10) { m_ImgRatioOnScreen *= 0.9F; } } else // 图像尚未完整显示 { // 自适应计算 ShowRegion m_ShowRegion = GetNewRegionWhenZoom(false); m_ImgRatioOnScreen = 1.0F; // 此时,无需拉伸比例控制 } // 显示图像 ShowOneImage(m_SrcFrame, TRUE, m_ShowRegion, m_ImgRatioOnScreen, m_ImgShowShift); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 3.7 功能: 当漫游图像时,自适应计算新的图像显示区 CRect CImgShowDlg::GetNewRegionWhenRoamImg(int deltaX, int deltaY) { // 返回值,初始化为当前显示区域 CRect newShowRegion = m_ShowRegion; // 新的图像显示区域 newShowRegion.left = m_ShowRegion.left - deltaX; newShowRegion.right = m_ShowRegion.right - deltaX; newShowRegion.top = m_ShowRegion.top - deltaY; newShowRegion.bottom = m_ShowRegion.bottom - deltaY; int m_Width = m_SrcFrame->width; int m_Height = m_SrcFrame->height; if (newShowRegion.left < 0L) { newShowRegion.right -= newShowRegion.left; newShowRegion.left = 0L; if (newShowRegion.right > static_cast(m_Width - 1)) { newShowRegion.right = static_cast(m_Width - 1); } } if (newShowRegion.right > static_cast(m_Width - 1)) { newShowRegion.left -= static_cast((newShowRegion.right - m_Width + 1)); newShowRegion.right = static_cast(m_Width - 1); if (newShowRegion.left < 0L) { newShowRegion.left = 0L; } } if (newShowRegion.top < 0) { newShowRegion.bottom -= newShowRegion.top; newShowRegion.top = 0L; if (newShowRegion.bottom > static_cast(m_Height - 1)) { newShowRegion.bottom = static_cast(m_Height - 1); } } if (newShowRegion.bottom > static_cast(m_Height - 1)) { newShowRegion.top -= static_cast((newShowRegion.bottom - m_Height + 1)); newShowRegion.bottom = static_cast(m_Height - 1); if (newShowRegion.top < 0L) { newShowRegion.top = 0L; } } // 在此修正,确保返回值有效 if (newShowRegion.left < 0) { newShowRegion.left = 0; } if (newShowRegion.right > m_Width - 1) { newShowRegion.right = m_Width - 1; } if (newShowRegion.top < 0) { newShowRegion.top = 0; } if (newShowRegion.bottom > m_Height - 1) { newShowRegion.bottom = m_Height - 1; } return newShowRegion; } // 3.8 功能: 执行图像全景(全屏)操作 void CImgShowDlg::DoZoomFitImg() { try { // 保证有图像 if (m_SrcFrame != NULL) { // 设置为整个图像显示 m_ShowRegion.left = 0L; m_ShowRegion.right = static_cast(m_SrcFrame->width - 1); m_ShowRegion.top = 0L; m_ShowRegion.bottom = static_cast(m_SrcFrame->height - 1); // 拉伸比例归1 m_ImgRatioOnScreen = 1.0F; // 复位 // 平移量归零 m_ImgShowShift.x = 0L; m_ImgShowShift.y = 0L; // 全景显示图像 ShowWholeImage(m_SrcFrame, m_ImgRatioOnScreen, m_ImgShowShift); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // CImgShowDlg 消息处理程序 BOOL CImgShowDlg::OnEraseBkgnd(CDC* pDC) { // 背景色为黑色 CRect Rect; GetClientRect(&Rect); pDC->FillSolidRect(Rect, RGB(0, 0, 0)); //设置窗口背景颜色为黑色 return TRUE; } void CImgShowDlg::OnPaint() { CPaintDC dc(this); // device context for painting try { if (m_SrcFrame != NULL) { // 重绘图像 ShowOneImage(m_SrcFrame, TRUE, m_ShowRegion, m_ImgRatioOnScreen, m_ImgShowShift); if (min(m_ShowRegionOnScreen.Width(), m_ShowRegionOnScreen.Height()) <= 10) { m_ImgRatioOnScreen = m_ImgRatioOnScreen / 0.9F; } if (m_bPlotRectOnPaint == TRUE) { // 标绘目标点 标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate), FALSE); } // 视场标绘 // SetQuadrangleCorners(m_corners); } else { if (m_sThemeText != "") { // 写字:图像窗口 // 获取窗口句柄 CWnd *pWnd = NULL; pWnd = GetDlgItem(IDC_IMG_SHOW_PIC_CTRL); if (pWnd == NULL) { return; } // 获得控件的 DC CDC *pDC = NULL; pDC = pWnd->GetDC(); if (pDC == NULL) { return; } CFont font; font.CreatePointFont(180,"Times New Roman"); CFont *pOldFont = pDC->SelectObject(&font); // 设置背景透明 pDC->SetBkMode(TRANSPARENT); // 设置字体颜色 pDC->SetTextColor(RGB(0,255,255)); // 确定输出位置 CRect Rect; GetClientRect(&Rect); int x = Rect.left + 5; int y = Rect.bottom - 28; // 输出信息 pDC->TextOutA(x, y, m_sThemeText); pDC->SelectObject(pOldFont); ReleaseDC(pDC); } } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 5.10 右键响应函数 // 功能:弹出右键菜单,进行功能选择 void CImgShowDlg::OnRButtonDown(UINT nFlags, CPoint point) { try { if (m_bCloseRughtBtnMenu == false) { // 加载菜单项 CMenu menu; menu.LoadMenu(IDR_MENU_IMG_PROCESS); // 保留右键坐标 由于定位导引 或 右键图像放大 m_RButtonPt = point; // 输入坐标为客户区坐标,也就是相对本对话框(左上角为(0,0))的坐标转换到屏幕坐标 ClientToScreen(&point); // 九宫格快速浏览图像 if (m_pFastLookUpDlg != NULL && m_pFastLookUpDlg->IsWindowVisible() == TRUE) { menu.GetSubMenu(0)->CheckMenuItem(ID_FAST_LOOKUP_IMGS, MF_BYCOMMAND | MF_CHECKED); } else { menu.GetSubMenu(0)->CheckMenuItem(ID_FAST_LOOKUP_IMGS, MF_BYCOMMAND | MF_UNCHECKED); } // menu.GetSubMenu(0)->EnableMenuItem(ID_FAST_LOOKUP_IMGS, MF_GRAYED); // MF_ENABLED // 标绘 目标 矩形 if (m_bDrawSquareOnImg == TRUE) { menu.GetSubMenu(0)->CheckMenuItem(ID_DRAW_SQUARE_ON_IMG, MF_BYCOMMAND | MF_CHECKED); } else { menu.GetSubMenu(0)->CheckMenuItem(ID_DRAW_SQUARE_ON_IMG, MF_BYCOMMAND | MF_UNCHECKED); } // 目标扣取 if (m_bGetTgtImgOn == true) { menu.GetSubMenu(0)->CheckMenuItem(ID_GET_TARGET_IMG, MF_BYCOMMAND | MF_CHECKED); } else { menu.GetSubMenu(0)->CheckMenuItem(ID_GET_TARGET_IMG, MF_BYCOMMAND | MF_UNCHECKED); } if (m_bClipImgOn == TRUE) { menu.GetSubMenu(0)->CheckMenuItem(ID_CLIP_IMG, MF_BYCOMMAND | MF_CHECKED); } else { menu.GetSubMenu(0)->CheckMenuItem(ID_CLIP_IMG, MF_BYCOMMAND | MF_UNCHECKED); } // 弹出菜单 menu.GetSubMenu(0)->TrackPopupMenu( TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, static_cast(point.x), static_cast(point.y), this); // 只在本窗口内作出相应 } CDialog::OnRButtonDown(nFlags, point); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:设置图像在屏幕中的显示比例 void CImgShowDlg::SetImgShowRationOnScreen(float ratio) { if(ratio >= 1.0F || ratio <= 0.0F) { ratio = 1.0F; } // 修改全局变量 ImgRatioOnScreen m_ImgRatioOnScreen = ratio; } void CImgShowDlg::OnZoomInImg() { try { // 如果有外部信号输入,操作与视频模式下相同 if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { SetImgShowRationOnScreen(m_ImgRatioOnScreen / 0.9F); return; } // 放大显示图像 DoZoomInImg(); // 更新标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate)); // 设置无效,不保留上次值 m_RButtonPt.x = -100; m_RButtonPt.y = -100; } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::OnZoomOutImg() { try { // 如果有外部信号输入 操作与视频模式下相同 if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { SetImgShowRationOnScreen(m_ImgRatioOnScreen * 0.9F); return; } // 缩小显示图像 DoZoomOutImg(); // 更新标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate)); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::OnZoomFitImg() { try { // 如果有外部信号输入 操作与视频模式下相同 if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { // 视频显示模式复位 m_ImgRatioOnScreen = 1.0F; m_ImgShowShift.x = 0L; m_ImgShowShift.y = 0L; return; } // 直接全景显示图像 DoZoomFitImg(); // 更新标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate)); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::OnConcelTargetPlot() { try { // 在onPaint中不重绘 m_bPlotRectOnPaint = FALSE; // 去掉上次标绘的框 InvalidateRect(&m_LatestPlotRect, FALSE); UpdateWindow(); // 发送消息 立即响应 // 设置为 小于0 的无效值 m_LButtonDblClkPixelCoordinate.x = -1; m_LButtonDblClkPixelCoordinate.y = -1; // 结束绘制 m_bPlotRect = FALSE; } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:保存当前帧图像及信息 BOOL CImgShowDlg::SaveCurrentDecodedFrame() { try { // 计算存储路径 static int imgSaveOrder = 1; // 图像数据有效 // 说明:程序设计中,SrcFrame代表当前图像 if (m_SrcFrame != NULL) { // 计算图像和复接数据存储路径 SYSTEMTIME CurrentTime; GetLocalTime(&CurrentTime); CString ImgSavePath; ImgSavePath.Format( "%04d%02d%02d_%02d%02d%02d%04d", CurrentTime.wYear, CurrentTime.wMonth, CurrentTime.wDay, CurrentTime.wHour, CurrentTime.wMinute, CurrentTime.wSecond, CurrentTime.wMilliseconds); // 添加序号 CString sImgSaveOlder; sImgSaveOlder.Format("%04d", imgSaveOrder); ImgSavePath = ImgSavePath + "_" + sImgSaveOlder; CString FJSavePath; FJSavePath = ImgSavePath; // 共享同一时间 CString FImgSavePath; FImgSavePath = ImgSavePath; // 共享同一时间 // 校验保存路径 if (m_sSaveCurrentImgFolder == "" || false == SearchDirectory(m_sSaveCurrentImgFolder)) { m_sSaveCurrentImgFolder = ""; } if (m_sSaveCurrentImgFolder == "") { ImgSavePath = m_sImgSaveFolder + "\\" + ImgSavePath + ".bmp"; // 完整图像存储路径 } else { ImgSavePath = m_sSaveCurrentImgFolder + "\\" + ImgSavePath + ".bmp"; // 完整图像存储路径 } // 确保有文件夹,如果中途误删,会再次创建 if (SearchDirectory(m_sRootFolder) == FALSE) // 没找到根文件夹 { CreateDirectory(m_sRootFolder, NULL); } if (SearchDirectory(m_sImgSaveFolder) == FALSE) // 没找到【图像】文件夹 { CreateDirectory(m_sImgSaveFolder, NULL); } // 转化 cv::Mat img(m_SrcFrame, false); // 保存图像 if (true == cv::imwrite(ImgSavePath.GetBuffer(0), img)) { // 保存路径回调 if (m_lpSendFilePath != NULL) { m_lpSendFilePath(ImgSavePath, 0); } } imgSaveOrder++; m_sSaveCurrentImgFolder = ""; // 复位 return TRUE; } return FALSE; } catch(cv::Exception &e) { e.msg; m_sSaveCurrentImgFolder = ""; // 复位 return FALSE; } catch(...) { m_sSaveCurrentImgFolder = ""; // 复位 return FALSE; } } // 保存当前帧 void CImgShowDlg::OnSaveCurrentFrame() { try { SaveCurrentDecodedFrame(); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:是否需要记忆前面多帧(18帧)图像信息 // 输入: // 1. bMem TRUE:记忆 FALSE:不记忆 // 输出:无 void CImgShowDlg::MemPreMultiFrame(BOOL bMem) { m_bMemPreMultiFrame = bMem; } // 左键按下消息响应 void CImgShowDlg::OnLButtonDown(UINT nFlags, CPoint point) { try { CDialog::OnLButtonDown(nFlags, point); if (m_SrcFrame == NULL) // 如果没有图像,不响应 { return; } // Alt = 1 Ctrl = 5 Shift = 9 if (nFlags == MK_CONTROL) // 当按住ctrl键时,不响应 因为与选择目标时冲突 { return; } // 更新鼠标坐标 m_LeftButtonDown = point; // 鼠标是否在图像上 if(m_LeftButtonDown.x > m_ShowRegionOnScreen.left && m_LeftButtonDown.x < m_ShowRegionOnScreen.right && m_LeftButtonDown.y > m_ShowRegionOnScreen.top && m_LeftButtonDown.y < m_ShowRegionOnScreen.bottom) { m_bStaisfyRoamImg = TRUE; // 计算一点的像素坐标 int ShowRegionWidth = m_ShowRegionOnScreen.Width() + 1; int ShowRegionHeight = m_ShowRegionOnScreen.Height() + 1; double ratioW = double(m_ShowRegion.Width() + 1) / ShowRegionWidth; double ratioH = double(m_ShowRegion.Height() + 1) / ShowRegionHeight; m_LButtonDownPixelCoordinate.x = static_cast((point.x - m_ShowRegionOnScreen.left) * ratioW + 0.5 + m_ShowRegion.left); m_LButtonDownPixelCoordinate.y = static_cast((point.y - m_ShowRegionOnScreen.top) * ratioH + 0.5 + m_ShowRegion.top); // 图像裁剪优先级高于目标扣取 if (m_bClipImgOn == true) { if (m_haveValidFirstPt == FALSE) { m_clipImgFirstPt = m_LButtonDownPixelCoordinate; m_clipImgFirstPtScreen = point; m_haveValidFirstPt = TRUE; } else { m_clipImgSecondPt = m_LButtonDownPixelCoordinate; m_haveValidFirstPt = FALSE; // 弹出裁剪提示 int Left = min(m_clipImgFirstPt.x, m_clipImgSecondPt.x); int Right = max(m_clipImgFirstPt.x, m_clipImgSecondPt.x); int Top = min(m_clipImgFirstPt.y, m_clipImgSecondPt.y); int Bottom = max(m_clipImgFirstPt.y, m_clipImgSecondPt.y); if (Right > Left && Bottom > Top) { cv::Mat img(m_SrcFrame, false); cv::Mat clipedImg; img(cv::Range(Top, Bottom), cv::Range(Left, Right)).copyTo(clipedImg); int ret = ::MessageBoxA(NULL, _T("确定裁剪图像?"),_T("操作提示"), MB_YESNO | MB_SYSTEMMODAL); if (ret == IDNO) { Invalidate(); } else { m_bClipImgOn = false; // 创建临时情报结构体 QBStru qbLocal; qbLocal.image.bValid = true; qbLocal.framePart.bValid = false; qbLocal.image.srcImg.ImgWidth = clipedImg.cols; qbLocal.image.srcImg.ImgHeight = clipedImg.rows; qbLocal.image.srcImg.bitcount = clipedImg.channels() * 8; // 步长:每行像素所占字节数 int lineByte = (clipedImg.cols * clipedImg.channels()); // 位图数据缓冲区的大小,即图像大小 int imgBufSize = clipedImg.rows * lineByte; if (imgBufSize > 0) { qbLocal.image.srcImg.buff = new BYTE[imgBufSize]; if (qbLocal.image.srcImg.buff != nullptr) { // 复制实际字节数 memcpy(qbLocal.image.srcImg.buff, clipedImg.data, static_cast(imgBufSize)); // 图像数据复制 if (m_boundbingBox.EastLon - m_boundbingBox.WestLon > 0 && m_boundbingBox.WestLon >= -180 && m_boundbingBox.WestLon <= 180 && m_boundbingBox.EastLon >= -180 && m_boundbingBox.EastLon <= 180 && m_boundbingBox.NorthLat - m_boundbingBox.SouthLat > 0 && m_boundbingBox.SouthLat >= -90 && m_boundbingBox.SouthLat <= 90 && m_boundbingBox.NorthLat >= -90 && m_boundbingBox.NorthLat <= 90) { m_ImgRatioOnScreen = 0.9f; // 设置经纬度盒子 GeoBoundingBox LLBox; double lonResolution = (m_boundbingBox.EastLon - m_boundbingBox.WestLon) / img.cols; double latResolution = (m_boundbingBox.NorthLat - m_boundbingBox.SouthLat) / img.rows; LLBox.WestLon = m_boundbingBox.WestLon + Left * lonResolution; LLBox.EastLon = m_boundbingBox.WestLon + Right * lonResolution; LLBox.NorthLat = m_boundbingBox.NorthLat - Top * latResolution; LLBox.SouthLat = m_boundbingBox.NorthLat - Bottom * latResolution; qbLocal.image.srcImg.BoundingBox = LLBox; DisposeQBData(&qbLocal); SetBoundingBox(LLBox); SAFE_DELETE_ARRAY(m_midImg.buff); m_midImg.buff = NULL; m_iLatest = 0; } else { if (qbLocal.framePart.bValid == true) { int ret = ::MessageBoxA(NULL, _T("提示:图像将丧失定位能力,是否继续?"),_T("操作提示"), MB_OKCANCEL); if (ret == IDOK) { m_ImgRatioOnScreen = 0.9f; DisposeQBData(&qbLocal); SAFE_DELETE_ARRAY(m_midImg.buff); m_midImg.buff = NULL; m_iLatest = 0; } else { Invalidate(); } } else { m_ImgRatioOnScreen = 0.9f; DisposeQBData(&qbLocal); SAFE_DELETE_ARRAY(m_midImg.buff); m_midImg.buff = NULL; m_iLatest = 0; } } delete [] qbLocal.image.srcImg.buff; qbLocal.image.srcImg.buff = NULL; } } } } } } else { // 目标扣取 if (m_bGetTgtImgOn == true) { if (m_haveValidFirstPt == FALSE) { m_clipImgFirstPt = m_LButtonDownPixelCoordinate; m_clipImgFirstPtScreen = point; m_haveValidFirstPt = TRUE; } else { m_clipImgSecondPt = m_LButtonDownPixelCoordinate; m_haveValidFirstPt = FALSE; // 弹出裁剪提示 int Left = min(m_clipImgFirstPt.x, m_clipImgSecondPt.x); int Right = max(m_clipImgFirstPt.x, m_clipImgSecondPt.x); int Top = min(m_clipImgFirstPt.y, m_clipImgSecondPt.y); int Bottom = max(m_clipImgFirstPt.y, m_clipImgSecondPt.y); if (Right > Left && Bottom > Top) { cv::Mat img(m_SrcFrame, false); cv::Mat clipedImg; img(cv::Range(Top, Bottom), cv::Range(Left, Right)).copyTo(clipedImg); int ret = ::MessageBoxA(NULL, _T("确定抓取目标图像?"),_T("操作提示"), MB_YESNO | MB_SYSTEMMODAL); if (ret == IDNO) { Invalidate(); } else { m_bGetTgtImgOn = false; // 计算图像和复接数据存储路径 SYSTEMTIME CurrentTime; GetLocalTime(&CurrentTime); CString ImgSavePath; ImgSavePath.Format( "%04d%02d%02d_%02d%02d%02d%04d.jpg", CurrentTime.wYear, CurrentTime.wMonth, CurrentTime.wDay, CurrentTime.wHour, CurrentTime.wMinute, CurrentTime.wSecond, CurrentTime.wMilliseconds); // 确保有文件夹,如果中途误删,会再次创建 CString tgtFolder = GetSoftwareCurrentDirectory() + "\\targets"; if (SearchDirectory(tgtFolder) == FALSE) // 没找到根文件夹 { CreateDirectory(tgtFolder, NULL); } CString savePath = tgtFolder + "\\" + ImgSavePath; cv::imwrite(savePath.GetBuffer(0) ,clipedImg); if (m_lpSendFilePath != nullptr) { m_lpSendFilePath(savePath, 7); } } } } } } } else { m_bStaisfyRoamImg = FALSE; } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:向图像中添加 经纬高 位置信息 // 输入: // 1: qb: 情报结构体 // 2: pt: 像素坐标 // 3. Lon: 经度 // 4. Lat: 纬度 // 5. H: 高度 // 返回值:无 void CImgShowDlg::TagLocationOnImgStru(ImgStru &imgData, cv::Point pt, double Lon, double Lat, double H) { try { if (imgData.ImgWidth <= 0 || imgData.ImgHeight <= 0 || (imgData.bitcount != 8 && imgData.bitcount != 24) || imgData.buff == NULL) { return; } if (pt.x < 0 || pt.y < 0) { return; } if (Lon < -180 || Lon > 180 || Lat < -90 || Lat > 90) { return; } if (imgData.ImgWidth > 0 && imgData.ImgHeight > 0 && (imgData.bitcount == 8 || imgData.bitcount == 24) && imgData.buff != NULL) { cv::Mat img; unsigned int imgBufSize = 0; if (imgData.bitcount == 8 && imgData.ImgHeight * imgData.ImgWidth > 0) { img = cv::Mat(imgData.ImgHeight, imgData.ImgWidth, CV_8UC1); imgBufSize = static_cast(imgData.ImgHeight * imgData.ImgWidth); } else if (imgData.bitcount == 24 && imgData.ImgHeight * imgData.ImgWidth * 3 > 0) { img = cv::Mat(imgData.ImgHeight, imgData.ImgWidth, CV_8UC3); imgBufSize = static_cast(imgData.ImgHeight * imgData.ImgWidth * 3); } memcpy(img.data, imgData.buff, imgBufSize); // 图像数据复制 CString sLon; CString sLat; CString sH; sLon.Format("%.6f", Lon); sLat.Format("%.6f", Lat); sH.Format("%.1f", H); sLon = "Lon:" + sLon; sLat = "Lat:" + sLat; sH = "H:" + sH; cv::Scalar color(0, 255, 255); cv::circle(img, pt, 2, color, 2); if (pt.x > (img.cols - 100)) { cv::putText(img, sLon.GetBuffer(0), cv::Point(pt.x + 5 - 100, pt.y + 4 + 15), 1, 1, color); cv::putText(img, sLat.GetBuffer(0), cv::Point(pt.x + 5 - 100, pt.y + 4 + 15 + 15), 1, 1, color); cv::putText(img, sH.GetBuffer(0), cv::Point(pt.x + 5 - 100, pt.y + 4 + 30 + 15), 1, 1, color); } else { cv::putText(img, sLon.GetBuffer(0), cv::Point(pt.x + 5, pt.y + 4), 1, 1, color); cv::putText(img, sLat.GetBuffer(0), cv::Point(pt.x + 5, pt.y + 4 + 15), 1, 1, color); cv::putText(img, sH.GetBuffer(0), cv::Point(pt.x + 5, pt.y + 4 + 30), 1, 1, color); } memcpy(imgData.buff, img.data, imgBufSize); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 向图像中写信息 void CImgShowDlg::TagLocationOnQBData(QBStru &qb, cv::Point pt, double Lon, double Lat, double H) { try { if (qb.image.bValid == true) { return; } if (pt.x < 0 || pt.y < 0) { return; } if (Lon < -180 || Lon > 180 || Lat < -90 || Lat > 90) { return; } // srcImg TagLocationOnImgStru(qb.image.srcImg, pt, Lon, Lat, H); // dstImg TagLocationOnImgStru(qb.image.dstImg, pt, Lon, Lat, H); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:向图像中添加 经纬高 位置信息 // 输入: // 1: img: 情报结构体 // 2: pt: 像素坐标 // 3. Lon: 经度 // 4. Lat: 纬度 // 5. H: 高度 // 返回值:无 void CImgShowDlg::TagLocationOnMatImg(cv::Mat &img, cv::Point pt, double Lon, double Lat, double H) { try { if (img.empty() == true || img.cols <= 0 || img.rows <= 0) { return; } if (pt.x < 0 || pt.y < 0) { return; } if (Lon < -180 || Lon > 180 || Lat < -90 || Lat > 90) { return; } CString sLon; CString sLat; CString sH; sLon.Format("%.6f", Lon); sLat.Format("%.6f", Lat); sH.Format("%.1f", H); sLon = "Lon:" + sLon; sLat = "Lat:" + sLat; sH = "H:" + sH; cv::Scalar color(0, 255, 255); cv::circle(img, pt, 3, color, 2); if (pt.x > (img.cols - 100)) { cv::putText(img, sLon.GetBuffer(0), cv::Point(pt.x + 5 - 100, pt.y + 4 + 15), 1, 1, color); cv::putText(img, sLat.GetBuffer(0), cv::Point(pt.x + 5 - 100, pt.y + 4 + 15 + 15), 1, 1, color); cv::putText(img, sH.GetBuffer(0), cv::Point(pt.x + 5 - 100, pt.y + 4 + 30 + 15), 1, 1, color); } else { cv::putText(img, sLon.GetBuffer(0), cv::Point(pt.x + 5, pt.y + 4), 1, 1, color); cv::putText(img, sLat.GetBuffer(0), cv::Point(pt.x + 5, pt.y + 4 + 15), 1, 1, color); cv::putText(img, sH.GetBuffer(0), cv::Point(pt.x + 5, pt.y + 4 + 30), 1, 1, color); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:向图像中添加 文字 信息 // 输入: // 1: imgData: 图像结构体 // 2: pt: 像素坐标 // 3. text: 文字信息 // 返回值:无 void CImgShowDlg::TagTextOnImgStru(ImgStru &imgData, cv::Point pt, CString text) { try { if (imgData.ImgWidth <= 0 || imgData.ImgHeight <= 0 || (imgData.bitcount != 8 && imgData.bitcount != 24) || imgData.buff == NULL) { return; } if (text == "") { return; } if (pt.x < 0 || pt.y < 0) { return; } if (imgData.ImgWidth > 0 && imgData.ImgHeight > 0 && (imgData.bitcount == 8 || imgData.bitcount == 24) && imgData.buff != NULL) { cv::Mat img; unsigned int imgBufSize = 0; if (imgData.bitcount == 8) { img = cv::Mat(imgData.ImgHeight, imgData.ImgWidth, CV_8UC1); imgBufSize = static_cast(imgData.ImgHeight * imgData.ImgWidth); } else { img = cv::Mat(imgData.ImgHeight, imgData.ImgWidth, CV_8UC3); imgBufSize = static_cast(imgData.ImgHeight * imgData.ImgWidth * 3); } memcpy(img.data, imgData.buff, imgBufSize); // 图像数据复制 cv::Scalar color(0, 255, 255); cv::putText(img, text.GetBuffer(0), cv::Point(pt.x + 5, pt.y - 5), 1, 1, color); memcpy(imgData.buff, img.data, imgBufSize); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:向图像中添加 文字 信息 // 输入: // 1: qb: 情报结构体 // 2: pt: 像素坐标 // 3. text: 文字信息 // 返回值:无 void CImgShowDlg::TagTextOnQBData(QBStru &qb, cv::Point pt, CString text) { try { if (qb.image.bValid == 0 || text == "") { return; } if (pt.x < 0 || pt.y < 0) { return; } // srcImg TagTextOnImgStru(qb.image.srcImg, pt, text); // dstImg TagTextOnImgStru(qb.image.dstImg, pt, text); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:向图像中添加 文字 信息 // 输入: // 1: img: 情报结构体 // 2: pt: 像素坐标 // 3. text: 文字信息 // 返回值:无 void CImgShowDlg::TagTextOnMatImg(cv::Mat &img, cv::Point pt, CString text) { try { if (img.empty() == true || text == "" || img.cols <= 0 || img.rows <= 0) { return; } if (pt.x < 0 || pt.y < 0) { return; } cv::Scalar color(0, 255, 255); cv::putText(img, text.GetBuffer(0), cv::Point(pt.x + 5, pt.y - 5), 1, 1, color); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::TagInfoReviseShotOnMatImg(cv::Mat &img, cv::Point pt1, cv::Point pt2, double *LLA1, double *LLA2) { try { if (img.empty() == true || img.cols <= 0 || img.rows <= 0) { return; } if (pt1.x < 0 || pt1.x > img.cols - 1 || pt1.y < 0 || pt1.y > img.rows - 1) { return; } if (pt2.x < 0 || pt2.x > img.cols - 1 || pt2.y < 0 || pt2.y > img.rows - 1) { return; } if (LLA1[0] < -180 || LLA1[0] > 180 || LLA1[1] < -90 || LLA1[1] > 90) { return; } if (LLA2[0] < -180 || LLA2[0] > 180 || LLA2[1] < -90 || LLA2[1] > 90) { return; } // 计算距离和方位 // 计算角度 double distance = 0.0; // 距离 double azAngle = 0.0; // 方位 // 计算两点间的距离和方位(顺时针:0 - 360) CalculateTwoPtsDistanceAzimuth(distance, azAngle, LLA1[0], LLA1[1], LLA2[0], LLA2[1], 3); // 计算 pt1 和 pt2 在图像中的夹角 const int R = 30; double theta = 0; if (pt1.x == pt2.x && pt1.y > pt2.y) { theta = 0; } else if (pt1.x < pt2.x && pt1.y > pt2.y) { theta = atan2(double(pt2.x - pt1.x), double(pt1.y - pt2.y)) * 180 / 3.1415926; } else if (pt1.x < pt2.x && pt1.y == pt2.y) { theta = 90; } else if (pt1.x < pt2.x && pt1.y < pt2.y) { theta = atan2(double(pt2.y - pt1.y), double(pt2.x - pt1.x)) * 180 / 3.1415926 + 90; } else if (pt1.x == pt2.x && pt1.y < pt2.y) { theta = 180; } else if (pt1.x > pt2.x && pt1.y < pt2.y) { theta = atan2(double(pt1.x - pt2.x), double(pt2.y - pt1.y)) * 180 / 3.1415926 + 180; } else if (pt1.x > pt2.x && pt1.y == pt2.y) { theta = 270; } else { theta = atan2(double(pt1.y - pt2.y), double(pt1.x - pt2.x)) * 180 / 3.1415926 + 270; } // 计算 cv::Scalar color = cv::Scalar(0,0, 255); cv::Point pt3; cv::Point pt4; pt3.x = pt2.x - static_cast(R * cos((90 - theta - 30) * 3.1415926 / 180)); pt3.y = pt2.y + static_cast(R * sin((90 - theta - 30) * 3.1415926 / 180)); pt4.x = pt2.x - static_cast(R * cos((90 - theta + 30) * 3.1415926 / 180)); pt4.y = pt2.y + static_cast(R * sin((90 - theta + 30) * 3.1415926 / 180)); cv::line(img, pt1, pt2, color, 1, 16); cv::line(img, pt2, pt3, color, 1, 16); cv::line(img, pt2, pt4, color, 1, 16); CString sDistance; CString sAngle; if (distance > 1000) { sDistance.Format("%.3fkm", distance / 1000); } else { sDistance.Format("%.1fm", distance); } sAngle.Format("%.1fd", azAngle); color = cv::Scalar(255, 0, 0); cv::putText(img, sDistance.GetBuffer(0), cv::Point(pt2.x + 5, pt2.y + 4), 1, 1, color); cv::putText(img, sAngle.GetBuffer(0), cv::Point(pt2.x + 5, pt2.y + 4 + 15), 1, 1, color); // 写字:“目标” color = cv::Scalar(0,0, 255); cv::putText(img, "T", cv::Point(pt1.x, pt1.y), 1, 2, color, 2); // 火炮校射信息回调输出 if (m_lpSendArtilleryReviseInfo != NULL) { m_lpSendArtilleryReviseInfo(float(distance), float(azAngle)); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::TagInfoReviseShotOnImgStru(ImgStru &imgData, cv::Point pt1, cv::Point pt2, double *LLA1, double *LLA2) { try { if (imgData.ImgWidth <= 0 || imgData.ImgHeight <= 0 || (imgData.bitcount != 8 && imgData.bitcount != 24) || imgData.buff == NULL) { return; } if (pt1.x < 0 || pt1.x > imgData.ImgWidth - 1 || pt1.y < 0 || pt1.y > imgData.ImgHeight - 1) { return; } if (pt2.x < 0 || pt2.x > imgData.ImgWidth - 1 || pt2.y < 0 || pt2.y > imgData.ImgHeight - 1) { return; } if (LLA1[0] < -180 || LLA1[0] > 180 || LLA1[1] < -90 || LLA1[1] > 90) { return; } if (LLA2[0] < -180 || LLA2[0] > 180 || LLA2[1] < -90 || LLA2[1] > 90) { return; } if (imgData.ImgWidth > 0 && imgData.ImgHeight > 0 && (imgData.bitcount == 8 || imgData.bitcount == 24) && imgData.buff != NULL) { cv::Mat img; unsigned int imgBufSize = 0; if (imgData.bitcount == 8) { img = cv::Mat(imgData.ImgHeight, imgData.ImgWidth, CV_8UC1); imgBufSize = static_cast(imgData.ImgHeight * imgData.ImgWidth); } else { img = cv::Mat(imgData.ImgHeight, imgData.ImgWidth, CV_8UC3); imgBufSize = static_cast(imgData.ImgHeight * imgData.ImgWidth * 3); } memcpy(img.data, imgData.buff, imgBufSize); // 图像数据复制 TagInfoReviseShotOnMatImg(img, pt1, pt2, LLA1, LLA2); memcpy(imgData.buff, img.data, imgBufSize); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::TagInfoReviseShotOnQBData(QBStru &qb, cv::Point pt1, cv::Point pt2, double *LLA1, double *LLA2) { try { if (qb.image.bValid == 0) { return; } // srcImg TagInfoReviseShotOnImgStru(qb.image.srcImg, pt1, pt2, LLA1, LLA2); // dstImg TagInfoReviseShotOnImgStru(qb.image.dstImg, pt1, pt2, LLA1, LLA2); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 左键双击消息响应 void CImgShowDlg::OnLButtonDblClk(UINT nFlags, CPoint point) { if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { return; } try { CDialog::OnLButtonDblClk(nFlags, point); // 要求按住Ctrl键 if ((m_SrcFrame != NULL)/* && (nFlags == MK_CONTROL + 1)*/) // SrcFrame 按住ctrl时,nFlags = 9 { // 计算 CPoint point 对应的像素坐标 CPoint LButtonDblClkPixelCoordinate; if ((point.x > m_ShowRegionOnScreen.left) && (point.x < m_ShowRegionOnScreen.right) && (point.y > m_ShowRegionOnScreen.top) && (point.y < m_ShowRegionOnScreen.bottom)) // 鼠标在图像上 { // 计算一点的像素坐标 int ShowRegionWidth = m_ShowRegionOnScreen.Width() + 1; int ShowRegionHeight = m_ShowRegionOnScreen.Height() + 1; double ratioW = double(m_ShowRegion.Width() + 1) / ShowRegionWidth; double ratioH = double(m_ShowRegion.Height() + 1) / ShowRegionHeight; m_LButtonDblClkPixelCoordinate.x = static_cast((point.x - m_ShowRegionOnScreen.left) * ratioW + 0.5 + m_ShowRegion.left); m_LButtonDblClkPixelCoordinate.y = static_cast((point.y - m_ShowRegionOnScreen.top) * ratioH + 0.5 + m_ShowRegion.top); // 地图匹配定位时,在图像中标绘目标 if (m_lpSendTgrLocLeadLonLat != NULL && m_bDrawSquareOnImg == TRUE) { cv::Mat DrawTargetImg(m_SrcFrame, false); cv::Scalar color; cv::Mat Mask = Mat::zeros(DrawTargetImg.size(), CV_8U); if (DrawTargetImg.type() == 0) { color = cv::Scalar(255); } else { color = cv::Scalar(0, 0, 255); } // 清理上次矩形标绘 cv::Point leftUp = m_TargetCenter + cv::Point(-25, -25); cv::Point rightUp = m_TargetCenter + cv::Point(+25, -25); cv::Point rightDown = m_TargetCenter + cv::Point(+25, +25); cv::Point leftDown = m_TargetCenter + cv::Point(-25, +25); try { cv::line(Mask, leftUp, rightUp, cv::Scalar(255), 1, 16); cv::line(Mask, leftUp, leftDown, cv::Scalar(255), 1, 16); cv::line(Mask, leftDown, rightDown, cv::Scalar(255), 1, 16); cv::line(Mask, rightUp, rightDown, cv::Scalar(255), 1, 16); cv::inpaint(DrawTargetImg, Mask, DrawTargetImg, 3, CV_INPAINT_TELEA); } catch (cv::Exception &e) { // 继续执行 即使修补失败,也能输出单点定位结果 e; } // 确定矩形四个点 cv::Point center = cv::Point(m_LButtonDblClkPixelCoordinate.x, m_LButtonDblClkPixelCoordinate.y); leftUp = center + cv::Point(-25, -25); rightUp = center + cv::Point(+25, -25); rightDown = center + cv::Point(+25, +25); leftDown = center + cv::Point(-25, +25); cv::line(DrawTargetImg, leftUp, rightUp, color, 1, 16); cv::line(DrawTargetImg, leftUp, leftDown, color, 1, 16); cv::line(DrawTargetImg, leftDown, rightDown, color, 1, 16); cv::line(DrawTargetImg, rightUp, rightDown, color, 1, 16); // 上一次无效时,本次重绘 if (m_TargetCenter.x = -100 && m_TargetCenter.y == -100) { OnPaint(); } // 更新记忆 m_TargetCenter = center; } else { m_bDrawSquareOnImg = FALSE; m_TargetCenter = cv::Point(-100, -100); } // 绘制标框 // 设计技巧:利用m_bPlotRectOnPaint,避免在OnPaint中重绘一次 m_bPlotRectOnPaint = FALSE; DrawSquareOnScreen(point, TRUE); m_bPlotRectOnPaint = TRUE; // 函数回调 对外输出目标坐标 if (m_lpSendCoordinate != NULL) // 函数指针有效性判断 { m_lpSendCoordinate(m_LButtonDblClkPixelCoordinate); } // 对外输出像素信息:王家星 20150721 原因:解决多次双击时的像素信息输出问题 //新增功能:计算当前图像 像素坐标 经纬度坐标 RGB值 回调输出 // 计算 CPoint point 对应的像素坐标 CPoint LButtonDblClkPixelCoordinate; if ((point.x > m_ShowRegionOnScreen.left) && (point.x < m_ShowRegionOnScreen.right) && (point.y > m_ShowRegionOnScreen.top) && (point.y < m_ShowRegionOnScreen.bottom)) // 鼠标在图像上 { // 图像尺寸与显示区域尺寸之间的比例 double ratio = 1.0; // 分母0值判断 if (m_ShowRegionOnScreen.Width() > 0) { ratio = (m_ShowRegion.Width() * 1.0) / m_ShowRegionOnScreen.Width(); } // 像素坐标 m_imgPixel_XY_Coordinate.x = static_cast((point.x - m_ShowRegionOnScreen.left) * ratio) + m_ShowRegion.left; m_imgPixel_XY_Coordinate.y = static_cast((point.y - m_ShowRegionOnScreen.top) * ratio) + m_ShowRegion.top; // 经纬度坐标 double Lon = 0.0; double Lat = 0.0; double H = 0; if (true == DoCalAnyPtCoordinate(Lon, Lat, H, &m_LatestQBData.framePart, m_imgPixel_XY_Coordinate.x, m_imgPixel_XY_Coordinate.y)) { m_imgPixel_LBH_Coordinate.x = Lon + m_deltaLon; m_imgPixel_LBH_Coordinate.y = Lat + m_deltaLat; CString DEMpath = GetSoftwareCurrentDirectory() + "\\ElevationData"; float fDem = 0; GetElevation(fDem, m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, DEMpath.GetBuffer(0)); m_imgPixel_LBH_Coordinate.z = fDem; } else { if (m_boundbingBox.EastLon - m_boundbingBox.WestLon > 0 && m_boundbingBox.WestLon >= -180 && m_boundbingBox.WestLon <= 180 && m_boundbingBox.EastLon >= -180 && m_boundbingBox.EastLon <= 180 && m_boundbingBox.NorthLat - m_boundbingBox.SouthLat > 0 && m_boundbingBox.SouthLat >= -90 && m_boundbingBox.SouthLat <= 90 && m_boundbingBox.NorthLat >= -90 && m_boundbingBox.NorthLat <= 90) { double LonResolution = (m_boundbingBox.EastLon - m_boundbingBox.WestLon) / m_SrcFrame->width; double LatResolution = (m_boundbingBox.NorthLat - m_boundbingBox.SouthLat) / m_SrcFrame->height; m_imgPixel_LBH_Coordinate.x = (m_boundbingBox.WestLon + m_imgPixel_XY_Coordinate.x * LonResolution); m_imgPixel_LBH_Coordinate.y = (m_boundbingBox.NorthLat - m_imgPixel_XY_Coordinate.y * LatResolution); // 修正 m_imgPixel_LBH_Coordinate.x += (m_deltaLon); m_imgPixel_LBH_Coordinate.y += (m_deltaLat); CString DEMpath = GetSoftwareCurrentDirectory() + "\\ElevationData"; float fDem = 0; GetElevation(fDem, m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, DEMpath.GetBuffer(0)); m_imgPixel_LBH_Coordinate.z = fDem; } else { m_imgPixel_LBH_Coordinate.x = -200.0; m_imgPixel_LBH_Coordinate.y = -200.0; m_imgPixel_LBH_Coordinate.z = -200.0; } } } else { // 设置为 小于0 的无效值 m_imgPixel_XY_Coordinate.x = -1; m_imgPixel_XY_Coordinate.y = -1; m_imgPixel_LBH_Coordinate.x = -200.0; m_imgPixel_LBH_Coordinate.y = -200.0; m_imgPixel_LBH_Coordinate.z = -200.0; } // 定位标记 if (m_iImgEditType == 0) { m_bHaveOnPt = false; // 清零 m_bEnhanceEdit = true; // 增强 } else if (m_iImgEditType == 1) // 定位标记 { m_bEnhanceEdit = false; // 编辑 // 未作任何处理 if (m_LatestQBData.image.dstImg.buff == NULL/* && m_midImg.buff == NULL*/) { CloneImgStru(m_LatestQBData.image.srcImg, m_LatestQBData.image.dstImg); CloneImgStru(m_LatestQBData.image.srcImg, m_midImg); TagLocationOnImgStru(m_LatestQBData.image.dstImg, cv::Point(m_imgPixel_XY_Coordinate.x, m_imgPixel_XY_Coordinate.y), m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, m_imgPixel_LBH_Coordinate.z); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); TagLocationOnImgStru(m_LatestQBData.image.dstImg, cv::Point(m_imgPixel_XY_Coordinate.x, m_imgPixel_XY_Coordinate.y), m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, m_imgPixel_LBH_Coordinate.z); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } } else if (m_iImgEditType == 2) // 文字标记 { m_bEnhanceEdit = false; // 编辑 CAddTextDlg addTextDlg; if (addTextDlg.DoModal() == IDOK) { CString inputText = addTextDlg.GetText(); // 未作任何处理 if (m_LatestQBData.image.dstImg.buff == NULL/* && m_midImg.buff == NULL*/) { CloneImgStru(m_LatestQBData.image.srcImg, m_LatestQBData.image.dstImg); CloneImgStru(m_LatestQBData.image.srcImg, m_midImg); TagTextOnImgStru(m_LatestQBData.image.dstImg, cv::Point(m_imgPixel_XY_Coordinate.x, m_imgPixel_XY_Coordinate.y), inputText); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); TagTextOnImgStru(m_LatestQBData.image.dstImg, cv::Point(m_imgPixel_XY_Coordinate.x, m_imgPixel_XY_Coordinate.y), inputText); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } } } else if (m_iImgEditType == 3) // 火炮校射标记 { m_bEnhanceEdit = false; // 编辑 if (m_bHaveOnPt == false) { m_bHaveOnPt = true; m_beginPixPt.x = m_LButtonDblClkPixelCoordinate.x; m_beginPixPt.y = m_LButtonDblClkPixelCoordinate.y; m_beginLLA[0] = m_imgPixel_LBH_Coordinate.x; m_beginLLA[1] = m_imgPixel_LBH_Coordinate.y; m_beginLLA[2] = m_imgPixel_LBH_Coordinate.z; } else { m_bHaveOnPt = false; m_endPixPt.x = m_LButtonDblClkPixelCoordinate.x; m_endPixPt.y = m_LButtonDblClkPixelCoordinate.y; m_endLLA[0] = m_imgPixel_LBH_Coordinate.x; m_endLLA[1] = m_imgPixel_LBH_Coordinate.y; m_endLLA[2] = m_imgPixel_LBH_Coordinate.z; // 未作任何处理 if (m_LatestQBData.image.dstImg.buff == NULL/* && m_midImg.buff == NULL*/) { CloneImgStru(m_LatestQBData.image.srcImg, m_LatestQBData.image.dstImg); CloneImgStru(m_LatestQBData.image.srcImg, m_midImg); TagInfoReviseShotOnImgStru(m_LatestQBData.image.dstImg, m_beginPixPt, m_endPixPt, m_beginLLA, m_endLLA); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); TagInfoReviseShotOnImgStru(m_LatestQBData.image.dstImg, m_beginPixPt, m_endPixPt, m_beginLLA, m_endLLA); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3 && srcFrameMat.data != NULL && m_LatestQBData.image.dstImg.buff != NULL && srcFrameMat.cols > 0 && srcFrameMat.rows > 0 && srcFrameMat.cols * srcFrameMat.rows < 1e8) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } } } else { m_bEnhanceEdit = true; // 增强 } // 回调输出信息即可 if (m_lpSendPixInfoProc != NULL) { CPoint pt; pt.x = m_imgPixel_XY_Coordinate.x; pt.y = m_imgPixel_XY_Coordinate.y; m_lpSendPixInfoProc(pt, m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, m_imgPixel_LBH_Coordinate.z); } } else { // 设置为 小于0 的无效值 m_LButtonDblClkPixelCoordinate.x = -1; m_LButtonDblClkPixelCoordinate.y = -1; } } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:获取当前图像中心的经纬度坐标 bool CImgShowDlg::GetCurrentImgCenterLonLat(double &lon, double &lat) { try { if (m_SrcFrame == NULL) { return false; } // 经纬度坐标 double Lon = 0.0; double Lat = 0.0; double H = 0; if (true == DoCalImgCenterCoordinate(Lon, Lat, H, &m_LatestQBData.framePart)) { lon = Lon + m_deltaLon; lat = Lat + m_deltaLat; return true; } else { if (m_boundbingBox.EastLon - m_boundbingBox.WestLon > 0 && m_boundbingBox.WestLon >= -180 && m_boundbingBox.WestLon <= 180 && m_boundbingBox.EastLon >= -180 && m_boundbingBox.EastLon <= 180 && m_boundbingBox.NorthLat - m_boundbingBox.SouthLat > 0 && m_boundbingBox.SouthLat >= -90 && m_boundbingBox.SouthLat <= 90 && m_boundbingBox.NorthLat >= -90 && m_boundbingBox.NorthLat <= 90) { lon = (m_boundbingBox.EastLon - m_boundbingBox.WestLon) / 2 + m_boundbingBox.WestLon; lat = (m_boundbingBox.NorthLat - m_boundbingBox.SouthLat) / 2 + m_boundbingBox.SouthLat; return true; } } return false; } catch(cv::Exception &e) { e.msg; return false; } catch(...) { return false; } } // 鼠标移动消息响应 void CImgShowDlg::OnMouseMove(UINT nFlags, CPoint point) { try { CDialog::OnMouseMove(nFlags, point); if (nFlags == MK_LBUTTON) // 首要条件:左键按下 { // 如果有外部信号输入 操作与视频模式相同 if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { if(m_bSatisfyMove == TRUE) { // 更新偏移量 m_ImgShowShift.x += (point.x - m_LeftButtonDown.x); m_ImgShowShift.y += (point.y - m_LeftButtonDown.y); // 更新鼠标左键按下点 m_LeftButtonDown = point; } return; } // 满足图像漫游条件 if(m_bStaisfyRoamImg == TRUE) { // 图像未全部显示 if (m_ShowRegion.Width() < m_SrcFrame->width - 1 || m_ShowRegion.Height() < m_SrcFrame->height - 1) { // 策略1:更新显示区域 int ShowRegionWidth = m_ShowRegionOnScreen.Width() + 1; int ShowRegionHeight = m_ShowRegionOnScreen.Height() + 1; double ratioW = double(m_ShowRegion.Width() + 1) / ShowRegionWidth; double ratioH = double(m_ShowRegion.Height() + 1) / ShowRegionHeight; // 像素坐标偏移量 int delatX = int((point.x - m_LeftButtonDown.x) * ratioW); int delatY = int((point.y - m_LeftButtonDown.y) * ratioH); m_LeftButtonDown = point; // 计算显示区域 CRect new_ShowRegion = GetNewRegionWhenRoamImg(delatX, delatY); // 如果有显示区域变动 if( new_ShowRegion.left - m_ShowRegion.left != 0 || new_ShowRegion.right - m_ShowRegion.right != 0 || new_ShowRegion.top - m_ShowRegion.top != 0 || new_ShowRegion.bottom - m_ShowRegion.bottom != 0) { // 更新显示区域 m_ShowRegion = new_ShowRegion; // 图像显示拉伸比例控制 m_ImgRatioOnScreen = 1.0F; // 显示图像 ShowOneImage(m_SrcFrame, TRUE, m_ShowRegion, m_ImgRatioOnScreen, m_ImgShowShift); // 更新标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate),FALSE); } } else { // 策略2:图像已经全部显示 // 更新偏移量 m_ImgShowShift.x += (point.x - m_LeftButtonDown.x); m_ImgShowShift.y += (point.y - m_LeftButtonDown.y); // 更新鼠标左键按下点 m_LeftButtonDown = point; // 显示图像 ShowWholeImage(m_SrcFrame, m_ImgRatioOnScreen, m_ImgShowShift); // 更新标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate), FALSE); } } } // 已经有一个点了 if ((m_bGetTgtImgOn == true || m_bClipImgOn == true)&& m_haveValidFirstPt == TRUE) { // 计算 CPoint point 对应的像素坐标 CPoint LButtonDblClkPixelCoordinate; if ((point.x > m_ShowRegionOnScreen.left) && (point.x < m_ShowRegionOnScreen.right) && (point.y > m_ShowRegionOnScreen.top) && (point.y < m_ShowRegionOnScreen.bottom)) // 鼠标在图像上 { m_clipImgSecondPtScreen = point; // 重新计算第一个点的屏幕坐标 m_clipImgFirstPtScreen = GetScreenCoordinateBasedOnPixelCoordinate(m_clipImgFirstPt); CDC* pDC = this->GetDC(); CPen newPen1; // 创建新画笔 newPen1.CreatePen(PS_SOLID, 2, RGB(0, 255, 255)); // 显示区域的地理边界 CRect rect; GetClientRect(&rect); InvalidateRect(&rect, FALSE); UpdateWindow(); CPen *pOldPen = pDC->SelectObject(&newPen1); CPoint pts[4]; pts[0] = m_clipImgFirstPtScreen; pts[1].x = m_clipImgSecondPtScreen.x; pts[1].y = m_clipImgFirstPtScreen.y; pts[2] = m_clipImgSecondPtScreen; pts[3].x = m_clipImgFirstPtScreen.x; pts[3].y = m_clipImgSecondPtScreen.y; pDC->MoveTo(pts[0]); pDC->LineTo(pts[1]); pDC->LineTo(pts[2]); pDC->LineTo(pts[3]); pDC->LineTo(pts[0]); // 释放设备上下文指针 ReleaseDC(pDC); pDC = NULL; } } //新增功能:计算当前图像 像素坐标 经纬度坐标 RGB值 回调输出 if (m_bFirstSignal == FALSE && m_bSecondSignal == FALSE && m_SrcFrame != NULL && m_bPlotRect == FALSE) { // 计算 CPoint point 对应的像素坐标 CPoint LButtonDblClkPixelCoordinate; if ((point.x > m_ShowRegionOnScreen.left) && (point.x < m_ShowRegionOnScreen.right) && (point.y > m_ShowRegionOnScreen.top) && (point.y < m_ShowRegionOnScreen.bottom)) // 鼠标在图像上 { int ShowRegionWidth = m_ShowRegionOnScreen.Width() + 1; int ShowRegionHeight = m_ShowRegionOnScreen.Height() + 1; double ratioW = double(m_ShowRegion.Width() + 1) / ShowRegionWidth; double ratioH = double(m_ShowRegion.Height() + 1) / ShowRegionHeight; m_imgPixel_XY_Coordinate.x = static_cast((point.x - m_ShowRegionOnScreen.left) * ratioW + 0.5 + m_ShowRegion.left); m_imgPixel_XY_Coordinate.y = static_cast((point.y - m_ShowRegionOnScreen.top) * ratioH + 0.5 + m_ShowRegion.top); // 经纬度坐标 double Lon = 0.0; double Lat = 0.0; double H = 0; if (true == DoCalAnyPtCoordinate(Lon, Lat, H, &m_LatestQBData.framePart, m_imgPixel_XY_Coordinate.x, m_imgPixel_XY_Coordinate.y)) { m_imgPixel_LBH_Coordinate.x = Lon + m_deltaLon; m_imgPixel_LBH_Coordinate.y = Lat + m_deltaLat; CString DEMpath = GetSoftwareCurrentDirectory() + "\\ElevationData"; float fDem = 0; GetElevation(fDem, m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, DEMpath.GetBuffer(0)); m_imgPixel_LBH_Coordinate.z = fDem; } else { if (m_boundbingBox.EastLon - m_boundbingBox.WestLon > 0 && m_boundbingBox.WestLon >= -180 && m_boundbingBox.WestLon <= 180 && m_boundbingBox.EastLon >= -180 && m_boundbingBox.EastLon <= 180 && m_boundbingBox.NorthLat - m_boundbingBox.SouthLat > 0 && m_boundbingBox.SouthLat >= -90 && m_boundbingBox.SouthLat <= 90 && m_boundbingBox.NorthLat >= -90 && m_boundbingBox.NorthLat <= 90) { double LonResolution = (m_boundbingBox.EastLon - m_boundbingBox.WestLon) / m_SrcFrame->width; double LatResolution = (m_boundbingBox.NorthLat - m_boundbingBox.SouthLat) / m_SrcFrame->height; m_imgPixel_LBH_Coordinate.x = (m_boundbingBox.WestLon + m_imgPixel_XY_Coordinate.x * LonResolution); m_imgPixel_LBH_Coordinate.y = (m_boundbingBox.NorthLat - m_imgPixel_XY_Coordinate.y * LatResolution); // 修正 m_imgPixel_LBH_Coordinate.x += (m_deltaLon); m_imgPixel_LBH_Coordinate.y += (m_deltaLat); CString DEMpath = GetSoftwareCurrentDirectory() + "\\ElevationData"; float fDem = 0; GetElevation(fDem, m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, DEMpath.GetBuffer(0)); m_imgPixel_LBH_Coordinate.z = fDem; } else { m_imgPixel_LBH_Coordinate.x = -200.0; m_imgPixel_LBH_Coordinate.y = -200.0; m_imgPixel_LBH_Coordinate.z = -200.0; } } } else { // 设置为 小于0 的无效值 m_imgPixel_XY_Coordinate.x = -1; m_imgPixel_XY_Coordinate.y = -1; m_imgPixel_LBH_Coordinate.x = -200.f; m_imgPixel_LBH_Coordinate.y = -200.f; m_imgPixel_LBH_Coordinate.z = -200.f; } // 回调输出信息即可 if (m_lpSendPixInfoProc != NULL) { CPoint pt; pt.x = m_imgPixel_XY_Coordinate.x; pt.y = m_imgPixel_XY_Coordinate.y; m_lpSendPixInfoProc(pt, m_imgPixel_LBH_Coordinate.x, m_imgPixel_LBH_Coordinate.y, m_imgPixel_LBH_Coordinate.z); } } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 滚轮消息响应 BOOL CImgShowDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { try { // 放大 if (zDelta > 0) { if (m_SrcFrame != NULL) { // 放大并显示图像 DoZoomInImg(); // 更新标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate), FALSE); } }else // 缩小 { if (m_SrcFrame != NULL) { // 放大并显示图像 DoZoomOutImg(); // 更新标绘窗口 DrawSquareOnScreen(GetScreenCoordinateBasedOnPixelCoordinate(m_LButtonDblClkPixelCoordinate), FALSE); } } return TRUE; } catch(cv::Exception &e) { e.msg; return FALSE; } catch(...) { return FALSE; } } BOOL CImgShowDlg::OnInitDialog() { try { CDialog::OnInitDialog(); // 数据存储目录 m_sRootFolder = GetSoftwareCurrentDirectory() + "\\QB_RESULT"; m_sImgSaveFolder = m_sRootFolder + "\\EDITED_IMAGE"; // 创建文件夹 CreateDirectory(m_sRootFolder, NULL); CreateDirectory(m_sImgSaveFolder, NULL); m_hMutex_ProcessData = CreateMutexA(NULL, FALSE, NULL); m_pFastLookUpDlg = new CFastLookUpDlg(); if (m_pFastLookUpDlg != NULL) { m_pFastLookUpDlg->Create(IDD_DLG_FAST_LOOKUP_IMGS, this); m_pFastLookUpDlg->SetParentPt(this); } return TRUE; } catch(cv::Exception &e) { e.msg; return FALSE; } catch(...) { return FALSE; } } // 设置一路信号是否正在输入 void CImgShowDlg::SetFirstSignal(BOOL bflag) { m_bFirstSignal = bflag; } BOOL CImgShowDlg::GetFirstSignal() { return m_bFirstSignal; } // 设置2路信号是否正在输入 void CImgShowDlg::SetSecondSignal(BOOL bflag) { m_bSecondSignal = bflag; } BOOL CImgShowDlg::GetSecondSignal() { return m_bSecondSignal; } // 释放m_LatestQBData void CImgShowDlg::ReleaseLatestQBData() { try { ReleaseQBData(&m_LatestQBData); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 设置m_LatestQBData void CImgShowDlg::SetLatestQBData(const QBStru &qbData) { try { ReleaseQBData(&m_LatestQBData); CloneQBData(qbData, m_LatestQBData); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 设置经纬度盒子 void CImgShowDlg::SetBoundingBox(GeoBoundingBox box) { m_boundbingBox = box; } // 设置iLatest void CImgShowDlg::SetiLatest(int i) { m_iLatest = i; } int CImgShowDlg::GetiLatest() { return m_iLatest; } // 设置iPreLatest void CImgShowDlg::SetiPreLatest(int i) { m_iPreLatest = i; } int CImgShowDlg::GetiPreLatest() { return m_iPreLatest; } //功能:解压后的情报数据处理函数(包括三项:更新本地情报、显示、入队列和对外传递数据) void CImgShowDlg::DisposeQBData(const QBStru* qbData) { try { // 空值判断 if (qbData == nullptr) { return; } // 输入数据有效性判断 如果复接数据和图像数据均无效,直接返回 if ((qbData->framePart.bValid == false) && (qbData->image.bValid == false)) { return; } // 功能1:更新数据 m_LatestQBData CloneQBData(*qbData, m_LatestQBData); // 设置为 小于0 的无效值 m_LButtonDblClkPixelCoordinate.x = -1; m_LButtonDblClkPixelCoordinate.y = -1; // 功能2:显示(显示图像)和 指北针 dstImg 或 srcImg,不显示geoImg(暂时觉得没必要) ShowLatestQBData(); // 功能3:入队列: 按需入队 if (m_bMemPreMultiFrame == TRUE) { PushLatestQBData2Deque(); // 功能4:送入 快速查询模块 if (m_pFastLookUpDlg != NULL) { m_pFastLookUpDlg->SetImgData(m_LatestQBData.image.srcImg); if (m_pFastLookUpDlg->IsWindowVisible() == TRUE) { m_pFastLookUpDlg->ShowImgData(); } } } // 更新数目,注意不是+1 WaitForSingleObject(m_hMutex_ProcessData, INFINITE); m_currentImgOrder = static_cast(m_QBDataDeque.size()); ReleaseMutex(m_hMutex_ProcessData); } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 功能:m_LatestQBData 入队列 // 输入: // 输出: // 说明:只有当m_LatestQBData图像数据有效时,方可入队 // 功能:LatestQBData 入队列, void CImgShowDlg::PushLatestQBData2Deque() { WaitForSingleObject(m_hMutex_ProcessData, INFINITE); try { if (m_LatestQBData.image.bValid == true) // 图像数据有效 { if ( m_QBDataDeque.size() < 18U) { QBStru local; // 局部变量 CloneQBData(m_LatestQBData,local); // 深度复制 m_QBDataDeque.push_back(local); // 入队,浅复制 // 设置局部变量buffer指向空,否则,local超出作用域会析构其指向的内存单元, // 从而使local中已入队的结构体成为野指针; local.image.srcImg.buff = NULL; local.image.dstImg.buff = NULL; local.image.geoImg.buff = NULL; } else { while(m_QBDataDeque.size() >= 18U) // 设计原因:中途可能设置小于当前数目的容量 { // 弹出 std::deque::iterator iter; // 定义迭代器 iter = m_QBDataDeque.begin(); // 释放指针指向的内存 SAFE_DELETE_ARRAY(iter->image.srcImg.buff); SAFE_DELETE_ARRAY(iter->image.dstImg.buff); SAFE_DELETE_ARRAY(iter->image.geoImg.buff); // 弹出 m_QBDataDeque.pop_front(); } // 当前帧入队 QBStru local; // 局部变量 CloneQBData(m_LatestQBData, local); // 深度复制 m_QBDataDeque.push_back(local); // 入队,浅复制 // 设置局部变量buffer指向空,否则,local超出作用域会析构其指向的内存单元, // 从而使local中已入队的结构体成为野指针; local.image.srcImg.buff = NULL; local.image.dstImg.buff = NULL; local.image.geoImg.buff = NULL; } } } catch(cv::Exception &e) { e.msg; } catch(...) { } ReleaseMutex(m_hMutex_ProcessData); } // 1.29 功能:清理内存及记忆 // 输入:无 // // 输出:无 void CImgShowDlg::ClearMemory() { if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { return; } try { // 如果有图像 需要释放该图像 if (m_SrcFrame != NULL) { cvReleaseImage(&m_SrcFrame); m_SrcFrame = NULL; } // 当前情报数据结构体:LatestQBData ReleaseQBData(&m_LatestQBData); WaitForSingleObject(m_hMutex_ProcessData, INFINITE); // 情报队列销毁 if(m_QBDataDeque.size() > 0) { for (size_t i = 0; i < m_QBDataDeque.size(); ++i) { SAFE_DELETE_ARRAY(m_QBDataDeque[i].image.srcImg.buff); SAFE_DELETE_ARRAY(m_QBDataDeque[i].image.dstImg.buff); SAFE_DELETE_ARRAY(m_QBDataDeque[i].image.geoImg.buff); } m_QBDataDeque.clear(); } ReleaseMutex(m_hMutex_ProcessData); // midImg 释放 SAFE_DELETE_ARRAY(m_midImg.buff); // 复位 m_ShowRegion = CRect(0,0,0,0); m_ShowRegionOnScreen.left = 0; m_ShowRegionOnScreen.right = 0; m_ShowRegionOnScreen.top = 0; m_ShowRegionOnScreen.bottom = 0; m_LButtonDownPixelCoordinate = CPoint(0,0); m_bStaisfyRoamImg = FALSE; m_LatestPlotRect = CRect(0,0,0,0); m_LButtonDblClkPixelCoordinate = CPoint(-1, -1); m_LeftButtonDown.x = 0; m_LeftButtonDown.y = 0; m_RButtonPt.x = 0; m_RButtonPt.y = 0; m_SrcFrame = NULL; m_ImgRatioOnScreen = 1.0F; m_ImgShowShift.x = 0L; m_ImgShowShift.y = 0L; m_bFirstSignal = FALSE; m_bSecondSignal = FALSE; m_bSatisfyMove = FALSE; m_iLatest = 0; m_iPreLatest = 0; m_LatestQuadrangle = CRect(0,0,0,0); // 像素信息 m_imgPixel_XY_Coordinate.x = -1; m_imgPixel_XY_Coordinate.y = -1; m_imgPixel_LBH_Coordinate.x = -200.0; m_imgPixel_LBH_Coordinate.y = -200.0; m_imgPixel_LBH_Coordinate.z = -200.0; m_currentImgOrder = 0; m_TargetCenter = cv::Point(-100, -100); m_bDrawSquareOnImg = TRUE; m_deltaLon = 0; m_deltaLat = 0; // 使窗口无效 Invalidate(); // 释放快速浏览对话框内存图像 if (m_pFastLookUpDlg != NULL) { m_pFastLookUpDlg->ClearMemory(); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 3.12 功能:保存图像为tiff,并回调保存路径 // 说明:当保存为tiff图像时,忽略校准量,牵扯面太广,且不可靠 // 如果实在想高精度保存一幅图像为tiff,可通过GCP几何校正实现 void CImgShowDlg::SaveToGeoTiff() { try { // 计算保存路径 CString savePath; CString sRootFolder; CString sImgSaveFolder; // 数据存储目录 sRootFolder = GetSoftwareCurrentDirectory() + "\\QB_RESULT"; sImgSaveFolder = sRootFolder + "\\EDITED_IMAGE"; // 创建文件夹 CreateDirectory(sRootFolder, NULL); CreateDirectory(sImgSaveFolder, NULL); // 计算存储路径 SYSTEMTIME CurrentTime; GetLocalTime(&CurrentTime); savePath.Format( "%04d%02d%02d_%02d%02d%02d%04d", CurrentTime.wYear, CurrentTime.wMonth, CurrentTime.wDay, CurrentTime.wHour, CurrentTime.wMinute, CurrentTime.wSecond, CurrentTime.wMilliseconds); savePath = "Geo_" + savePath; savePath = savePath + _T(".tif"); savePath = sImgSaveFolder + "\\" + savePath; bool bret = false; // 保存为tiff if (true == SaveToGeoTIFF(&m_LatestQBData, savePath.GetBuffer(0))) { bret = true; } else if (true == SaveToGeoTIFF(&m_LatestQBData.image.dstImg, savePath.GetBuffer(0))) { bret = true; } else if (true == SaveToGeoTIFF(&m_LatestQBData.image.srcImg, savePath.GetBuffer(0))) { bret = true; } else { bret = false; } if (bret == true) { // 保存路径回调 if (m_lpSendFilePath != NULL) { m_lpSendFilePath(savePath, 6); } } // 清理 geoImg SAFE_DELETE_ARRAY(m_LatestQBData.image.geoImg.buff); m_LatestQBData.image.geoImg.buff = NULL; } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 右键 清理内存记忆 void CImgShowDlg::OnClearMemory() { try { ClearMemory(); // 复位目标标绘 m_bPlotRect = FALSE; } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 单帧校正采集 void CImgShowDlg::OnSaveImgToTiff() { SaveToGeoTiff(); } // 功能:图像去雾 void CImgShowDlg::AdjustImgDehaze(BOOL bAdjust, int A_MAX, double degree) { try { if (bAdjust == TRUE) { if(m_bEnhanceEdit == true) // 增强 { if (GetiLatest() == 0) // 如果刚什么也没做 { if (m_LatestQBData.image.dstImg.buff == NULL && m_midImg.buff == NULL) { CloneImgStru(m_LatestQBData.image.srcImg, m_midImg); DoDehazeCtrl(&m_midImg, &m_LatestQBData.image.dstImg, A_MAX, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(1); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); DoDehazeCtrl(&m_midImg, &m_LatestQBData.image.dstImg, A_MAX, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(1); } } else if (GetiLatest() == 1) // 如果刚才就是去雾 { DoDehazeCtrl(&m_midImg, &m_LatestQBData.image.dstImg, A_MAX,degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); } else // 其它 { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); DoDehazeCtrl(&m_midImg, &m_LatestQBData.image.dstImg, A_MAX,degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(1); } } } } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 功能:图像亮度调节 void CImgShowDlg::AdjustImgIntensity(BOOL bAdjust, int degree) { try { // 执行亮度调节 if(bAdjust == TRUE) { if (degree == 10) { return; } if (m_bEnhanceEdit == true) // 增强 { if (GetiLatest() == 0) { if (m_LatestQBData.image.dstImg.buff == NULL && m_midImg.buff == NULL) { CloneImgStru(m_LatestQBData.image.srcImg, m_midImg); DoIntensityCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(2); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); DoIntensityCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(2); } } else if(GetiLatest() == 2) { DoIntensityCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); DoIntensityCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(2); } } } } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 功能:图像对比度调节 void CImgShowDlg::AdjustImgContrast(BOOL bAdjust, int degree) { try { if(bAdjust == TRUE) { if (degree == 10) { return; } if (m_bEnhanceEdit == true) // 增强 { if (GetiLatest() == 0) { if (m_LatestQBData.image.dstImg.buff == NULL && m_midImg.buff == NULL) { CloneImgStru(m_LatestQBData.image.srcImg, m_midImg); DoContrastCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(3); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); DoContrastCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(3); } } else if(GetiLatest() == 3) { DoContrastCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); DoContrastCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(3); } } } } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 功能:图像清晰度调节 void CImgShowDlg::AdjustImgDefinition(BOOL bAdjust, int degree) { try { if(bAdjust == TRUE) { if (degree == 10) { return; } if (m_bEnhanceEdit == true) // 增强 { if (GetiLatest() == 0) { if (m_LatestQBData.image.dstImg.buff == NULL && m_midImg.buff == NULL) { CloneImgStru(m_LatestQBData.image.srcImg,m_midImg); DoDefinitionCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(4); } else { CloneImgStru(m_LatestQBData.image.dstImg,m_midImg); DoDefinitionCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(4); } } else if(GetiLatest() == 4) { DoDefinitionCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); } else { CloneImgStru(m_LatestQBData.image.dstImg, m_midImg); DoDefinitionCtrl(&m_midImg, &m_LatestQBData.image.dstImg, degree); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); SetiPreLatest(GetiLatest()); SetiLatest(4); } } } } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 功能:返回图像调节上一步图像状态 void CImgShowDlg::ReturnToPreImgState() { try { if (m_bEnhanceEdit == true) { CloneImgStru(m_midImg, m_LatestQBData.image.dstImg); ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); // 返回一步 SetiLatest(GetiPreLatest()); } else { CloneImgStru(m_midImg, m_LatestQBData.image.dstImg); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3) { memcpy(srcFrameMat.data, m_LatestQBData.image.dstImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 功能:返回原始图像状态 void CImgShowDlg::ReturnToSrcImgState() { try { if (m_bEnhanceEdit == true) { SAFE_DELETE_ARRAY(m_midImg.buff); m_midImg.buff = NULL; SAFE_DELETE_ARRAY(m_LatestQBData.image.dstImg.buff); m_LatestQBData.image.dstImg.buff = NULL; ShowLatestQBData(); // 显示图像 SetTargetPixelCoordinate(GetTargetCoordinate()); // 一步还原 SetiLatest(0); SetiPreLatest(0); } else { CloneImgStru(m_LatestQBData.image.srcImg, m_midImg); CloneImgStru(m_LatestQBData.image.srcImg, m_LatestQBData.image.dstImg); // 标记 m_SrcFrame cv::Mat srcFrameMat(m_SrcFrame, false); if (srcFrameMat.type() == CV_8UC1) { memcpy(srcFrameMat.data, m_LatestQBData.image.srcImg.buff, srcFrameMat.cols * srcFrameMat.rows); // 图像数据复制 } else if (srcFrameMat.type() == CV_8UC3) { memcpy(srcFrameMat.data, m_LatestQBData.image.srcImg.buff, srcFrameMat.cols * srcFrameMat.rows * 3); // 图像数据复制 } Invalidate(); } } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 18 功能:设置图像编辑类型 void CImgShowDlg::SetImgEditType(int type) { m_iImgEditType = type; if (type == 1 || type == 2 || type == 3) { m_bEnhanceEdit = false; } else { m_bEnhanceEdit = true; } } // 获取图像编辑模式 true 增强 false 标记 bool CImgShowDlg::GetImgEditMode() { return m_bEnhanceEdit; } // 20 功能:显示记忆图像队列中的指定某一张图像 void CImgShowDlg::ShowSelectedImgInMem(int order) { WaitForSingleObject(m_hMutex_ProcessData, INFINITE); try { if (m_QBDataDeque.empty() == false) { if (order >= 1 && order <= static_cast(m_QBDataDeque.size())/* && m_currentImgOrder != order*/) { // 释放 ReleaseQBData(&m_LatestQBData); SAFE_DELETE(m_midImg.buff); m_midImg.buff = NULL; CloneQBData(m_QBDataDeque[order - 1], m_LatestQBData); ShowLatestQBData(); m_currentImgOrder = order; } } } catch(cv::Exception &e) { e.what(); } catch (...) { int a = 8; } ReleaseMutex(m_hMutex_ProcessData); } // 快速查找图像 void CImgShowDlg::OnFastLookupImgs() { try { if (m_pFastLookUpDlg != NULL) { // 为空时 if (m_pFastLookUpDlg->isEmpty() == true) { ::MessageBoxA(NULL, _T("无记忆图像供查找!"),_T("操作提示"), MB_OK); m_pFastLookUpDlg->ShowWindow(SW_HIDE); return; } else { if (TRUE == m_pFastLookUpDlg->IsWindowVisible()) { m_pFastLookUpDlg->ShowWindow(SW_HIDE); } else { m_pFastLookUpDlg->ShowWindow(SW_SHOW); m_pFastLookUpDlg->ShowImgData(); } } } } catch(cv::Exception &e) { e.what(); return; } catch (...) { return; } } // 定位引导 void CImgShowDlg::OnTgtLocLead() { try { // 右键坐标 CPoint point; point.x = m_RButtonPt.x; point.y = m_RButtonPt.y; if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { return; } if (m_SrcFrame != NULL) { // 计算 CPoint point 对应的像素坐标 CPoint LButtonDblClkPixelCoordinate; if ((point.x > m_ShowRegionOnScreen.left) && (point.x < m_ShowRegionOnScreen.right) && (point.y > m_ShowRegionOnScreen.top) && (point.y < m_ShowRegionOnScreen.bottom)) // 鼠标在图像上 { // 图像尺寸与显示区域尺寸之间的比例 double ratio = 1.0; // 分母0值判断 if (m_ShowRegionOnScreen.Width() > 0) { ratio = (m_ShowRegion.Width() * 1.0) / m_ShowRegionOnScreen.Width(); } CPoint PixelCoordinate; // 像素坐标 PixelCoordinate.x = static_cast((point.x - m_ShowRegionOnScreen.left) * ratio) + m_ShowRegion.left; PixelCoordinate.y = static_cast((point.y - m_ShowRegionOnScreen.top) * ratio) + m_ShowRegion.top; // 经纬度坐标 double Lon = -200; double Lat = -200; double H = 0; // 图像四个顶点的经纬度坐标 double Lon1 = -200, Lat1 = -200, H1 = -200; double Lon2 = -200, Lat2 = -200, H2 = -200; double Lon3 = -200, Lat3 = -200, H3 = -200; double Lon4 = -200, Lat4 = -200, H4 = -200; if (false == DoCalAnyPtCoordinate(Lon, Lat, H, &m_LatestQBData.framePart, PixelCoordinate.x, PixelCoordinate.y)) { if (m_boundbingBox.EastLon - m_boundbingBox.WestLon > 0 && m_boundbingBox.WestLon >= -180 && m_boundbingBox.WestLon <= 180 && m_boundbingBox.EastLon >= -180 && m_boundbingBox.EastLon <= 180 && m_boundbingBox.NorthLat - m_boundbingBox.SouthLat > 0 && m_boundbingBox.SouthLat >= -90 && m_boundbingBox.SouthLat <= 90 && m_boundbingBox.NorthLat >= -90 && m_boundbingBox.NorthLat <= 90) { double LonResolution = (m_boundbingBox.EastLon - m_boundbingBox.WestLon) / m_SrcFrame->width; double LatResolution = (m_boundbingBox.NorthLat - m_boundbingBox.SouthLat) / m_SrcFrame->height; Lon = float(m_boundbingBox.WestLon + PixelCoordinate.x * LonResolution); Lat = float(m_boundbingBox.NorthLat - PixelCoordinate.y * LatResolution); // 四个角点经纬度 Lon1 = m_boundbingBox.WestLon, Lat1 = m_boundbingBox.NorthLat; Lon2 = m_boundbingBox.EastLon, Lat2 = m_boundbingBox.NorthLat; Lon3 = m_boundbingBox.EastLon, Lat3 = m_boundbingBox.SouthLat; Lon4 = m_boundbingBox.WestLon, Lat4 = m_boundbingBox.SouthLat; } else { Lon = -200.f; Lat = -200.f; } } else { // 计算四个角点的经纬度坐标 bool ret1 = DoCalAnyPtCoordinate(Lon1, Lat1, H1, &m_LatestQBData.framePart, 0, 0); bool ret2 = DoCalAnyPtCoordinate(Lon2, Lat2, H2, &m_LatestQBData.framePart, m_SrcFrame->width - 1, 0); bool ret3 = DoCalAnyPtCoordinate(Lon3, Lat3, H3, &m_LatestQBData.framePart, m_SrcFrame->width - 1, m_SrcFrame->height - 1); bool ret4 = DoCalAnyPtCoordinate(Lon4, Lat4, H4, &m_LatestQBData.framePart, 0, m_SrcFrame->height - 1); } // 修正 if (abs(Lon) < 180 && abs(Lat) < 90) { Lon += m_deltaLon; Lat += m_deltaLat; Lon1 += m_deltaLon, Lat1 += m_deltaLat; Lon2 += m_deltaLon, Lat2 += m_deltaLat; Lon3 += m_deltaLon, Lat3 += m_deltaLat; Lon4 += m_deltaLon, Lat4 += m_deltaLat; } // 回调输出 if (m_lpSendTgrLocLeadLonLat != NULL) { m_lpSendTgrLocLeadLonLat(Lon, Lat, Lon1, Lat1, Lon2, Lat2, Lon3, Lat3, Lon4, Lat4); } } } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } void CImgShowDlg::LeadImgLoc() { CRect rect; GetClientRect(&rect); // 右键坐标 m_RButtonPt.x = rect.Width() / 2; m_RButtonPt.y = rect.Height() / 2; OnTgtLocLead(); } // 几何校正 并显示图像 void CImgShowDlg::OnGeoCorrectAndShow() { try { // 当未设置定位导引输出函数指针时,即不用于地图匹配定位时,该功能设为无效 if (m_lpSendTgrLocLeadLonLat == NULL) { return; } // 几何校正: 选择该模式的原因是牵扯到图像增强等操作 if (TRUE == DoSysGeoCorrect(&m_LatestQBData)) { SAFE_DELETE_ARRAY(m_LatestQBData.image.srcImg.buff); SAFE_DELETE_ARRAY(m_LatestQBData.image.dstImg.buff); CloneImgStru(m_LatestQBData.image.geoImg, m_LatestQBData.image.srcImg); SAFE_DELETE_ARRAY(m_LatestQBData.image.geoImg.buff); // 复接数据设置为0 无效 m_LatestQBData.framePart.bValid = false; memset(&m_LatestQBData.framePart, 0, sizeof(m_LatestQBData.framePart)); // 设置经纬度盒子 SetBoundingBox(m_LatestQBData.image.srcImg.BoundingBox); // 显示图像 ShowLatestQBData(); } } catch(cv::Exception &e) { e.msg; return; } catch (...) { return; } } // 设置文件夹 void CImgShowDlg::SetSaveCurrentImgFolder(CString str) { m_sSaveCurrentImgFolder = str; } void CImgShowDlg::SetSavePreMultiImgFolder(CString str) { m_sSavePreMultiImgFolder = str; } // 21 功能:几何校正并显示图像 void CImgShowDlg::GeoCorrectAndShowImg() { OnGeoCorrectAndShow(); } // 在图像中标绘目标 矩形 定位用 void CImgShowDlg::OnDrawSqureOnImg() { // 只有设置了目标导引情况下操作 if (m_lpSendTgrLocLeadLonLat != NULL) { m_bDrawSquareOnImg = !m_bDrawSquareOnImg; } else { m_bDrawSquareOnImg = FALSE; } } // 图像加载线程(GDAL) UINT LoadImgThroughGDAL(void *pt) { CImgShowDlg *ptr = (CImgShowDlg*)pt; if (ptr == nullptr) { return 0; } CString ImgFilePath = ptr->m_GDALLoadImgPath; try { // 注册 GDALAllRegister(); CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); // 打开图像 GDALDataset* srcDataSet = nullptr; srcDataSet = (GDALDataset*)GDALOpen(ImgFilePath, GA_ReadOnly); if (srcDataSet != nullptr) { // 获取图像参数 int Width = srcDataSet->GetRasterXSize(); int Height = srcDataSet->GetRasterYSize(); int nBound = srcDataSet->GetRasterCount(); if (nBound == 1 || nBound == 3) { double r = 0; if (Width > Height) { r = 10000.0 / Width; } else { r = 10000.0 / Height; } if (r > 1) { r = 1.0; } int scaledWidth = int(Width * r);; int scaledHeight = int(Height * r); if (scaledWidth > 0 && scaledHeight > 0) { GDALRasterBand *pBand = srcDataSet->GetRasterBand(1); GDALDataType type = pBand->GetRasterDataType(); cv::Mat img; if (nBound == 1) { img = cv::Mat(scaledHeight, scaledWidth, CV_8UC1, cv::Scalar(0)); pBand->RasterIO(GF_Read, 0,0, Width, Height, img.data, img.cols, img.rows, type, 0, 0); } else { img = cv::Mat(scaledHeight, scaledWidth, CV_8UC3, cv::Scalar(0)); int bandMap[3] = {3, 2, 1}; CPLErr error = srcDataSet->RasterIO(GF_Read, 0,0, Width, Height, img.data, img.cols, img.rows, type, 3, bandMap, 3, // nPixelSpace 3 * scaledWidth, // nLineSpace 1); // nBandSpace } BITMAPINFO info; info.bmiHeader.biWidth = img.cols; info.bmiHeader.biHeight = img.rows; info.bmiHeader.biBitCount = static_cast(img.channels() * 8); double GISDATA[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; srcDataSet->GetGeoTransform(GISDATA); double WLon = GISDATA[0]; double ELon = GISDATA[0] + Width * GISDATA[1]; double NLat = GISDATA[3]; double SLat = GISDATA[3] + Height * GISDATA[5]; GeoBoundingBox LBbox; LBbox.WestLon = WLon; LBbox.EastLon = ELon; LBbox.SouthLat = SLat; LBbox.NorthLat = NLat; ptr->LoadOneImgFromMenu(&info, img.data, LBbox); } } } GDALClose(srcDataSet); srcDataSet = NULL; } catch(...) { return 0; } return 0; } // 右键打开一副图像 void CImgShowDlg::OnOpenOneImg() { CFileDialog ImgDialog( TRUE, NULL, NULL, OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY, _T("Image files (*.bmp;*.jpg;*.tif;) |*.bmp;*.jpg;*.tif;| All Files (*.*) |*.*||"), NULL); ImgDialog.m_ofn.lpstrTitle = _T("打开一幅图像"); if (ImgDialog.DoModal() != IDOK) { return; } CString ImgFilePath = ImgDialog.GetPathName(); m_GDALLoadImgPath = ImgFilePath; int len = ImgFilePath.GetLength(); int leftLen = ImgFilePath.ReverseFind('.'); CString Type = ImgFilePath.Right(len - leftLen); std::string path = ImgFilePath.GetString(); try { cv::Mat img = cv::imread(path, -1); if (img.empty() == true) { return; } else { BITMAPINFO info; info.bmiHeader.biWidth = img.cols; info.bmiHeader.biHeight = img.rows; info.bmiHeader.biBitCount = static_cast(img.channels() * 8); if (Type == ".tif") { // 读取文件地理信息 GDALAllRegister(); CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); GDALDataset* tempdata = nullptr; tempdata = ( GDALDataset* )GDALOpen((LPSTR)(LPCTSTR)ImgFilePath, GA_ReadOnly); double GISDATA[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; if (tempdata != NULL) { tempdata->GetGeoTransform(GISDATA); // 获取尺寸 int width = tempdata->GetRasterXSize(); int height = tempdata->GetRasterYSize(); double WLon = GISDATA[0]; double ELon = GISDATA[0] + width * GISDATA[1]; double NLat = GISDATA[3]; double SLat = GISDATA[3] + height * GISDATA[5]; GeoBoundingBox LBbox; LBbox.WestLon = WLon; LBbox.EastLon = ELon; LBbox.SouthLat = SLat; LBbox.NorthLat = NLat; LoadOneImgFromMenu(&info, img.data, LBbox); } else { LoadOneImgFromMenu(&info, img.data); } GDALClose( tempdata ); tempdata = NULL; } else { LoadOneImgFromMenu(&info, img.data); } } } catch(cv::Exception &e) { e.what(); ::MessageBoxA(NULL, _T("图像过大,缩放显示!"),_T("操作提示"), MB_OK); // 启动GDAL数据加载线程 AfxBeginThread(LoadImgThroughGDAL, this); } catch(...) { } } void CImgShowDlg::LoadOneImgFromMenu(const BITMAPINFO* pImgInfo, BYTE* pImgData, GeoBoundingBox LBbox, BOOL isNeedFlip, BOOL isNeedClip, const CRect* pShowRegion, float Strecth_Ratio, POINT xyShift) { try { // 数据有效性验证 if ( (pImgInfo == NULL) || (pImgData == NULL)) { return; } // 设置一路输入正在输入标识 SetFirstSignal(TRUE); // biBitCount 验证 if(pImgInfo->bmiHeader.biBitCount != 24 && pImgInfo->bmiHeader.biBitCount != 8) { SetFirstSignal(FALSE); return; } // 更新数据至全局变量:LatestQBData if (pImgInfo->bmiHeader.biWidth > 0 && pImgInfo->bmiHeader.biHeight > 0 && pImgData != NULL) { // 设置一路输入正在输入标识 SetFirstSignal(TRUE); // 构建临时对象 QBStru local; local.image.srcImg.ImgWidth = pImgInfo->bmiHeader.biWidth; local.image.srcImg.ImgHeight = pImgInfo->bmiHeader.biHeight; local.image.srcImg.bitcount = pImgInfo->bmiHeader.biBitCount; // 步长:每行像素所占字节数 int lineByte = (pImgInfo->bmiHeader.biWidth * pImgInfo->bmiHeader.biBitCount / 8); // 位图数据缓冲区的大小,即图像大小 int imgBufSize = pImgInfo->bmiHeader.biHeight * lineByte; if ( imgBufSize > 0) { local.image.srcImg.buff = new BYTE[imgBufSize]; if (local.image.srcImg.buff != NULL) { // 复制实际字节数 memcpy(local.image.srcImg.buff, pImgData, static_cast(imgBufSize)); // 图像数据复制 // 设置图像数据有效 local.image.bValid = true; // 是否需要反转 if (isNeedFlip == TRUE) { FlipImgStru(&local.image.srcImg); } } } local.image.srcImg.BoundingBox = LBbox; /*m_boundbingBox = LBbox;*/ // 将 local 复制到 m_LatestQBData SetLatestQBData(local); SetBoundingBox(LBbox); // 释放 local if (local.image.srcImg.buff != NULL) { SAFE_DELETE_ARRAY(local.image.srcImg.buff); } // 显示图像 // 接口转换 CRect ShowRegion; if (pShowRegion != NULL) { ShowRegion = *pShowRegion; } ShowOneImage(const_cast(pImgInfo), pImgData, isNeedClip, ShowRegion, isNeedFlip, Strecth_Ratio, xyShift); // 图像去雾 亮度调节 对比度调节 清晰度调节 复位 SetiLatest(0); // 最近的一次 SetiPreLatest(0); // 最近的一次的前一次 // 关闭1路正在输入标识 SetFirstSignal(FALSE); } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 单点定位校准 void CImgShowDlg::OnTgtloccalibrate() { try { CTgtLocCalibrateDlg TLCdlg; if (TLCdlg.DoModal() == IDOK) { // 获取校准值 double calibrateLon = TLCdlg.GetCalibrateLon(); double calibrateLat = TLCdlg.GetCalibrateLat(); if (abs(calibrateLon) > 180 || abs(calibrateLat) > 90) { return; } // 取消校准 if (abs(calibrateLon) + abs(calibrateLat) < 1e-5) { m_deltaLon = 0; m_deltaLat = 0; } // 获取校准前的值 // 经纬度坐标 double Lon = -200; double Lat = -200; double H = 0; // 右键坐标 CPoint point; point.x = m_RButtonPt.x; point.y = m_RButtonPt.y; if (m_bFirstSignal == TRUE || m_bSecondSignal == TRUE) { return; } if (m_SrcFrame != NULL) { // 计算 CPoint point 对应的像素坐标 CPoint LButtonDblClkPixelCoordinate; if ((point.x > m_ShowRegionOnScreen.left) && (point.x < m_ShowRegionOnScreen.right) && (point.y > m_ShowRegionOnScreen.top) && (point.y < m_ShowRegionOnScreen.bottom)) // 鼠标在图像上 { // 图像尺寸与显示区域尺寸之间的比例 double ratio = 1.0; // 分母0值判断 if (m_ShowRegionOnScreen.Width() > 0) { ratio = (m_ShowRegion.Width() * 1.0) / m_ShowRegionOnScreen.Width(); } CPoint PixelCoordinate; // 像素坐标 PixelCoordinate.x = static_cast((point.x - m_ShowRegionOnScreen.left) * ratio) + m_ShowRegion.left; PixelCoordinate.y = static_cast((point.y - m_ShowRegionOnScreen.top) * ratio) + m_ShowRegion.top; if (false == DoCalAnyPtCoordinate(Lon, Lat, H, &m_LatestQBData.framePart, PixelCoordinate.x, PixelCoordinate.y)) { if (m_boundbingBox.EastLon - m_boundbingBox.WestLon > 0 && m_boundbingBox.WestLon >= -180 && m_boundbingBox.WestLon <= 180 && m_boundbingBox.EastLon >= -180 && m_boundbingBox.EastLon <= 180 && m_boundbingBox.NorthLat - m_boundbingBox.SouthLat > 0 && m_boundbingBox.SouthLat >= -90 && m_boundbingBox.SouthLat <= 90 && m_boundbingBox.NorthLat >= -90 && m_boundbingBox.NorthLat <= 90) { double LonResolution = (m_boundbingBox.EastLon - m_boundbingBox.WestLon) / m_SrcFrame->width; double LatResolution = (m_boundbingBox.NorthLat - m_boundbingBox.SouthLat) / m_SrcFrame->height; Lon = float(m_boundbingBox.WestLon + PixelCoordinate.x * LonResolution); Lat = float(m_boundbingBox.NorthLat - PixelCoordinate.y * LatResolution); } else { return; } } } else { return; } } else { return; } // 计算修正量 double deltaLon = calibrateLon - Lon; double deltaLat = calibrateLat - Lat; if (abs(deltaLon) > 1 || abs(deltaLat) > 1) { return; } else { m_deltaLon = deltaLon; m_deltaLat = deltaLat; } } } catch(cv::Exception &e) { e.msg; return; } catch(...) { return; } } // 查看 经纬度校准量 void CImgShowDlg::OnViewDeltaLonLat() { // TODO: 在此添加命令处理程序代码 CString sDeltaLon; sDeltaLon.Format("%.6f", m_deltaLon); CString sDeltaLat; sDeltaLat.Format("%.6f", m_deltaLat); CString msg = "delatLon = " + sDeltaLon + "\n" + "deltaLat = " + sDeltaLat; ::MessageBoxA(NULL, _T(msg), _T("操作提示"), MB_OK); } // 22 功能:获取当前显示图像 cv::Mat CImgShowDlg::GetCurrentImg() { cv::Mat img; if (m_SrcFrame != NULL) { img = cv::Mat(m_SrcFrame, true); } return img; } // 24 功能:标注图像(矩形、区域边缘) // 输入: // 1. 区域边缘点 集合 void CImgShowDlg::MarkRegionOnImg(std::vector> &valisContours) { try { if (valisContours.size() > 0) { if (m_SrcFrame != NULL && m_SrcFrame->width > 0 && m_SrcFrame->height > 0) { cv::Mat img(m_SrcFrame, false); for (size_t i = 0; i < valisContours.size(); i++) { cv::Rect rect = cv::boundingRect(valisContours[i]); cv::rectangle(img, rect, cv::Scalar(0,255,255), 2); } cv::drawContours(img, valisContours, -1, cv::Scalar(0,255,255), 1); // m_midImg if (m_LatestQBData.image.dstImg.buff != NULL) { memcpy(m_LatestQBData.image.dstImg.buff, img.data, img.cols * img.rows * img.channels()); } if (m_LatestQBData.image.srcImg.buff != NULL) { memcpy(m_LatestQBData.image.srcImg.buff, img.data, img.cols * img.rows * img.channels()); } ShowLatestQBData(); } } } catch(cv::Exception &e) { e.what(); } catch (...) { } } // 功能:屏蔽右键按钮菜单 void CImgShowDlg::CloseRightBtnDownMenu(bool bClose) { m_bCloseRughtBtnMenu = bClose; } // 功能:设置空屏文字 void CImgShowDlg::SetThemeText(CString str) { m_sThemeText = str; } void CImgShowDlg::OnGetTargetImg() { if (m_bClipImgOn == true) { m_bGetTgtImgOn = false; m_haveValidFirstPt = false; } else { m_bGetTgtImgOn = !m_bGetTgtImgOn; if (m_bGetTgtImgOn == false) { m_haveValidFirstPt = false; } } } // 功能:获取图像边界地理坐标 bool CImgShowDlg::GetImgBoundingBox(double &leftLon, double &topLat, double &rigtLon, double &bottomLat) { double leftLon0 = m_LatestQBData.image.srcImg.BoundingBox.WestLon; double rigtLon0 = m_LatestQBData.image.srcImg.BoundingBox.EastLon; double topLat0 = m_LatestQBData.image.srcImg.BoundingBox.NorthLat; double bottomLat0 = m_LatestQBData.image.srcImg.BoundingBox.SouthLat; if (abs(leftLon0) <= 180 && abs(rigtLon0) <= 180 && leftLon0 < rigtLon0 && abs(topLat0) <= 90 && abs(bottomLat0) <= 90 && bottomLat0 < topLat0) { leftLon = leftLon0; rigtLon = rigtLon0; topLat = topLat0; bottomLat = bottomLat0; return true; } else { return false; } } void CImgShowDlg::OnClipImg() { m_bClipImgOn = !m_bClipImgOn; if (m_bClipImgOn == true) { m_bGetTgtImgOn = false; } m_haveValidFirstPt = false; }