【2012年终总结】之三 opencv + ds采集摄像头视频 简易截图工具

 

关于截图工具,QQ的截图可以自动选择窗口,之前以为是颜色相近的选取,后来意识到不对,应该是窗口,用spy++找到的窗口和QQ截取到的窗口也是一样的,

但是有个问题,那就是怎么选择这些窗口?   我的想法是枚举所有窗口,记录这些窗口的位置和大小,然后当鼠标经过的时候用DC来画框,但是这样有个问题就是枚举到的窗口有几百个,太多了,当鼠标经过的从几百个大小的数组或vector里查找当前鼠标的位置在哪个窗口范围内实在是太拙计了,这种方法实在不太靠谱。

 

关于QQ的截图: 拷贝当前屏幕图像然后全屏打开一个(透明?)窗口,把拷贝到的图像贴在那个全屏窗口上,然后鼠标经过窗口时画框。。。

 

由于没能实现后面那几步,所以只是做了一个简易的截图工具,其原理差不多,那就是:当截图时拷贝当前屏幕图像然后打开一个对话框,把这个对话框放大到屏幕大小,也就是全屏,然后把屏幕图像贴到对话框上,然后鼠标可以拖动选择区域,在拖动的时候有一个【确定】button在鼠标附近,点击这个button就可以保存选择的区域至bmp文件。 当然需要考虑背景重绘的情况!

把截图工具封装成了一个类,该类继承自CWnd类,对应的对话框为IDD_DLG_CAPTURE ,在Jietu.h第15行, 对话框上有一个button,在这里button的名字没改,就是button1,如果改了这个名字,对应的代码里也需要修改。

 

Jietu.h

 1 #pragma once
 2 
 3 
 4 // CJietu 对话框
 5 
 6 class CJietu : public CDialog
 7 {
 8     DECLARE_DYNAMIC(CJietu)
 9 
10 public:
11     CJietu(CWnd* pParent = NULL);   // 标准构造函数
12     virtual ~CJietu();
13 
14 // 对话框数据
15     enum { IDD = IDD_DLG_CAPTURE };
16 
17 protected:
18     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
19 
20     DECLARE_MESSAGE_MAP()
21 public:
22     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
23     afx_msg void OnPaint();
24     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
25     afx_msg void OnMouseMove(UINT nFlags, CPoint point);
26     afx_msg BOOL OnEraseBkgnd(CDC* pDC);
27     afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
28     virtual BOOL OnInitDialog();
29 
30     void WriteBMPFile(HBITMAP hBitMap, LPTSTR filename, HDC hDC, int cx, int cy);
31 
32 protected:
33     int m_nCx;
34     int m_nCy;
35 
36     CPoint m_pointStart;  //记录起点;
37     CPoint m_pointEnd;    //记录终点;
38     bool m_bIsBegin;
39 
40     CDC m_dcGlobal;
41     HDC m_hDCGlobal;
42     HBITMAP m_hBitmapGlobal;
43     CBitmap m_bitmapGlobal;
44     CWnd *m_pWndButtonOK;  //确定 按钮; 
45 
46 public:
47     afx_msg void OnBnClickedButton1();
48 };

 

 

