【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 }

 

 

  

 

 

 

你可能感兴趣的:(opencv)