迅雷之家是迅雷做的网站吗,哪里可以注册免费域名,个人网站建设与维护,国际人才网appCRectTracker 类并非 Microsoft Foundation Class (MFC) 库中应用很广泛的一个类#xff0c;一般教科书中很少有提到。在编程中如果需编写选择框绘制以及选择框大小调整、移动等程序时#xff0c;用CRectTracker 类就会做到事半而功倍。下面详细介绍MFC CRectTracker 类。
M… CRectTracker 类并非 Microsoft Foundation Class (MFC) 库中应用很广泛的一个类一般教科书中很少有提到。在编程中如果需编写选择框绘制以及选择框大小调整、移动等程序时用CRectTracker 类就会做到事半而功倍。下面详细介绍MFC CRectTracker 类。
MFC CRectTracker 类详解 CRectTracker 类的构造函数 CRectTracker 类的构造函数的原型如下
CRectTracker();
CRectTracker(
LPCRECT lpSrcRect,
UINT nStyle);
参数 lpSrcRect 矩形对象的指针 nStyle CRectTracker 对象的样式, 有一下几种样式
CRectTracker::solidLine 对矩形边框使用实线。 CRectTracker::dottedLine 对矩形边框使用虚线。 CRectTracker::hatchedBorder 对矩形边框使用带阴影的图案。 CRectTracker::resizeInside 调整位于矩形内的图柄的大小。 CRectTracker::resizeOutside 调整位于矩形外的图柄的大小。 CRectTracker::hatchInside 带阴影的图案覆盖整个矩形。
默认构造函数使用来自 lpSrcRect CRectTracker 的值初始化 对象并将其他大小初始化为
系统默认值。 如果创建对象时没有参数那么 m_rect 和 m_nStyle 数据成员就不会被初
始化。 CRectTracker 类的公共方法公有成员函数 CRectTracker 类的公共方法如下 下面逐一介绍CRectTracker 类的公共方法。 CRectTracker::AdjustRect CRectTracker::AdjustRect是一个虚函数使用调整大小图柄调整跟踪矩形的大小时由框架调用。其原型如下
virtual void AdjustRect(
int nHandle,
LPRECT lpRect);
参数 nHandl 所用图柄的索引 lpRect 指向矩形当前大小的指针。矩形的大小由其高度和宽度决定。
CRectTracker::Draw
调用此函数以绘制矩形的外部线和内部区域。其原型如下
void Draw(CDC* pDC) const;
参数: pDC 指向要进行绘制的设备上下文的指针。 CRectTracker::DrawTrackerRect CRectTracker::DrawTrackerRect是一个虚函数每当跟踪器的位Track 或TrackRubberBand 成员函数内部发生变化时由框架调用。其原型如下
virtual void DrawTrackerRect(
LPCRECT lpRect,
CWnd* pWndClipTo,
CDC* pDC,
CWnd* pWnd); 参数 lpRect 指向包含要绘制的矩形RECT的指针。 pWndClipTo 指向用于剪切矩形的窗口的指针。 pDC 指向要进行绘制的设备上下文的指针。 pWnd 指向要在其中进行绘制的窗口的指针。
注解默认实现调用 CDC::DrawFocusRect 这将绘制一个虚线矩形。重写此函数以在跟踪操作期间提供不同的反馈。 CRectTracker::GetHandleMask CRectTracker::GetHandleMask是一个虚函数框架调用此成员函数来检索矩形调整大小图柄的掩码。其原型如下
virtual UINT GetHandleMask() const;
返回值CRectTracker 项的调整大小图柄的掩码。
一个矩形有 8 个调整大小图柄编号为 0-7。 每个调整大小图柄由掩码中的一个位表
示该位的值为 2^ n其中 n 是调整大小图柄的编号。 重写此成员函数以隐藏或显示指示的调整大小图柄。 CRectTracker::GetTrueRect 调用此函数以检索矩形的坐标。其原型如下
void GetTrueRect(LPRECT lpTrueRect) const;
参数lpTrueRect 指向将包含CRectTracker 对象的设备坐标的RECT结构的指针。
CRectTracker::HitTest
调用此函数以了解用户是否已抓取一个调整大小图柄。其原型如下
int HitTest(CPoint point) const;
参数point 要测试的点以设备坐标表示。
返回值返回的值基于枚举类型 CRectTracker::TrackerHit 可以具有以下值之一 CRectTracker::hitNothing -1 CRectTracker::hitTopLeft 0 CRectTracker::hitBottomRight 2 CRectTracker::hitBottomLeft 3 CRectTracker::hitTop 4 CRectTracker::hitRight 5 CRectTracker::hitBottom 6 CRectTracker::hitLeft 7 CRectTracker::hitMiddle 8 CRectTracker::NormalizeHit 调用此函数以转换可能反转的图柄。其原型如下
int NormalizeHit(int nHandle) const;
参数nHandle 用户选择的图柄。
返回值规范化图柄的索引。 CRectTracker::OnChangedRect
CRectTracker::OnChangedRect是一个虚函数每当在调用Track期间跟踪器矩形发生变化时由框架调用。其原型如下
virtual void OnChangedRect(const CRect rectOld);
参数 rectOld 包含 CRectTracker 对象的旧设备坐标。 CRectTracker::SetCursor 当光标在CRectTracker 对象的区域上时调用此函数来改变光标的形状。从处理 WM_SETCURSOR 消息通常为 OnSetCursor 的窗口的函数内部调用此函数。其原型如下
BOOL SetCursor(CWnd* pWnd,UINT nHitTest) const;
参数
pWnd 指向当前包含光标的窗口。 nHitTest 上一命中测试的结果来自WM_SETCURSOR消息。
返回值如果上一命中是在跟踪器矩形上则为非零值否则为 0。 CRectTracker::Track 调用此函数以显示矩形大小的用户界面。其原型如下
BOOL Track(
CWnd* pWnd,
CPoint point,
BOOL bAllowInvert FALSE,
CWnd* pWndClipTo NULL);
参数
pWnd 包含矩形的窗口对象。
Point 相对于工作区的当前鼠标位置的设备坐标。
bAllowInvert 如果为 TRUE则可以沿 x 轴或 y 轴反转矩形否则为 FALSE。
pWndClipTo 绘制操作将剪切到的窗口。 如果为 NULLpWnd 将用作剪切矩形。
返回值如果按下 ESC 键跟踪过程会停止跟踪器中存储的矩形不会改变并且返回 0。 如果更改已提交通过移动鼠标并释放鼠标左键后会在跟踪器的矩形中记录新的位置和/或大小并返回非零值。 CRectTracker::TrackRubberBand 调用此函数以执行橡皮筋选择。该函数的原型如下
BOOL TrackRubberBand(
CWnd* pWnd,
CPoint point,
BOOL bAllowInvert TRUE);
参数 pWnd 包含矩形的窗口对象。 point 相对于工作区的当前鼠标位置的设备坐标。 bAllowInvert 如果为 TRUE则可以沿 x 轴或 y 轴反转矩形否则为 FALSE。 返回值如果鼠标已移动且矩形不为空则为非零值否则为 0。 CRectTracker 类的公共数据成员成员变量 CRectTracker 类的公共数据成员成员变量如下 上面已经详细介绍了CRectTracker类下面用一个对话框程序来演示CRectTracker类的用法。
CRectTracker类应用示例 新建一个对话框Project来演示CRectTracker类的用法。对话框界面如下: 为简化图像处理程序这里会用到OpenCVOpenCV的配置如下这里使用的4.90用其他低一些的版本也快 由于用OpenCV显示图像显示窗口难以嵌入MFC对话框。 为便于图像显示许为对话框程序添加Mat对象转Cimage对象程序及图像显示程序。
Mat对象转Cimage对象程序的代码如下
void CRectTrackerTestDlg::MatToCImage(Mat src, CImage dst)
{if (src.empty() || (src.type() ! CV_8UC3 src.type() ! CV_8UC1)) {return;}// 如果CImage对象有附加图像就分离并销毁图像if (!dst.IsNull())dst.Destroy();//创建CImage对象附加图像需与源图像大小类型一致dst.Create(src.cols, src.rows, 8 * src.channels());if (src.channels() 1){//将源位图转成八位灰度图时CImage对象需用到颜色表需定义一个RGBQUAD数组并填充该数组RGBQUAD* colorTable new RGBQUAD[256];for (int i 0; i 256; i){colorTable[i].rgbRed i;colorTable[i].rgbGreen i;colorTable[i].rgbBlue i;}//设置颜色表RGB分量值dst.SetColorTable(0, 255, colorTable);}int rows src.rows;int cols src.cols;uchar channels src.channels();//内存中的数据传送注意这里是逐行传送。for (int i 0; i rows; i){memcpy(dst.GetPixelAddress(0, i), src.ptruchar(i), cols * channels);}
}
图像显示程序的代码如下
if (mImage.IsNull())MessageBox(LNo Image to Display!, L系统提示, MB_ICONWARNING | MB_OK);
else
{CClientDC dc(this);mImage.BitBlt(dc.GetSafeHdc(), 0, 0, SRCCOPY);
} 下面再为对话框按钮添加事件处理程序代码”打开图像“按钮的事件处理程序的代码如下
void CRectTrackerTestDlg::OnBnClickedOpen()
{mString 正在进行打开图像操作...;mInformation.SetWindowTextW(mString);CFileDialog fdlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T(All files(*.*)|*.*||));if (fdlg.DoModal() IDOK){m_Path fdlg.GetPathName();m_strEx fdlg.GetFileExt();m_strName fdlg.GetFileName();m_Path.ReleaseBuffer();m_strEx.ReleaseBuffer();m_strName.ReleaseBuffer();m_str CT2A(m_Path);src imread(m_str);dst src;if (src.empty()){mString.Format(L打开图像文件%s失败,文件格式不正确或文件已损坏, m_strName);mInformation.SetWindowTextW(mString);}else{MatToCImage(dst, mImage); //send Mat object data to CImage objiect//DispalyImage(mImage); //dispaly imageInvalidate();mString.Format(L已打开%s , m_Path);mInformation.SetWindowTextW(mString);}}else{mString 已取消打开图像;mInformation.SetWindowTextW(mString);}
}
由于打开图像的代码中DisplayImagemImage已被屏蔽掉需在Opaint中添加图像显示代码如下 “缩放图像”按钮的事件处理程序的代码如下
void CRectTrackerTestDlg::OnBnClickedScaleImage()
{UpdateData(1);int nWidth, nHeight;nWidth (int)(fscale * dst.cols) / 4 * 4; //fscale为按钮旁边编辑框绑定变量用以设定缩放系数nHeight fscale * dst.rows;resize(dst, dst, Size(nWidth, nHeight));MatToCImage(dst, mImage); //send Mat object data to CImage objiectInvalidate();mString.Format(L缩放操作已完成,现在图像大小是缩放前的 %f 倍, fscale);mInformation.SetWindowTextW(mString);
} 为“选择ROI区域”按钮添加事件处理程序“选择ROI区域”按钮的事件处理程序代码如下
void CRectTrackerTestDlg::OnBnClickedSelectRoiArea()
{if (bPikFrameEanble){bPikFrameEanble false;pickRect CRect(0, 0, 0, 0);pickFrame.m_rect pickRect;Invalidate();}bDrawPickFrame true;
}
仅有上面这个事件处理程序是没法实现选择ROI区域的首先需声明CRectTracker变量变量还需初始化然后在鼠标消息处理程序中添加选择框绘制、大小调整、移动等相关代码。这里声明的CRectTracker变量及其相关变量如下 CRectTracker变量初始化的代码如下 在OnLButtonDown(UINT nFlags, CPoint point)函数中加入如下代码
void CRectTrackerTestDlg::OnLButtonDown(UINT nFlags, CPoint point)
{CDC* pDC GetDC();if (bDrawPickFrame){bStartDraw true;bDrawPickFrame false;}else{if (bPikFrameEanble){pickFrame.Track(this, point);//pickFrame.Draw(pDC);pickFrame.GetTrueRect(pickRect);Invalidate();}}ReleaseDC(pDC);CDialogEx::OnLButtonDown(nFlags, point);
}再在OnLButtonUp(UINT nFlags, CPoint point)中加入代码代码如下
void CRectTrackerTestDlg::OnLButtonUp(UINT nFlags, CPoint point)
{CDC* pDC GetDC();if (bStartDraw){bStartDraw false;bPikFrameEanble true;pickFrame.TrackRubberBand(this, point);pickFrame.Draw(pDC);pickFrame.GetTrueRect(pickRect);}ReleaseDC(pDC);CDialogEx::OnLButtonUp(nFlags, point);
}
到此可以实现选择ROI区域了试运行程序结果如下 点击打开图像按钮选择图像文件如下 点击打开结果如下 点击“选取ROI区域”按钮将鼠标指针移动到图像适当位置点击鼠标左键只能一次然后拖动鼠标可以看到随着鼠标指针移动有一个变化的矩形在适当位置再次点击鼠标左键即绘制出了一个选择框如下 将鼠标指针移动到选择矿内按下鼠标左键不松拖动鼠标即可移动选择框。将鼠标指针移动到选择框的图柄上按下鼠标左键不松拖动鼠标即可改变选择框的大小。但是目前鼠标的指针不会随着不同的操作变化。 现在来改善这一不足添加OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)函数在OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)函数中加入如下代码
BOOL CRectTrackerTestDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{if (pWnd this pickFrame.SetCursor(this, nHitTest)){// 如果SetCursor成功设置了光标形状则返回TRUE return TRUE;}return CDialogEx::OnSetCursor(pWnd, nHitTest, message);
}
再次试运行点击“选取ROI区域”按钮绘制选取框这时可以看到当鼠标指针移动到选取框内时鼠标指针变成了4箭头移动图标指针移动到不同的图柄上时指针图标也会发生改变。 添加截取ROI区域按钮的事件处理程序代码代码如下
void CRectTrackerTestDlg::OnBnClickedKeepRoiArea()
{dst dst(Rect(pickRect.left, pickRect.top, pickRect.Width(), pickRect.Height()));MatToCImage(dst, mImage);bPikFrameEanble false;pickRect CRect(0, 0, 0, 0);pickFrame.m_rect pickRect;mString 截取ROI区域操作已完成;mInformation.SetWindowTextW(mString);Invalidate();
} 添加保存图像按钮的事件处理程序代码代码如下
void CRectTrackerTestDlg::OnBnClickedSaveImage()
{mString 正在进行图像存储操作...;mInformation.SetWindowTextW(mString);CString mfilter _T(图片文件(*.bmp *.png *.jpg *.webp *.tif)|*.bmp;*.png;*jpg,*.webp,*.tif|All Files (*.*)|*.*||);CFileDialog fdlg(FALSE, NULL, 0, OFN_OVERWRITEPROMPT, mfilter, NULL);if (fdlg.DoModal() IDOK){m_Path fdlg.GetPathName();m_strEx fdlg.GetFileExt();m_strName fdlg.GetFileName();m_Path.ReleaseBuffer();m_strEx.ReleaseBuffer();m_strName.ReleaseBuffer();}else{mString 图像存储操作已被取消;mInformation.SetWindowTextW(mString);return;}if (m_strEx BMP || m_strEx bmp || m_strEx dib || m_strEx TIF || m_strEx tif || m_strEx tiff || m_strEx PNG || m_strEx png|| m_strEx jpg || m_strEx JPG || m_strEx jpe || m_strEx jpeg || m_strEx jp2 || m_strEx webp || m_strEx avif || m_strEx pbm|| m_strEx pgm || m_strEx ppm || m_strEx pxm || m_strEx pnm || m_strEx pfm || m_strEx sr || m_strEx ras || m_strEx exr|| m_strEx hdr || m_strEx pic){m_str CT2A(m_Path);imwrite(m_str, dst);mString.Format(L图像文件已存储到%s , m_Path);mInformation.SetWindowTextW(mString);}else if (m_strEx ){m_Path .bmp;m_str CT2A(m_Path);imwrite(m_str, dst);mString.Format(L图像文件已存储到%s , m_Path);mInformation.SetWindowTextW(mString);}
}
到此示例程序的代码已完成。试运行结果如下 点击“打开图像”按钮选择打开图像文件 点击“打开”按钮打开图像如下 在“缩放图像”按钮旁的输入框中输入2.5然后点击“缩放图像”按钮结果如下 点击“选取ROI区域”按钮将鼠标指针移动到图片适当位置点击鼠标左键然后拖动鼠标到适当位置点击鼠标左键选取图像中自己感兴趣的区域如下 点击“截取ROI区域”按钮结果如下 点击“保存图像”按钮选定路径输入存储图像名 点击保存按钮结果如下 再点击“打开图像”按钮选择刚才存储的图片 点击“打开”按钮结果如下 说明存储的图片可以正常打开。本示例程序测试到此结束。本示例程序的源代码已上传到CSDN如果需要查看细节可以去下载。下载链接为https://download.csdn.net/download/billliu66/89541184
如果需要重新编译因OpenCV的路径及版本不一定一致一般需要重新配置 OpenCV。本示例程序是基于OpenCv4.90及VS2022编写。