Jietu.cpp

  1 // Jietu.cpp : 实现文件
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "CameraMonitor.h"
  6 #include "Jietu.h"
  7 
  8 
  9 // CJietu 对话框
 10 
 11 IMPLEMENT_DYNAMIC(CJietu, CDialog)
 12 
 13 CJietu::CJietu(CWnd* pParent /*=NULL*/)
 14     : CDialog(CJietu::IDD, pParent)
 15 { 
 16     m_nCx = GetSystemMetrics(SM_CXSCREEN);
 17     m_nCy = GetSystemMetrics(SM_CYSCREEN);
 18     m_bIsBegin = false; 
 19 }
 20 
 21 CJietu::~CJietu()
 22 {
 23     if (m_hDCGlobal)
 24     {
 25         DeleteDC(m_hDCGlobal);
 26     }
 27     if (m_hBitmapGlobal)
 28     {
 29         DeleteObject(m_hBitmapGlobal);
 30     }
 31 
 32     if (m_dcGlobal)
 33     {
 34         m_dcGlobal.DeleteDC();
 35     }
 36 }
 37 
 38 void CJietu::DoDataExchange(CDataExchange* pDX)
 39 {
 40     CDialog::DoDataExchange(pDX);
 41 }
 42 
 43 
 44 BEGIN_MESSAGE_MAP(CJietu, CDialog)
 45     ON_WM_LBUTTONDOWN()
 46     ON_WM_PAINT()
 47     ON_WM_LBUTTONUP()
 48     ON_WM_MOUSEMOVE()
 49     ON_WM_ERASEBKGND()
 50     ON_WM_SHOWWINDOW()
 51     ON_BN_CLICKED(IDC_BUTTON1, &CJietu::OnBnClickedButton1)
 52 END_MESSAGE_MAP()
 53 
 54 
 55 // CJietu 消息处理程序
 56 
 57 void CJietu::OnLButtonDown(UINT nFlags, CPoint point)
 58 {
 59     // TODO: 在此添加消息处理程序代码和/或调用默认值;
 60 
 61     ClientToScreen(&point);
 62     m_pointStart = point;  //记录起点;
 63     m_bIsBegin = true; 
 64 
 65     SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
 66 
 67     CDialog::OnLButtonDown(nFlags, point);
 68 }
 69 
 70 void CJietu::OnLButtonUp(UINT nFlags, CPoint point)
 71 {
 72     // TODO: 在此添加消息处理程序代码和/或调用默认值;
 73     m_bIsBegin = false;
 74     ClientToScreen(&point);
 75 
 76     //鼠标左键抬起,鼠标指针恢复正常;
 77     SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
 78 
 79 
 80 
 81     CDialog::OnLButtonUp(nFlags, point);
 82 }
 83 
 84 void CJietu::OnMouseMove(UINT nFlags, CPoint point)
 85 {
 86     // TODO: 在此添加消息处理程序代码和/或调用默认值; 
 87 
 88 
 89     if (true == m_bIsBegin)
 90     {
 91         int b = false;
 92         if (false == b && m_pWndButtonOK != NULL)
 93         { 
 94             m_pWndButtonOK->ShowWindow(SW_SHOW);     //确定 按钮显示;
 95             b = true;
 96         }
 97 
 98         Invalidate(TRUE);  //先把之前线条的清空;  
 99         UpdateWindow(); 
100 
101         ClientToScreen(&point);   
102         m_pointEnd = point;          //记录终点;
103 
104         CPen pen(PS_SOLID, 6, RGB(255, 0, 0));
105         CPen *oldPen;
106         CDC *pDC;
107         CWnd *pWnd;
108         CRect rect;
109 
110         int cx = m_nCx;
111         int cy = m_nCy;  
112 
113         pWnd = FromHandle(m_hWnd);
114         pDC = pWnd->GetDC();
115 
116         int x1 = m_pointStart.x;
117         int y1 = m_pointStart.y;
118         int x2 = point.x;
119         int y2 = y1;
120         int x3 = point.x;
121         int y3 = point.y;
122         int x4 = x1;
123         int y4 = y3;
124 
125         oldPen = pDC->SelectObject(&pen);
126 
127         pDC->MoveTo(x1, y1);
128         pDC->LineTo(x2, y2);
129 
130         pDC->MoveTo(x2, y2);
131         pDC->LineTo(x3, y3);
132 
133         pDC->MoveTo(x3, y3);
134         pDC->LineTo(x4, y4);
135 
136         pDC->MoveTo(x4, y4);
137         pDC->LineTo(x1, y1);
138 
139         int width = abs(x1 - x3);
140         int height = abs(y1 - y3);
141         char wArr[5] = {0};
142         char hArr[5] = {0};
143         _itoa_s(width, wArr, 10);
144         _itoa_s(height, hArr, 10);
145 
146         CString str("尺寸:");
147         str += wArr;
148         str += "x";
149         str += hArr;
150         pDC->SetBkMode(TRANSPARENT);
151 
152         CFont font;
153         CFont *oldFont;
154         font.CreatePointFont(150, _T("宋体"));
155         oldFont = pDC->SelectObject(&font);
156         pDC->SetTextColor(RGB(0, 0, 255));
157 
158         int xPos = 0;
159         int yPos = 0;
160         int xStep = 100;
161         int yStep = 50;
162 
163         //选区到了边界的情况;
164         if (cx - x3 <= xStep || cy - y3 <= yStep || (cx - x3) >= (cx - xStep)  || (cy - y3) >= (cy - yStep))
165         {
166             if (x3 >= x1 && y3 <= y1)
167             {
168                 pDC->TextOut(x3 - xStep - 50, y3 + yStep - 10, str);
169                 m_pWndButtonOK->SetWindowPos(NULL, x3 - xStep - 50, y3 + yStep + 20, 0, 0, SWP_NOSIZE);
170             }
171             else if (x3 >= x1 && y3 >= y1)
172             {
173                 pDC->TextOut(x3 - xStep - 50, y3 - yStep, str);
174                 m_pWndButtonOK->SetWindowPos(NULL, x3 - xStep - 50, y3 - yStep - 60, 0, 0, SWP_NOSIZE);
175             }
176             else if (x3 <= x1 && y3 >= y1)
177             {
178                 pDC->TextOut(x3 + xStep - 20, y3 - yStep, str);
179                 m_pWndButtonOK->SetWindowPos(NULL, x3 + xStep - 20, y3 - yStep - 60, 0, 0, SWP_NOSIZE);
180             }
181             else
182             {
183                 pDC->TextOut(x3 + xStep - 50, y3 + yStep - 10, str);
184                 m_pWndButtonOK->SetWindowPos(NULL, x3 + xStep - 50, y3 + yStep + 20, 0, 0, SWP_NOSIZE);
185             } 
186 
187         }
188         else
189         {
190             pDC->TextOut(x3, y3, str);
191             m_pWndButtonOK->SetWindowPos(NULL, x3, y3 + 30, 0, 0, SWP_NOSIZE);
192         }
193 
194 
195         pDC->SelectObject(oldFont);
196         pDC->SelectObject(oldPen);
197         pWnd->ReleaseDC(pDC);
198         pen.DeleteObject();
199         font.DeleteObject();
200 
201     }
202 
203     CDialog::OnMouseMove(nFlags, point);
204 }
205 
206 void CJietu::OnPaint()
207 {
208     CPaintDC dc(this); // device context for painting
209     // TODO: 在此处添加消息处理程序代码
210     // 不为绘图消息调用 CDialog::OnPaint()  
211     
212     HWND hWnd = m_hWnd;
213     CWnd *pWnd = FromHandle(hWnd); 
214     CDC *pDC = pWnd->GetDC();
215     HDC hDC = pDC->GetSafeHdc();
216 
217     StretchBlt(hDC, 0, 0, m_nCx, m_nCy, m_hDCGlobal, 0, 0, m_nCx, m_nCy, SRCCOPY); 
218 
219     pWnd->ReleaseDC(pDC); 
220      
221 }
222 
223 
224 
225 
226 
227 BOOL CJietu::OnEraseBkgnd(CDC* pDC)
228 {
229     // TODO: 在此添加消息处理程序代码和/或调用默认值;
230  
231     HWND hWnd = m_hWnd;
232     CWnd *pWnd = FromHandle(hWnd); 
233     HDC hDC = pDC->GetSafeHdc();
234  
235     StretchBlt(hDC, 0, 0, m_nCx, m_nCy, m_hDCGlobal, 0, 0, m_nCx, m_nCy, SRCCOPY);  
236 
237     return TRUE;
238 //    return CDialog::OnEraseBkgnd(pDC);
239 }
240 
241 void CJietu::OnShowWindow(BOOL bShow, UINT nStatus)
242 {  
243     m_pWndButtonOK = (CWnd*)GetDlgItem(IDC_BUTTON1);   //确定 按钮指针;
244 
245 
246     //////////////////////////////////////////////////////////////////////////
247     CDialog::OnShowWindow(bShow, nStatus);
248     SetWindowPos(&wndTop, 0, 0, m_nCx, m_nCy, 0);
249     ////////////////////////////////////////////////////////////////////////// 
250  
251     CDC *pDC = GetDC();
252     HDC hDC = pDC->GetSafeHdc();
253 
254     StretchBlt(hDC, 0, 0, m_nCx, m_nCy, m_hDCGlobal, 0, 0, m_nCx, m_nCy, SRCCOPY);
255 
256     ReleaseDC(pDC);
257  
258 
259 }
260 
261 BOOL CJietu::OnInitDialog()
262 {
263     CDialog::OnInitDialog();
264 
265     // TODO:  在此添加额外的初始化;  
266 
267     //改变指针形状为十字星;
268     SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS)); 
269 
270 
271     CWnd *pDesktop = GetDesktopWindow();
272     HWND hWndDesktop = pDesktop->m_hWnd; 
273     CDC *pDCDesktop = pDesktop->GetDC();
274     HDC hDCDesktop = pDCDesktop->GetSafeHdc(); 
275 
276     HWND hWnd = m_hWnd;
277     CWnd *pWnd = FromHandle(hWnd);
278     CDC *pDC = pWnd->GetDC();
279     HDC hDC = pDC->GetSafeHdc();
280 
281     HDC hDCMem = CreateCompatibleDC(hDCDesktop);                                      //兼容DC;
282     HBITMAP hBitmap = CreateCompatibleBitmap(hDCDesktop, m_nCx,m_nCy);                //桌面DC的图片;
283  //   SelectObject(hDCMem, hBitmap);
284     StretchBlt(hDCMem, 0, 0, m_nCx, m_nCy, hDCDesktop, 0, 0, m_nCx, m_nCy, SRCCOPY);  //拷贝进内存DC;
285 
286 
287     m_dcGlobal.CreateCompatibleDC(pDCDesktop);                         //该DC用来写图片文件时使用;
288     m_hDCGlobal = m_dcGlobal.GetSafeHdc();                             //该HDC用来写图片文件时使用;
289 
290     CBitmap bitmap;
291     bitmap.CreateCompatibleBitmap(pDCDesktop, m_nCx, m_nCy);           //该图片用来贴图;
292     m_bitmapGlobal.CreateCompatibleBitmap(pDCDesktop, m_nCx, m_nCy);   //该图片用来风写图片文件时使用;
293 
294     m_dcGlobal.SelectObject(&bitmap);                                  // 该DC用来写图片文件时使用;   
295     m_dcGlobal.BitBlt(0, 0, m_nCx, m_nCy, pDCDesktop, 0, 0, SRCCOPY);  // 该DC用来写图片文件时使用;   
296 
297 
298     pDesktop->ReleaseDC(pDCDesktop);
299     pWnd->ReleaseDC(pDC);
300     DeleteDC(hDCMem);
301     DeleteObject(hBitmap); 
302 
303 
304 
305     return TRUE;  // return TRUE unless you set the focus to a control
306     // 异常: OCX 属性页应返回 FALSE
307 }
308 
309 

