반응형

Pillow 모듈을 사용해 큰 이미지에서 작은 부분을 찾을 수 있다. 예를 들어 아래 Target과 같이 작은 부분을 큰 Source에서 찾아야 하는 경우이다.


2018/12/02 - [Software/Python] - Pillow 이미지 서치(Image Search) 2

2019/07/08 - [Software/OpenCV] - Template Matching(Image Searching) - 부분 이미지 검색

2019/07/10 - [Software/OpenCV] - Template Matching(Image Searching) for multiple objects - 반복되는 이미지 모두 찾기

2019/07/12 - [Software/OpenCV] - Template Matching(Image Searching) with a mask for multiple objects - 마스크를 이용해 (배경이 다른) 반복되는 이미지 모두 찾기


Target:


Source:


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
from PIL import Image
from PIL import ImageDraw
from PIL import ImageChops
from PIL import ImageStat
import sys
 
source = Image.open("source.bmp")
sx, sy = source.size
target = Image.open("target.bmp")
tx, ty = target.size
 
print("Source size: ", source.size)
print("Target size: ", target.size)
 
trial = 0 # Image search 시도 횟수.
 
def Search(cx, cy):
    #for y in range(ty):
    #    for x in range(tx):
    #        if target.getpixel((x, y)) == source.getpixel((cx + x, cy + y)):
    #            continue
    #        else:
    #            return False
    #return True
 
    compare = source.crop((cx, cy, cx + tx, cy + ty)) # 소스에서 타겟으로 판단되는 위치의 이미지를 타겟 사이즈 만큼 잘라낸다.
    # Returns a rectangular region from this image. The box is a 4-tuple defining the left, upper, right, and lower pixel coordinate.
    print("Compare size: ", compare.size)
 
    diff = ImageChops.difference(compare, target) # 타겟과 타겟으로 판단되는 부분의 픽셀값 비교.
    stat = ImageStat.Stat(diff)
    global trial
    if stat.sum == [000]:
        print("Target found(checksum): ", stat.sum)
        return True
    else:
        trial += 1
        return False
 
draw = ImageDraw.Draw(source)    # Creates an object that can be used to draw in the given image.
 
for y in range(sy - ty):        # 소스의 처음부터 타겟 사이즈를 뺀 위치 까지 검색을 시작 한다.
    for x in range(sx - tx):    # 처음 (2 X 2)개 픽셀의 값이 같다면 Search()로 타겟 사이즈 전체를 다시 확인한다.
        if source.getpixel((x, y)) == target.getpixel((00)) and source.getpixel((x + 1, y)) == target.getpixel((10)) \
            and source.getpixel((x, y + 1)) == target.getpixel((01)) and source.getpixel((x + 1, y + 1)) == target.getpixel((11)):
            if Search(x, y) == True:
                print("Top left point: (%d, %d)" %(x, y))
                print("Center of targe point: (%d, %d)" %(x + target.width / 2, y + target.height / 2))
                print("Number of total wrong detection: ", trial)
                draw.rectangle((x, y, x + target.width, y + target.height), outline = (25500))
                # Draws a rectangle. 소스 이미지의 타겟 부분에 빨간 사각형을 그린다.
                source.show()
                sys.exit()
            else:
                print("At (%d, %d): Target not found" %(x, y))
                print("Wrong detection count: ", trial)
 
print("Image search failed.")
cs




결과: 리트리버의 앞발 쪽에서 Target을 찾았다.

반응형
Posted by J-sean
:
반응형

Python에서 windows API를 사용 할 수 있게 해 주는 모듈이다.

간단한 Desktop GUI 예제:

 

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
import win32api
import win32gui
import win32con
import win32ui
 
#hinstance = win32api.GetModuleHandle(None)
 
hWnd = win32gui.GetDesktopWindow()
# Retrieves a handle to the desktop window. The desktop window covers the entire screen.
# The desktop window is the area on top of which other windows are painted.
hdc = win32gui.GetDC(hWnd)
#win32gui.GetDC(None)
# A handle to the window whose DC is to be retrieved. If this value is NULL, GetDC
# retrieves the DC for the entire screen.
 
hMemDC = win32gui.CreateCompatibleDC(hdc)
 
hImage = win32gui.LoadImage(None, "cat.bmp", win32con.IMAGE_BITMAP, 00, win32con.LR_LOADFROMFILE | win32con.LR_CREATEDIBSECTION);
# Loads an icon, cursor, animated cursor, or bitmap
 
