Advertisement

深度学习训练图片收集器——C++截图程序(主对话框响应键鼠消息截屏)

阅读量:

在上一节《深度学习训练图片收集器——C++截图程序的实现2(键鼠钩子篇)》中,我们完成了键鼠截图信息的传输过程。本节将重点完成主程序中截图功能的实现。

当前的设计思路为:当主程序接收到截图指令后,将弹出一个覆盖整个屏幕的界面,并将当前桌面画面渲染至该全屏窗口中。用户在该窗口内拖动鼠标时,系统将调用OpenCV相关函数,在屏幕上绘制一个带有红色边框的选取区域。当用户在该区域内部双击鼠标左键时,系统将执行截图保存操作,并关闭全屏界面,返回至桌面环境。

为增强软件使用的便捷性,我们特别设计了取消已绘制矩形的功能。用户无需退出全屏界面即可清除当前选取区域,并重新绘制新的矩形范围。与常见的微信或QQ截图工具相比,这些平台在单次截图操作过程中仅允许绘制一个矩形区域,无法中途取消并重新选择新的范围,必须退出后再进行新一轮截图操作。

需要说明的是,本程序依赖于OpenCV函数库的支持。若希望参照本程序进行相关实验,请确保已正确安装OpenCV开发环境。

接下来我们将开始具体实现截图功能模块。

首先打开上一节《C++截图程序的实现2(键鼠钩子篇)》中创建的工程项目ScreenshotForML,在该项目中新增一个对话框资源,并将其标识符修改为“IDD_DIALOG_SCREENSHOT”,同时移除对话框上的所有按钮控件,具体界面布局如图所示:

通过右键点击此对话框,从弹出的菜单中选取“添加类...”选项,在随后出现的MFC类向导界面中,输入类名为“CScreenShotView”,并将基类设置为“CDialog”,具体操作如图所示:

执行完毕。

接下来,打开ScreenShotView.h头文件,并在DECLARE_MESSAGE_MAP()上方插入如下函数声明:

复制代码
     afx_msg LRESULT OnMouseDown(WPARAM wParam, LPARAM lParam);

    
     afx_msg LRESULT OnMouseUp(WPARAM wParam, LPARAM lParam);
    
     afx_msg LRESULT OnMouseMove(WPARAM wParam, LPARAM lParam);
    
     afx_msg LRESULT OnMouseDBClick(WPARAM wParam, LPARAM lParam);
    
     afx_msg LRESULT OnEscPressed(WPARAM wParam, LPARAM lParam);
    
    
    
    
    cpp

在DECLARE_MESSAGE_MAP()的下方需插入如下声明:

复制代码
 public:

    
     void DrawScreenshot();
    
     
    
 private:
    
     bool                 m_bHideWindow;                           // 是否准备隐藏窗口,如果是,则把DC的颜色全部置为灰色,否则重新显示窗口时会有明显的闪烁
    
     bool                 m_bStartDrawing;                          // 是否开始绘制矩形
    
     bool                 m_bIsDrawing;                               // 是否正在用鼠标拉矩形
    
     POINT             m_ptRectStart;                              // 鼠标所拉矩形的左上顶点坐标
    
     POINT             m_ptRectEnd;                                // 鼠标所拉矩形的右下顶点坐标
    
     BITMAPINFOHEADER m_bitmap_info;
    
  
    
 public:
    
     Mat                  m_cvScreen;                                  // 该变量保存了桌面截图的原始图像
    
     Mat                  m_cvROI;
    
  
    
 public:
    
     afx_msg void OnDestroy();
    
    
    
    

最终,在“#pragma once”语句之后,需插入如下两行代码:

复制代码
 #include "cv.h"

    
  
    
 using namespace cv;
    
    
    
    
    cpp

此时按下F7进行生成操作时,系统会提示无法找到cv.h头文件。要解决该错误提示,只需为当前工程设置OpenCV的包含目录即可。

右键点击ScreenshotForML,依次选择“属性”→“VC++目录”→“包含目录”→“编辑”,在弹出的窗口中输入本机OpenCV对应的路径,如图所示,共需输入三行内容,确认无误后点击确定:

在完成目录配置之后,还需对库目录进行相应的设定,具体操作如下所示:

接下来,在属性页面中依次点击“链接器”→“输入”→“附加依赖项”,在编辑界面中添加以下依赖库(请根据本机实际安装的OpenCV版本进行替换;实际上并不需要全部添加这些依赖文件,此处仅为后续方便扩展其他功能做准备):

opencv_core2411.lib

opencv_highgui2411.lib

opencv_imgproc2411.lib

opencv_legacy2411.lib

opencv_ml2411.lib

opencv_objdetect2411.lib

opencv_ts2411.lib

opencv_video2411.lib

opencv_features2d2411.lib

opencv_flann2411.lib

opencv_nonfree2411.lib

完成以上配置步骤后,按下F7进行项目构建,此时编译错误将不再出现。

CScreenShotView类的具体实现代码位于ScreenShotView.cpp文件中,其完整内容如下:

复制代码
 // ScreenShotView.cpp : 实现文件

    
 //
    
  
    
 #include "stdafx.h"
    
 #include "ScreenshotForML.h"
    
 #include "ScreenShotView.h"
    
 #include "afxdialogex.h"
    
  
    
 #include "cv.h"
    
 #include "highgui.h"
    
 #include "opencv2/features2d/features2d.hpp"
    
 #include "opencv2/nonfree/features2d.hpp"
    
  
    
 using namespace cv;
    
 using namespace std;
    
  
    
 #define WM_MOUSE_LEFT_DOWN                   WM_USER + 113
    
 #define WM_MOUSE_LEFT_UP                          WM_USER + 114
    
 #define WM_MOUSE_MOVE                                WM_USER + 115
    
 #define WM_MOUSE_DBCLICK                          WM_USER + 116
    
 #define WM_ESC_PRESSED                               WM_USER + 117
    
  
    
 #define WM_SCREENSHOT_FINISHED             WM_USER + 118
    
  
    
  
    
 // CScreenShotView 对话框
    
  
    
 IMPLEMENT_DYNAMIC(CScreenShotView, CDialog)
    
  
    
 CScreenShotView::CScreenShotView(CWnd* pParent /*=NULL*/)
    
 : CDialog(CScreenShotView::IDD, pParent)
    
 {
    
     m_bStartDrawing = false;
    
     m_bIsDrawing = false;
    
     m_bHideWindow = false;
    
 }
    
  
    
 CScreenShotView::~CScreenShotView()
    
 {
    
 }
    
  
    
 void CScreenShotView::DoDataExchange(CDataExchange* pDX)
    
 {
    
     CDialog::DoDataExchange(pDX);
    
 }
    
  
    
  
    
 BEGIN_MESSAGE_MAP(CScreenShotView, CDialog)
    
     ON_MESSAGE(WM_MOUSE_LEFT_DOWN, OnMouseDown)
    
     ON_MESSAGE(WM_MOUSE_LEFT_UP, OnMouseUp)
    
     ON_MESSAGE(WM_MOUSE_MOVE, OnMouseMove)
    
     ON_MESSAGE(WM_MOUSE_DBCLICK, OnMouseDBClick)
    
     ON_MESSAGE(WM_ESC_PRESSED, OnEscPressed)
    
     ON_WM_DESTROY()
    
 END_MESSAGE_MAP()
    
  
    
 void CScreenShotView::OnDestroy()
    
 {
    
     CDialog::OnDestroy();
    
  
    
     // TODO:  在此处添加消息处理程序代码
    
 }
    
  
    
  
    
 // CScreenShotView 消息处理程序
    
  
    
  
    
 afx_msg LRESULT CScreenShotView::OnMouseDown(WPARAM wParam, LPARAM lParam)
    
 {
    
     m_bStartDrawing = true;
    
  
    
     GetCursorPos(&m_ptRectStart);
    
  
    
     return 0;
    
 }
    
  
    
 afx_msg LRESULT CScreenShotView::OnMouseUp(WPARAM wParam, LPARAM lParam)
    
 {
    
     m_bStartDrawing = false;
    
     m_bIsDrawing = false;
    
  
    
     return 0;
    
 }
    
  
    
 afx_msg LRESULT CScreenShotView::OnMouseMove(WPARAM wParam, LPARAM lParam)
    
 {
    
     if (m_bStartDrawing) {
    
     m_bIsDrawing = true;
    
     DrawScreenshot();
    
     }
    
  
    
     return 0;
    
 }
    
  
    
 afx_msg LRESULT CScreenShotView::OnMouseDBClick(WPARAM wParam, LPARAM lParam)
    
 {
    
     m_bStartDrawing = false;
    
     m_bIsDrawing = false;
    
  
    
     // 如果发生鼠标双击事件,并且m_cvROI对象存有图像数据,则发送截图完成的消息给主对话框,由主对话框进一步处理
    
     if (m_cvROI.rows > 0) {
    
     m_bHideWindow = true;
    
     DrawScreenshot();
    
     m_bHideWindow = false;
    
  
    
     this->ShowWindow(SW_HIDE);
    
  
    
     HWND hwnd = ::FindWindowA(NULL, "ScreenShot for Machine Learning");
    
     ::PostMessage(hwnd, WM_SCREENSHOT_FINISHED, NULL, NULL);
    
     }
    
  
    
     return 0;
    
 }
    
  
    
 afx_msg LRESULT CScreenShotView::OnEscPressed(WPARAM wParam, LPARAM lParam)
    
 {
    
     m_bStartDrawing = false;
    
     m_bIsDrawing = false;
    
  
    
     this->ShowWindow(SW_HIDE);
    
  
    
     HWND hwnd = ::FindWindowA(NULL, "ScreenShot for Machine Learning");
    
     ::PostMessage(hwnd, WM_ESC_PRESSED, NULL, NULL);
    
  
    
     return 0;
    
 }
    
  
    
 void CScreenShotView::DrawScreenshot()
    
 {
    
     char msg[256] = "11111 ";
    
  
    
     Mat cv_screen;
    
  
    
     POINT pt;
    
     GetCursorPos(&pt);
    
  
    
     // 矩形左上顶点和右下顶点坐标
    
     POINT rectPt1;
    
     POINT rectPt2;
    
  
    
     if (!m_bHideWindow) {
    
     if ((abs(pt.x - m_ptRectStart.x) <= 2) && (abs(pt.y - m_ptRectStart.y) <= 2))
    
         return;
    
  
    
     rectPt1.x = (m_ptRectStart.x < pt.x) ? m_ptRectStart.x : pt.x;
    
     rectPt1.y = (m_ptRectStart.y < pt.y) ? m_ptRectStart.y : pt.y;
    
     rectPt2.x = (m_ptRectStart.x < pt.x) ? pt.x : m_ptRectStart.x;
    
     rectPt2.y = (m_ptRectStart.y < pt.y) ? pt.y : m_ptRectStart.y;
    
  
    
     cv_screen = m_cvScreen.clone();
    
  
    
     // 让截图界面图像整体变暗
    
     for (int a = 0; a < cv_screen.rows; a++) {
    
         uchar *p = cv_screen.ptr<uchar>(a);
    
         for (int b = 0; b < cv_screen.cols; b++) {
    
             p[b * 4 + 0] = ((float)p[b * 4 + 0]) * 0.63;
    
             p[b * 4 + 1] = ((float)p[b * 4 + 1]) * 0.63;
    
             p[b * 4 + 2] = ((float)p[b * 4 + 2]) * 0.63;
    
         }
    
     }
    
  
    
     // 还原选中区域的亮度
    
     Mat roi = cv_screen(Range(rectPt1.y, rectPt2.y), Range(rectPt1.x, rectPt2.x));
    
     m_cvROI = roi.clone();
    
     for (int a = 0; a < roi.rows; a++) {
    
         uchar *p = roi.ptr<uchar>(a);
    
         for (int b = 0; b < roi.cols; b++) {
    
             p[b * 4 + 0] = ((float)p[b * 4 + 0]) * 1.5;
    
             p[b * 4 + 1] = ((float)p[b * 4 + 1]) * 1.5;
    
             p[b * 4 + 2] = ((float)p[b * 4 + 2]) * 1.5;
    
         }
    
     }
    
     m_cvROI = roi.clone();
    
     }
    
     else {
    
     cv_screen = m_cvScreen;
    
     }
    
  
    
     // 对选中区域绘制边界矩形
    
     int       lineType = 8;
    
     rectangle(cv_screen, Point(rectPt1.x, rectPt1.y), Point(rectPt2.x, rectPt2.y), Scalar(0, 0, 255), 3, lineType);
    
  
    
     // 设置Bitmap信息
    
     m_bitmap_info.biBitCount = 32;
    
     m_bitmap_info.biClrImportant = 0;
    
     m_bitmap_info.biCompression = BI_RGB;
    
     m_bitmap_info.biHeight = -m_cvScreen.rows;
    
     m_bitmap_info.biPlanes = 1;
    
     m_bitmap_info.biSize = sizeof(BITMAPINFOHEADER);
    
     m_bitmap_info.biSizeImage = m_cvScreen.cols*m_cvScreen.rows * 4;
    
     m_bitmap_info.biWidth = m_cvScreen.cols;
    
     m_bitmap_info.biXPelsPerMeter = 0;
    
     m_bitmap_info.biYPelsPerMeter = 0;
    
  
    
     byte *p = cv_screen.ptr<byte>(0);
    
     //sprintf(msg + 6, "rows, cols: %d, %d", p[0], p[1]);
    
     //OutputDebugStringA(msg);
    
  
    
     // 将经过OpenCV处理过的图像粘贴到对话框DC上显示出来
    
     int ret = SetDIBitsToDevice(::GetDC(this->m_hWnd), 0, 0, m_cvScreen.cols, m_cvScreen.rows, 0, 0, 0, m_cvScreen.rows, (void*)p, (BITMAPINFO*)&m_bitmap_info, DIB_RGB_COLORS);
    
     this->UpdateWindow();
    
 }
    
    
    
    