//HDC存为BMP 310 void CJietu::WriteBMPFile(HBITMAP hBitMap, LPTSTR filename, HDC hDC, int cx, int cy) 311 { 312 BITMAP bmp; 313 PBITMAPINFO pbmi; 314 WORD cClrBits; 315 HANDLE hf; // file handle 316 BITMAPFILEHEADER hdr; // bitmap file-header 317 PBITMAPINFOHEADER pbih; // bitmap info-header 318 LPBYTE lpBits; // memory pointer 319 DWORD dwTotal; // total count of bytes 320 DWORD cb; // incremental count of bytes 321 BYTE *hp; // byte pointer 322 DWORD dwTmp; 323 // create the bitmapinfo header information 324 if (!GetObject( hBitMap, sizeof(BITMAP), (LPTSTR)&bmp)) 325 { 326 return; 327 } 328 // Convert the color format to a count of bits. 329 cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 330 if (cClrBits == 1) 331 cClrBits = 1; 332 else if (cClrBits <= 4) 333 cClrBits = 4; 334 else if (cClrBits <= 8) 335 cClrBits = 8; 336 else if (cClrBits <= 16) 337 cClrBits = 16; 338 else if (cClrBits <= 24) 339 cClrBits = 24; 340 else cClrBits = 32; 341 // Allocate memory for the BITMAPINFO structure. 342 if (cClrBits != 24) 343 pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << cClrBits)); 344 else 345 pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); 346 // Initialize the fields in the BITMAPINFO structure. 347 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 348 pbmi->bmiHeader.biWidth = cx; //bmp.bmWidth; 349 pbmi->bmiHeader.biHeight = cy; //bmp.bmHeight; 350 pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 351 pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 352 if (cClrBits < 24) 353 pbmi->bmiHeader.biClrUsed = 1; // If the bitmap is not compressed, set the BI_RGB flag. 354 pbmi->bmiHeader.biCompression = BI_RGB; 355 // Compute the number of bytes in the array of color 356 // indices and store the result in biSizeImage. 357 pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8 * pbmi->bmiHeader.biHeight * cClrBits; 358 // Set biClrImportant to 0, indicating that all of the 359 // device colors are important. 360 pbmi->bmiHeader.biClrImportant = 0; 361 // now open file and save the data 362 pbih = (PBITMAPINFOHEADER) pbmi; 363 lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); 364 if (!lpBits) 365 { 366 return; 367 } 368 // Retrieve the color table (RGBQUAD array) and the bits 369 if (!GetDIBits(hDC, HBITMAP(hBitMap), 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS)) 370 { 371 return; 372 } 373 // Create the .BMP file. 374 hf = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, 375 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 376 (HANDLE) NULL); 377 if (hf == INVALID_HANDLE_VALUE) 378 { 379 return; 380 } 381 hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M" 382 // Compute the size of the entire file. 383 hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed 384 * sizeof(RGBQUAD) + pbih->biSizeImage); 385 hdr.bfReserved1 = 0; 386 hdr.bfReserved2 = 0; 387 // Compute the offset to the array of color indices. 388 hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 389 pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD); 390 // Copy the BITMAPFILEHEADER into the .BMP file. 391 if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL)) 392 { 393 return; 394 } 395 // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. 396 if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD), (LPDWORD) &dwTmp, ( NULL))) 397 { 398 return; 399 } 400 // Copy the array of color indices into the .BMP file. 401 dwTotal = cb = pbih->biSizeImage; 402 hp = lpBits; 403 if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) 404 { 405 return; 406 } 407 // Close the .BMP file. 408 if (!CloseHandle(hf)) 409 { 410 return; 411 } 412 // Free memory. 413 GlobalFree((HGLOBAL)lpBits); 414 }