hOldBitmap = win32gui.SelectObject(hMemDC, hImage)
win32gui.BitBlt(hdc, 505050 + 40050 + 272, hMemDC, 00, win32con.SRCCOPY) # Image(400, 272) at (50, 50)
# The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle of pixels
# from the specified source device context into a destination device context.
 
win32gui.SelectObject(hMemDC, hOldBitmap)
win32gui.DeleteObject(hImage)
win32gui.DeleteDC(hMemDC)
win32gui.ReleaseDC(hWnd, hdc)
cs

 

결과

 

 

실행 방식에 따라 제대로 표시가 안되는 경우가 있다.

 

1) 스크립트파일 - 우클릭 - 연결 프로그램 - Python - 표시가 안되는 경우가 있다.

2) Console - 스크립트 파일 실행 - 잘 표시 된다.

 

반응형
Posted by J-sean
:
반응형

Python에서 windows API를 사용 할 수 있게 해 주는 모듈이다.


간단한 Desktop GUI 예제:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import win32api
import win32gui
import win32con
import win32ui
 
hWnd = win32gui.GetDesktopWindow()
# Retrieves a handle to the desktop window. The desktop window covers the entire screen.
# The desktop window is the area on top of which other windows are painted.
hdc = win32gui.GetDC(hWnd)
#win32gui.GetDC(None)
# A handle to the window whose DC is to be retrieved. If this value is NULL, GetDC
# retrieves the DC for the entire screen.
 
red = win32api.RGB(25500)
win32gui.SetPixel(hdc, 00, red)  # (0, 0)에 빨간 점 그리기
 
MyPen = win32gui.CreatePen(win32con.PS_SOLID, 5, win32api.RGB(0,0,255));
OldPen = win32gui.SelectObject(hdc, MyPen);
 
win32gui.Rectangle(hdc, 5050100100# (50, 50, 100, 100)에 파란 선으로 사각형 그리기
 
win32gui.SelectObject(hdc, OldPen);
win32gui.DeleteObject(MyPen);
 
# 폰트 만들기
font_spec = {'name':'Arial''height':42'weight':30}
font = win32ui.CreateFont(font_spec)
#lf = win32gui.LOGFONT()
#lf.lfFaceName = "Times New Roman"
#lf.lfHeight = 100
#lf.lfWeight = win32con.FW_NORMAL
#hf = win32gui.CreateFontIndirect(lf)
 
oldfont = win32gui.SelectObject(hdc, font.GetSafeHandle())
 
win32gui.SetTextColor(hdc, win32api.RGB(255,0,0))
win32gui.SetBkColor(hdc, win32api.RGB(255,255,0))
#win32gui.SetBkMode(hdc, win32con.TRANSPARENT)
# Desktop window DC로는 SetBKMode()가 잘 작동하지 않는다
 
text = 'Software Engineer'
rect = win32gui.GetClientRect(hWnd)
win32gui.DrawText(hdc, text, len(text), rect, win32con.DT_CENTER | win32con.DT_VCENTER
                  | win32con.DT_SINGLELINE | win32con.DT_WORDBREAK)
# 화면 가운데 문자열 출력
 
win32gui.SelectObject(hdc,oldfont)
win32gui.DeleteObject(font.GetSafeHandle())
 
win32gui.ReleaseDC(hWnd, hdc)
cs


반응형

'Python' 카테고리의 다른 글

Pillow 이미지 서치(Image Search) 1  (0) 2018.11.30
pywin32 Windows Extensions for Python 2  (0) 2018.11.27
Pillow 화면 변화 감지(Pixel Checksum) 2  (0) 2018.11.21
Pillow 화면 변화 감지(Pixel Checksum) 1  (0) 2018.11.20
PyMySQL  (2) 2018.11.19
Posted by J-sean
:

Python C API

C, C++ 2018. 11. 21. 15:52 |
반응형

가장 간단하게 Python을 C에 embed 시키는 방법은 Very High Level interface를 사용 하는 것이다. VHL interface는 어플리케이션과 직접적인 상관 없이 Python script를 실행하기 위한 것이다.

 

관련 문서

Python/C API Reference Manual

 

우선 Python C API 관련 Include, Library 디렉토리를 프로젝트에 추가한다.

C:\Users\UserName\AppData\Local\Programs\Python\PythonXXX\include

C:\Users\UserName\AppData\Local\Programs\Python\PythonXXX\libs

 

파이썬 공식 홈페이지에서 다운 받은 파이썬 인스톨러 패키지를 설치 했다면 Solution Configurations를 Release로 설정 한다. Debug 모드로 build 할 경우 pythonXX_d.lib를 찾을 수 없다는 에러가 발생한다. pythonXX_d.lib 파일을 생성하려면 파이썬 소스를 받아서 직접 컴파일해야 한다.

 

예제:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#pragma comment(lib, "python36.lib")
#include <Python.h>
 
int main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    // Decode a byte string from the locale encoding with the surrogateescape error handler:
    // undecodable bytes are decoded as characters in range U+DC80..U+DCFF. If a byte sequence
    // can be decoded as a surrogate character, escape the bytes using the surrogateescape error
    // handler instead of decoding them.
    // Return a pointer to a newly allocated wide character string, use PyMem_RawFree() to free
    // the memory. If size is not NULL, write the number of wide characters excluding the null
    // character into *size
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    // This function should be called before Py_Initialize() is called for the first time, if it
    // is called at all.It tells the interpreter the value of the argv[0] argument to the main()
    // function of the program(converted to wide characters).This is used by Py_GetPath() and some
    // other functions below to find the Python run - time libraries relative to the interpreter
    // executable.
 
    Py_Initialize();
    // Initialize the Python interpreter. In an application embedding Python, this should be called
    // before using any other Python/C API functions
    if (Py_IsInitialized())
    // Return true (nonzero) when the Python interpreter has been initialized, false (zero) if not.
    // After Py_FinalizeEx() is called, this returns false until Py_Initialize() is called again.
    {
        PyRun_SimpleString("print('Hello Python')");
        // This is a simplified interface to PyRun_SimpleStringFlags(), leaving the PyCompilerFlags*
        // argument set to NULL.
        PyRun_SimpleString("from time import time, ctime\n"
            "print('Today is', ctime(time()))\n");
        //PyRun_SimpleString("from time import time, ctime\nprint('Today is', ctime(time()))\n");
 
        if (Py_FinalizeEx() < 0)
        // Undo all initializations made by Py_Initialize() and subsequent use of Python/C API
        // functions, and destroy all sub-interpreters that were created and not yet destroyed
        // since the last call to Py_Initialize().
        {
            exit(120);
        }
        PyMem_RawFree(program);
        // Frees the memory block pointed to by p, which must have been returned by a previous call
        // to PyMem_RawMalloc(), PyMem_RawRealloc() or PyMem_RawCalloc().
        // Otherwise, or if PyMem_RawFree(p) has been called before, undefined behavior occurs.
        // If p is NULL, no operation is performed.
    }
 
    return 0;
}
cs

 

