티스토리 뷰

210727

자 저번 강의에서는 앱플레이어를 찾아서 캡쳐하는 것 까지 진행했었습니다.

 

이번에는 원하는 이미지를 찾아서 클릭하는 것 까지 해보도록 하겠습니다.

먼저 프로젝트 폴더 bin>Debug 폴더에서 "img" 란 폴더를 하나 만들어주세요.

 

자 그리고 img 폴더에 찾을 이미지를 저장해주십시다.

 

저는 듀랑고에 돌맹이를 찾고 클릭할 예정입니다.

윈도우 기본 앱인 캡쳐 도구를 이용해서 간단하게 원하는 이미지를 아래와 같이 저장해주세요.

 

캡처도구에서

1. 새로만들기 클릭

2. 돌맹이 모양 캡쳐하기.

3. "stone" 이름으로 저장하기

 

아래와 같이 찾을 돌맹이를 하나 저장해놨습니다.

 

!!!중요!!!!

캡쳐 후에는 앱플레이어 사이즈를 변경하지 말아주세요~! 이 다음 강의때 사이즈를 변경해도 동작하는 부분 진행하도록하겠습니다.

 

위에 저장한 stone 이미지를 프로젝트 상에 불러와 보겠습니다.

 

1
2
3
4
5
6
7
8
        String AppPlayerName = "[MOMO]앱플레이어";
        Bitmap Stone_Img = null;
 
        public Form1()
        {
            InitializeComponent();
            Stone_Img = new Bitmap(@"img\stone.PNG");
        }
cs

 

2번째 줄 처럼 비트맵 을 하나 선언해주세요.

7번째 줄 처럼 img폴더에 stone 이미지를 불러와 주세요.

 

이제 플레이어 게임화면에 해당 stone 이미지를 찾아보겠습니다.

searchIMG 함수를 만들어봅시다. 해당 함수는 비트맵 이미지 두개를 받습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
        //searchIMG에 스크린 이미지와 찾을 이미지를 넣어줄거에요
        public void searchIMG(Bitmap screen_img, Bitmap find_img)
        {
            //스크린 이미지 선언
            using (Mat ScreenMat = OpenCvSharp.Extensions.BitmapConverter.ToMat(screen_img))
            //찾을 이미지 선언
            using (Mat FindMat = OpenCvSharp.Extensions.BitmapConverter.ToMat(find_img))
            //스크린 이미지에서 FindMat 이미지를 찾아라
            using (Mat res = ScreenMat.MatchTemplate(FindMat, TemplateMatchModes.CCoeffNormed))
            {
                //찾은 이미지의 유사도를 담을 더블형 최대 최소 값을 선언합니다.
                double minval, maxval = 0;
                //찾은 이미지의 위치를 담을 포인트형을 선업합니다.
                OpenCvSharp.Point minloc, maxloc;
                //찾은 이미지의 유사도 및 위치 값을 받습니다. 
                Cv2.MinMaxLoc(res, out minval, out maxval, out minloc, out maxloc);
                Debug.WriteLine("찾은 이미지의 유사도 : " + maxval);
            }
        }
cs

 

코드설명은 위 주석 참고 부탁드릴게요.

 

자 maxval 값이 0.7~1 사이 값이 나온다면 유사한 이미지를 찾았다고 생각하면됩니다.

찾은 이미지를 클릭해보도록 합시다.

 

우리는 찾은이미지 위치를 maxloc 변수에 저장하고 있습니다.

마우스 이벤트만 발생시키면 됩니다.

 

마우스 이벤트를 발생시키기 위해서 아래 9.10,12,13,15,16 줄을 추가하였습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public partial class Form1 : Form
    {
        [System.Runtime.InteropServices.DllImport("User32", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
 
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        internal static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);
 
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, IntPtr lParam);
 
        [System.Runtime.InteropServices.DllImport("User32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr Parent, IntPtr Child, string lpszClass, string lpszWindows);
 
        public const int WM_LBUTTONDOWN = 0x201;
        public const int WM_LBUTTONUP = 0x202;
cs

 

아래 함수가 마우스 이벤트를 발생시키는 함수입니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        //x,y 값을 전달해주면 클릭이벤트를 발생합니다.
        public void InClick(int x, int y)
        {
            //클릭이벤트를 발생시킬 플레이어를 찾습니다.
            IntPtr findwindow = FindWindow(null, AppPlayerName);
            if (findwindow != IntPtr.Zero)
            {
                //플레이어를 찾았을 경우 클릭이벤트를 발생시킬 핸들을 가져옵니다.
                IntPtr hwnd_child = FindWindowEx(findwindow, IntPtr.Zero, "RenderWindow""TheRender");
                IntPtr lparam = new IntPtr(x | (y << 16));
 
                //플레이어 핸들에 클릭 이벤트를 전달합니다.
                SendMessage(hwnd_child, WM_LBUTTONDOWN, 1, lparam);
                SendMessage(hwnd_child, WM_LBUTTONUP, 0, lparam);
            }
        }
cs

 

 

button1_Click 함수에 stone 이미지를 찾는 함수를 선언해주세요. 아래코드 30번째 줄입니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        private void button1_Click(object sender, EventArgs e)
        {
            IntPtr findwindow = FindWindow(null, AppPlayerName);
            if (findwindow != IntPtr.Zero)
            {
                //플레이어를 찾았을 경우
                Debug.WriteLine("앱플레이어 찾았습니다.");
 
                //찾은 플레이어를 바탕으로 Graphics 정보를 가져옵니다.
                Graphics Graphicsdata = Graphics.FromHwnd(findwindow);
 
                //찾은 플레이어 창 크기 및 위치를 가져옵니다. 
                Rectangle rect = Rectangle.Round(Graphicsdata.VisibleClipBounds);
 
                //플레이어 창 크기 만큼의 비트맵을 선언해줍니다.
                Bitmap bmp = new Bitmap(rect.Width, rect.Height);
 
                //비트맵을 바탕으로 그래픽스 함수로 선언해줍니다.
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    //찾은 플레이어의 크기만큼 화면을 캡쳐합니다.
                    IntPtr hdc = g.GetHdc();
                    PrintWindow(findwindow, hdc, 0x2);
                    g.ReleaseHdc(hdc);
                }
 
                // pictureBox1 이미지를 표시해줍니다.
                pictureBox1.Image = bmp;
 
                searchIMG(bmp, Stone_Img);
            }
cs

 

이제 다시 searchIMG 함수로 돌아와 maxval 0.8 이상일 경우 이미지를 찾았다로 판단하여 클릭해보도록 하겠습니다.

아래 코드 20~23 번 줄 추가했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
        //searchIMG에 스크린 이미지와 찾을 이미지를 넣어줄거에요
        public void searchIMG(Bitmap screen_img, Bitmap find_img)
        {
            //스크린 이미지 선언
            using (Mat ScreenMat = OpenCvSharp.Extensions.BitmapConverter.ToMat(screen_img))
            //찾을 이미지 선언
            using (Mat FindMat = OpenCvSharp.Extensions.BitmapConverter.ToMat(find_img))
            //스크린 이미지에서 FindMat 이미지를 찾아라
            using (Mat res = ScreenMat.MatchTemplate(FindMat, TemplateMatchModes.CCoeffNormed))
            {
                //찾은 이미지의 유사도를 담을 더블형 최대 최소 값을 선언합니다.
                double minval, maxval = 0;
                //찾은 이미지의 위치를 담을 포인트형을 선업합니다.
                OpenCvSharp.Point minloc, maxloc;
                //찾은 이미지의 유사도 및 위치 값을 받습니다. 
                Cv2.MinMaxLoc(res, out minval, out maxval, out minloc, out maxloc);
                Debug.WriteLine("찾은 이미지의 유사도 : " + maxval);
 
                //이미지를 찾았을 경우 클릭이벤트를 발생!!
                if(maxval >= 0.8)
                {
                    InClick(maxloc.X, maxloc.Y);
                }
            }
        }
cs

 

이제 이미지를 찾고 클릭까지 완료되었습니다.

실제 실행되는 모습을 보도록 하죠!

 

 

#

이 블로그가 도움이 되었다면, 후원을 부탁드립니다
http://yc0345.tistory.com/218

댓글