//保存按钮
415 void CJietu::OnBnClickedButton1() 416 { 417 // TODO: 在此添加控件通知处理程序代码; 418 419 CDC dcSave; 420 dcSave.CreateCompatibleDC(&m_dcGlobal); 421 dcSave.SelectObject(&m_bitmapGlobal); 422 423 int x1 = m_pointStart.x; 424 int y1 = m_pointStart.y; 425 426 int x2 = m_pointEnd.x; 427 int y2 = m_pointEnd.y; 428 429 int width = abs(m_pointEnd.x - m_pointStart.x); 430 int height = abs(m_pointEnd.y - m_pointStart.y); 431 432 int xBegin = 0; 433 int yBegin = 0; 434 435 //考虑四种画框的不同情况,寻找矩形不同的左上角坐标; 436 if (x2 >= x1 && y2 <= y1) 437 { 438 xBegin = x1; 439 yBegin = y2; 440 } 441 else if (x2 >= x1 && y2 >= y1) 442 { 443 xBegin = x1; 444 yBegin = y1; 445 } 446 else if (x2 <= x1 && y2 >= y1) 447 { 448 xBegin = x2; 449 yBegin = y1; 450 } 451 else 452 { 453 xBegin = x2; 454 yBegin = y2; 455 } 456 457 //拷贝进dcSave必须从(0,0)开始存储,因为WriteBMPFile指定长宽写的时候就是从(0, 0)开始截取的长宽; 458 //由于m_hDCGlobal保存的是整个桌面的图片,所以要从指定的坐标开始拷贝; 459 StretchBlt(dcSave, 0, 0, width, height, m_hDCGlobal, xBegin, yBegin, width, height, SRCCOPY); 460 CTime time = CTime::GetCurrentTime(); 461 CString strTime; 462 strTime = time.Format("%Y-%m-%d %H%M%S"); 463 int len = strTime.GetLength(); 464 TCHAR *pFileName = new TCHAR[len + 1 + 4]; 465 lstrcpy(pFileName, strTime.GetBuffer(len)); 466 lstrcat(pFileName, _T(".bmp")); 467 468 WriteBMPFile((HBITMAP)m_bitmapGlobal.m_hObject, pFileName, dcSave, width, height); 469 delete [] pFileName; 470 strTime.ReleaseBuffer(len); 471 dcSave.DeleteDC(); 472 473 OnCancel(); 474 }

 

 

  

 

 

 

posted on 2013-02-06 10:45  崔好好  阅读(765)  评论(0编辑  收藏  举报

导航