윗글을 읽고 오시면 이해가 빠릅니다.
결과 영상
전의 파이썬과 비교했을 때, 확실히 검출해네는 속도가 빨라졌다! 심지어 C++은 의도적으로 딜레이를 30ms정도 준 상태인데도 말이다.
확실히 이런 실시간 싱크 맟추는 것이 중요하다면, C++이 강력한 것 같다. 하지만 C++로 코딩하기는 참 너무 귀찮다.. 해줄게 너무 많다! 그래도 속도만큼은 진짜 탁월한 것 같다.
C++ 소스
화면 녹화 부분 참고 코드 출처 : github.com/sturkmen72/opencv_samples/blob/master/Screen-Capturing.cpp
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <Windows.h>
#include <iostream>
using namespace std;
using namespace cv;
class hwnd2Mat
{
public:
hwnd2Mat(HWND hwindow, float scale = 1);
virtual ~hwnd2Mat();
virtual void read();
Mat image;
private:
HWND hwnd;
HDC hwindowDC, hwindowCompatibleDC;
int height, width, srcheight, srcwidth;
HBITMAP hbwindow;
BITMAPINFOHEADER bi;
};
hwnd2Mat::hwnd2Mat(HWND hwindow, float scale)
{
hwnd = hwindow;
hwindowDC = GetDC(hwnd);
hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);
SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);
RECT windowsize; // get the height and width of the screen
GetClientRect(hwnd, &windowsize);
srcheight = 680;
srcwidth = 550;
height = (int)(srcheight * scale);
width = (int)(srcwidth * scale);
image.create(height, width, CV_8UC4);
// create a bitmap
hbwindow = CreateCompatibleBitmap(hwindowDC, width, height);
bi.biSize = sizeof(BITMAPINFOHEADER); //http://msdn.microsoft.com/en-us/library/windows/window/dd183402%28v=vs.85%29.aspx
bi.biWidth = width;
bi.biHeight = -height; //this is the line that makes it draw upside down or not
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
// use the previously created device context with the bitmap
SelectObject(hwindowCompatibleDC, hbwindow);
read();
};
void hwnd2Mat::read()
{
// copy from the window device context to the bitmap device context
StretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, 1, 180, srcwidth, srcheight, SRCCOPY); //change SRCCOPY to NOTSRCCOPY for wacky colors !
GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, image.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS); //copy from hwindowCompatibleDC to hbwindow
};
hwnd2Mat::~hwnd2Mat()
{
// avoid memory leak
DeleteObject(hbwindow);
DeleteDC(hwindowCompatibleDC);
ReleaseDC(hwnd, hwindowDC);
};
void make_binary(const Mat& img_src, Mat& img_binary)
{
int thresh = 10;
int maxval = 255;
Mat img_gray;
cvtColor(img_src, img_gray, COLOR_BGR2GRAY);
threshold(img_gray, img_binary, thresh, maxval, THRESH_BINARY_INV);
}
void click_node(int cx, int cy)
{
INPUT input;
ZeroMemory(&input, sizeof(INPUT));
input.type = INPUT_MOUSE;
// 마우스 노드 좌표로 이동
double screenRes_width = ::GetSystemMetrics(SM_CXSCREEN) - 2;
double screenRes_height = ::GetSystemMetrics(SM_CYSCREEN) - 300;
float dx = cx * (65535.0f / screenRes_width);
float dy = cy * (65535.0f / screenRes_height);
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
input.mi.dx = LONG(dx);
input.mi.dy = LONG(dy);
SendInput(1, &input, sizeof(INPUT));
// 마우스 왼쪽 버튼 클릭 이벤트
input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1, &input, sizeof(INPUT));
input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, &input, sizeof(INPUT));
Sleep(35);
}
void detect_contours(Mat& img_src, Mat& img_binary)
{
vector<vector<Point>> contours;
findContours(img_binary, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
if (!contours.empty())
{
vector<Point2f> approx;
for (size_t i = 0; i < contours.size(); i++)
{
// contour 근사
approxPolyDP(Mat(contours[i]), approx,
arcLength(Mat(contours[i]), true)*0.01, true);
int size = approx.size();
// 사각형일 경우
if (size == 4)
{
line(img_src, approx[0], approx[approx.size() - 1], Scalar(0, 255, 0), 3);
// line
for (size_t j = 0; j < size -1; j++)
{
line(img_src, approx[j], approx[j + 1], Scalar(0, 255, 0), 3);
}
// 무게중심에 원 그리기
Moments mu;
mu = moments(contours[i]);
int cx = static_cast<float>(mu.m10 / (mu.m00 + 1e-5));
int cy = static_cast<float>(mu.m01 / (mu.m00 + 1e-5));
cout << "노드 좌표 : " << cx << ' ' << cy << '\n';
circle(img_src, Point(cx, cy), 15, Scalar(0, 255, 255), -1);
// 원 클릭
if (cy > 90)
{
click_node(cx, cy);
}
}
}
}
}
int main()
{
Mat bgrImg;
Mat img_binary;
hwnd2Mat capDesktop(GetDesktopWindow());
int tmp;
cout << "자동 클릭 시스템을 구동하시겠습니까? (1)";
cin >> tmp;
while (tmp)
{
capDesktop.read();
cvtColor(capDesktop.image, bgrImg, COLOR_BGRA2BGR);
make_binary(bgrImg, img_binary);
detect_contours(bgrImg, img_binary);
imshow("cap win", bgrImg);
int key = waitKey(5);
if (key == 27)
break;
}
}
'openCV' 카테고리의 다른 글
[파이썬 openCV 도형 인식] 게임 매직타일 매크로 [1] (0) | 2021.01.27 |
---|---|
[Python openCV] 유로 트럭2 반자율주행 (1) | 2021.01.25 |
[파이썬 openCV] - 트랙바로 임계값 조정하기 (0) | 2021.01.21 |
[파이썬 openCV] - 픽셀, 컬러와 흑백 이미지 (0) | 2021.01.20 |
[파이썬 openCV] - 이미지 데이터 공유 & 복사 (0) | 2021.01.19 |