반응형
Posted by J-sean
:
반응형

'Pillow 화면 변화 감지(Pixel Checksum) 1'에서는 모든 픽셀의 값을 확인해서 좌표까지 알아내기 때문에 시간이 오래 걸린다.

ImageStat 모듈을 사용해 모든 픽셀을 확인하지 않고 전체적인 변화 여부만 감지하면 빠르게 확인 할 수 있다.


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
32
from PIL import Image
from PIL import ImageGrab
from PIL import ImageChops
from PIL import ImageStat
import time
 
def PixelCheck(x1, y1, x2, y2):
    im1 = ImageGrab.grab((x1, y1, x2, y2))
    # Take a snapshot of the screen. The pixels inside the bounding box are returned as an “RGB” image
    # on Windows or “RGBA” on macOS. If the bounding box is omitted, the entire screen is copied.
    while 1:
        time.sleep(0.1)
        im2 = ImageGrab.grab((x1, y1, x2, y2))
        im = ImageChops.difference(im1, im2)
        # Returns the absolute value of the pixel-by-pixel difference between the two images.
        # 마우스로 인한 변경은 반영 되지 않는다. 같은 이미지이면 difference()의 결과 이미지는 모든 픽셀이 0.
        stat = ImageStat.Stat(im)
        # Calculate statistics for the given image. If a mask is included, only the regions covered by
        # that mask are included in the statistics. You can also pass in a previously calculated histogram.
        if stat.sum != [000]: # Sum of all pixels for each band in the image.
            print("Change detected: sum[%s]: %s" %(im.getbands().__str__(), stat.sum.__str__()))
            # Returns a tuple containing the name of each band in this image. For example, getbands on
            # an RGB image returns (“R”, “G”, “B”).
            return
 
x1, y1, x2, y2 = map(int, input("Enter x1, y1, x2, y2 values: ").split()) # 추적할 영역의 좌상단, 우하단 좌표
PixelCheck(x1, y1, x2, y2)
# x1, y1, x2, y2 = input("Enter x1, y1, x2, y2 values: ").split()
# x1 = int(x1)
# y1 = int(y1)
# x2 = int(x2)
# y2 = int(y2)
cs


반응형

'Python' 카테고리의 다른 글