上述代码主要用于消息处理及图形绘制功能,其逻辑结构相对简单,已添加部分注释说明,因此不再做进一步解释。

在完成 CScreenShotView 类的声明与实现后,需将以下代码复制并粘贴至主对话框头文件 ScreenshotForMLDlg.h 中进行覆盖:

复制代码
 // ScreenshotForMLDlg.h : 头文件

    
 //
    
  
    
 #pragma once
    
  
    
  
    
 // CScreenshotForMLDlg 对话框
    
 class CScreenshotForMLDlg : public CDialogEx
    
 {
    
 // 构造
    
 public:
    
 	CScreenshotForMLDlg(CWnd* pParent = NULL);	// 标准构造函数
    
  
    
 // 对话框数据
    
 	enum { IDD = IDD_SCREENSHOTFORML_DIALOG };
    
  
    
 	protected:
    
 	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持
    
  
    
  
    
     // 实现
    
 protected:
    
     HICON m_hIcon;
    
  
    
     // 生成的消息映射函数
    
     virtual BOOL OnInitDialog();
    
     afx_msg void OnPaint();
    
     afx_msg HCURSOR OnQueryDragIcon();
    
     afx_msg LRESULT OnStartScreenshot(WPARAM wParam, LPARAM lParam);
    
     afx_msg LRESULT OnEscPressed(WPARAM wParam, LPARAM lParam);
    
     afx_msg LRESULT OnScreenshotFinished(WPARAM wParam, LPARAM lParam);
    
     DECLARE_MESSAGE_MAP()
    
  
    
 private:
    
     bool                 m_bStartScreenShot;                    // 是否处于截屏状态
    
     bool                 m_bIsDrawingRectangle;              // 是否正在用鼠标拉矩形
    
     POINT             m_ptRectStart;                              // 鼠标所拉矩形的左上顶点坐标
    
     POINT             m_ptRectEnd;                                // 鼠标所拉矩形的右下顶点坐标
    
  
    
 private:
    
     CDialog         *m_screenshot_dlg;
    
  
    
 public:
    
     afx_msg void OnDestroy();
    
 };
    
    
    
    

接下来,需对ScreenshotForMLDlg.cpp文件进行操作,在该文件的头文件包含声明部分插入如下代码:

复制代码
 #include "ScreenShotView.h"

    
 #include "cv.h"
    
 #include "highgui.h"
    
 #include "opencv2/features2d/features2d.hpp"
    
 #include "opencv2/nonfree/features2d.hpp"
    
  
    
 using namespace cv;
    
 using namespace std;
    
  
    
 #define WM_START_SCREENSHOT                  WM_USER + 111
    
 #define WM_ESC_PRESSED                               WM_USER + 117
    
 #define WM_SCREENSHOT_FINISHED             WM_USER + 118
    
    
    
    

在cpp文件对应的消息映射区域中,需添加以下映射说明:

复制代码
     ON_MESSAGE(WM_START_SCREENSHOT, OnStartScreenshot)

    
     ON_MESSAGE(WM_ESC_PRESSED, OnEscPressed)
    
     ON_MESSAGE(WM_SCREENSHOT_FINISHED, OnScreenshotFinished)
    
     ON_WM_DESTROY()
    
    
    
    
    cpp

在OnInitDialog()函数内部插入如下代码段:

复制代码
     // 设置窗口标题,以便传递消息

    
     this->SetWindowTextW(L"ScreenShot for Machine Learning");
    
  
    
     // 初始化成员变量
    
     m_screenshot_dlg = NULL;
    
    
    
    
    cpp

接下来,需在对应的cpp文件中补充如下四个函数的实现代码:

复制代码
 void CScreenshotForMLDlg::OnDestroy()

    
 {
    
     CDialogEx::OnDestroy();
    
  
    
     // TODO:  在此处添加消息处理程序代码
    
     if (m_screenshot_dlg) {
    
     delete m_screenshot_dlg;
    
     m_screenshot_dlg = NULL;
    
     }
    
 }
    
  
    
 afx_msg LRESULT CScreenshotForMLDlg::OnStartScreenshot(WPARAM wParam, LPARAM lParam)
    
 {
    
     m_bStartScreenShot = true;
    
  
    
     // 窗口定位
    
     RECT rect;
    
     int nScreenX = GetSystemMetrics(SM_CXSCREEN);
    
     int nScreenY = GetSystemMetrics(SM_CYSCREEN);
    
  
    
     DWORD dwStyle;
    
     DWORD dwNewStyle;
    
  
    
     // 获取桌面DC
    
     CWnd *pDesktopWnd = GetDesktopWindow();
    
     CDC *pDeskDC = pDesktopWnd->GetDC();
    
     CRect re;
    
  
    
     // 获取窗口的大小
    
     pDesktopWnd->GetClientRect(&re);
    
     CBitmap cbmp;
    
     cbmp.CreateCompatibleBitmap(pDeskDC, re.Width(), re.Height());
    
  
    
     BITMAP bitmap;
    
     cbmp.GetBitmap(&bitmap);
    
  
    
     // 创建一个兼容的内存画板
    
     CDC memDC;
    
     memDC.CreateCompatibleDC(pDeskDC);
    
     memDC.SelectObject(&cbmp);
    
  
    
     // BitBlt 绘制
    
     memDC.BitBlt(0, 0, re.Width(), re.Height(), pDeskDC, 0, 0, SRCCOPY);
    
  
    
     // opencv 操作开始
    
     IplImage *cvImage = cvCreateImage(cvSize(nScreenX, nScreenY), 8, 3);
    
     DWORD size = bitmap.bmWidthBytes * bitmap.bmHeight;
    
     byte* pData = new BYTE[size];
    
  
    
     BITMAPINFOHEADER bit_info;
    
     bit_info.biBitCount = 32;
    
     bit_info.biClrImportant = 0;
    
     bit_info.biCompression = BI_RGB;
    
     bit_info.biHeight = -bitmap.bmHeight;
    
     bit_info.biPlanes = 1;
    
     bit_info.biSize = sizeof(BITMAPINFOHEADER);
    
     bit_info.biSizeImage = size;
    
     bit_info.biWidth = bitmap.bmWidth;
    
     bit_info.biXPelsPerMeter = 0;
    
     bit_info.biYPelsPerMeter = 0;
    
  
    
     // 获取桌面前景图像数据,并将数据保存在一个Mat对象中
    
     int ret = GetDIBits(pDeskDC->m_hDC, cbmp, 0, -bit_info.biHeight, pData, (BITMAPINFO*)&bit_info, DIB_RGB_COLORS);
    
     Mat    cv_screen = Mat(Size(nScreenX, nScreenY), CV_8UC4, pData);
    
  
    
     // 对桌面图像绘制边缘,提示用户进入截图操作
    
     int       lineType = 8;
    
     rectangle(cv_screen, Point(0, 0), Point(nScreenX - 1, nScreenY - 1), Scalar(255, 0, 255), 8, lineType);
    
  
    
     // 创建截图窗口时需要将父窗口指定为当前的前置窗口,否则默认父窗口为本程序的主界面,会导致本程序主界面自动前置
    
     m_screenshot_dlg = new CScreenShotView;
    
     m_screenshot_dlg->Create(IDD_DIALOG_SCREENSHOT, CWnd::FromHandle(::GetForegroundWindow()));
    
     m_screenshot_dlg->SetWindowTextW(L"ScreenShot for Machine Learning (full screen)");
    
  
    
     // 设置窗口样式,最大化显示截图窗口,并使其前置
    
     dwStyle = m_screenshot_dlg->GetStyle();
    
     dwNewStyle = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
    
     dwNewStyle &= dwStyle;
    
     ::SetWindowLong(m_screenshot_dlg->m_hWnd, GWL_STYLE, dwNewStyle);       // 设置成新的样式
    
     ::SetWindowPos(m_screenshot_dlg->m_hWnd, HWND_TOPMOST, 0, 0, nScreenX, nScreenY, SWP_NOMOVE | SWP_SHOWWINDOW);
    
     m_screenshot_dlg->ShowWindow(SW_SHOWMAXIMIZED);
    
  
    
     // 将处理过的CV图像显示在截图窗口
    
     byte *p = cv_screen.ptr<byte>(0);
    
     ret = SetDIBitsToDevice(::GetDC(m_screenshot_dlg->m_hWnd), 0, 0, re.Width(), re.Height(), 0, 0, 0, re.Height(), (void*)p, (BITMAPINFO*)&bit_info, DIB_RGB_COLORS);
    
  
    
     // 更新截图窗口
    
     m_screenshot_dlg->UpdateWindow();
    
  
    
     // 将截图窗口图像保存在m_cvScreen
    
     ((CScreenShotView*)m_screenshot_dlg)->m_cvScreen = cv_screen.clone();
    
  
    
     // 销毁临时创建的内存区域
    
     delete[] pData;
    
     ReleaseDC(pDeskDC);
    
     ReleaseDC(&memDC);
    
     cvReleaseImage(&cvImage);
    
     DeleteObject(cbmp);
    
  
    
     return 0;
    
 }
    
  
    
  
    
 afx_msg LRESULT CScreenshotForMLDlg::OnEscPressed(WPARAM wParam, LPARAM lParam)
    
 {
    
     if (m_screenshot_dlg) {
    
     delete m_screenshot_dlg;
    
     m_screenshot_dlg = NULL;
    
     }
    
     return 0;
    
 }
    
  
    
  
    
 afx_msg LRESULT CScreenshotForMLDlg::OnScreenshotFinished(WPARAM wParam, LPARAM lParam)
    
 {
    
     if (m_screenshot_dlg) {
    
     if (((CScreenShotView*)m_screenshot_dlg)->m_cvROI.rows > 0) {
    
         // 截图结束,截取的图像保存在m_cvROI,通过对m_cvROI进行操作,就可以实现二次处理
    
         //::CreateThread(NULL, 0, Thread_ScreenshotHandler, (VOID*)(&((CScreenShotView*)m_screenshot_dlg)->m_cvROI), 0, NULL);
    
  
    
         // 这里睡眠100毫秒,是为了让Mat数据在m_screenshot_dlg被delete之前可以被处理线程完整拷贝;
    
         // 更好的做法是创建互斥体,或等待某个布尔变量发生变化;也可以使用WaitForSingleObject()函数
    
         Sleep(100);
    
     }
    
     delete m_screenshot_dlg;
    
     m_screenshot_dlg = NULL;
    
     }
    
     return 0;
    
 }
    
    
    
    

目前,所有代码的编写工作已全部结束。截屏图像被存储于m_screenshot_dlg类中的m_cvROI成员变量中,针对该变量,我们可以进一步开展诸如轮廓检测、特征提取等图像处理操作,同时也可以将其保存为文件格式。

此时按下F7键即可生成可执行文件exe,启动该exe程序后,即可顺利进行屏幕截图操作,其对应的快捷键组合为alt+a。在执行exe程序之前,请务必完成一项重要步骤:将opencv相关的dll文件路径添加至系统环境变量Path中。具体而言,需要将类似“C:\opencv241\opencv\build\x86\vc12\bin”以及“C:\opencv241\opencv\build\x64\vc12\bin”这样的目录路径纳入环境变量配置。

程序运行的实际效果如以下示意图所示:

全部评论 (0)

还没有任何评论哟~