Pillow 이미지 서치(Image Search) 1  (0) 2018.11.30
pywin32 Windows Extensions for Python 2  (0) 2018.11.27
pywin32 Windows Extensions for Python 1  (0) 2018.11.27
Pillow 화면 변화 감지(Pixel Checksum) 1  (0) 2018.11.20
PyMySQL  (2) 2018.11.19
Posted by J-sean
:
반응형

Pillow 라이브러리를 사용해서 바탕화면의 변화를 추적할 영역을 지정하고 영역에 변화가 있을때 변화된 영역의 좌상단 좌표를 반환 한다.

지정된 영역의 모든 pixel을 확인하기 때문에 넓은 영역을 지정할 수록 시간이 오래 걸린다.


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
from PIL import Image
from PIL import ImageGrab
from PIL import ImageChops
import time
 
def PixelCheck(x1, y1, x2, y2):
    im1 = ImageGrab.grab((x1, y1, x2, y2))
    # Take a snapshot of the screen. The pixels inside the bounding box are returned as an “RGB” image
    # on Windows or “RGBA” on macOS. If the bounding box is omitted, the entire screen is copied.
    while 1:
        time.sleep(0.1)
        im2 = ImageGrab.grab((x1, y1, x2, y2))
        im = ImageChops.difference(im1, im2)
        # Returns the absolute value of the pixel-by-pixel difference between the two images.
        # 마우스로 인한 변경은 반영 되지 않는다. 같은 이미지이면 difference()의 결과 이미지는 모든 픽셀이 0.
        for y in range(im.height):
            for x in range(im.width):
                if im.getpixel((x, y)) != (000): # Returns the pixel value at a given position.
                    return x, y
 
x1, y1, x2, y2 = map(int, input("Enter x1, y1, x2, y2 values: ").split())
# x1, y1, x2, y2 = input("Enter x1, y1, x2, y2 values: ").split()
# x1 = int(x1)
# y1 = int(y1)
# x2 = int(x2)
# y2 = int(y2)
 
coord = PixelCheck(x1, y1, x2, y2) # 추적할 영역의 좌상단, 우하단 좌표
print(x1 + coord[0], y1 + coord[1]) # 추적 영역 중 변화된 영역의 좌상단 좌표(스크린 기준)
cs


PixelAccess class 를 사용해 PIL.Image data를 pixel level 에서 읽어 판단하기. (쓰기도 가능)

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
32
33
34
35
from PIL import Image
from PIL import ImageGrab
from PIL import ImageChops
import time
 
def PixelCheck(x1, y1, x2, y2):
    im1 = ImageGrab.grab((x1, y1, x2, y2))
    # Take a snapshot of the screen. The pixels inside the bounding box are returned as an “RGB” image
    # on Windows or “RGBA” on macOS. If the bounding box is omitted, the entire screen is copied.
    while 1:
        time.sleep(0.1)
        im2 = ImageGrab.grab((x1, y1, x2, y2))
        im = ImageChops.difference(im1, im2)
        # Returns the absolute value of the pixel-by-pixel difference between the two images.
        # 마우스로 인한 변경은 반영 되지 않는다. 같은 이미지이면 difference()의 결과 이미지는 모든 픽셀이 0.
        px = im.load()
        # Allocates storage for the image and loads the pixel data. In normal cases, you don’t need to
        # call this method, since the Image class automatically loads an opened image when it is accessed
        # for the first time.
        for y in range(im.height):
            for x in range(im.width):
                if px[x, y] != (000):
                    return x, y
        # Accessing individual pixels is fairly slow. If you are looping over all of the pixels in an image,
        # there is likely a faster way using other parts of the Pillow API.
 
x1, y1, x2, y2 = map(int, input("Enter x1, y1, x2, y2 values: ").split())
# x1, y1, x2, y2 = input("Enter x1, y1, x2, y2 values: ").split()
# x1 = int(x1)
# y1 = int(y1)
# x2 = int(x2)
# y2 = int(y2)
 
coord = PixelCheck(x1, y1, x2, y2) # 추적할 영역의 좌상단, 우하단 좌표
print(x1 + coord[0], y1 + coord[1]) # 추적 영역 중 변화된 영역의 좌상단 좌표(스크린 기준)
cs


반응형

'Python' 카테고리의 다른 글

Pillow 이미지 서치(Image Search) 1  (0) 2018.11.30
pywin32 Windows Extensions for Python 2  (0) 2018.11.27
pywin32 Windows Extensions for Python 1  (0) 2018.11.27
Pillow 화면 변화 감지(Pixel Checksum) 2  (0) 2018.11.21
PyMySQL  (2) 2018.11.19
Posted by J-sean
: