반응형

유튜브를 시청하다 보면 갑자기 튀어나오는 짜증나는 광고.


아무리 한예슬이 나온다고 해도 어쩔 수 없다. 광고는 짜증난다.


'광고 건너뛰기' 버튼이 나올때 까지 기다렸다 클릭 해야만 다시 시청하던 영상으로 돌아 갈 수 있다. 파이썬 으로 '광고 건너뛰기' 버튼을 자동으로 클릭하는 프로그램을 만들어 보자.


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
import pyautogui
import datetime
import time
 
size = pyautogui.size()  
print('Screen Size: {0}'.format(size))
 
while True:
    try :
        nowTime = datetime.datetime.now()
        location = pyautogui.locateCenterOnScreen('adskip.png', region = (1200750300100), confidence = 0.7)
        # region = (left, top, width, height)
        # You need to have OpenCV installed for the confidence keyword to work.
 
        if location == None:            
            print("[{0}] Ad not found. (Press 'Ctrl + C' to quit)".format(nowTime.strftime('%H:%M:%S')))
            time.sleep(2.0)
 
            continue
 
        print('[{0}] Ad found at {1}'.format(nowTime.strftime('%H:%M:%S'), location))
        pyautogui.moveTo(location[0], location[1], 1)
        pyautogui.click(button = 'left')
        time.sleep(5.0)
    
    except KeyboardInterrupt :
        print("Thank You.")
        break


Python Source Code



'광고 건너뛰기' 버튼을 찾기 위해 이 그림을 adskip.png로 저장 한다.


실행 로그


영상으로 확인 하자.


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

Python comes preinstalled on most Linux distributions and is available as a package on all others. However, there are certain features you might want to use that are not available on your distro’s package. You can easily compile the latest version of Python from the source.


대부분의 리눅스에는 파이썬이 포함되어 있어 바로 사용할 수 있지만 최신 버전의 파이썬 소스를 직접 컴파일해 사용할 수 도 있다.


파이썬 홈페이지에서 소스 파일 링크 주소를 확인 한다.


wget으로 소스코드를 다운 받는다.


다운 받은 소스 코드 확인.


--enable-optimizations 옵션과 함께 configure를 실행 한다.


make가 없다면 설치 한다.



make로 컴파일 한다. 지정된 디렉토리에 설치 하고 싶다면 make 실행 후 make altinstall 까지 진행 한다.


Warning: make install can overwrite or masquerade the python3 binary. make altinstall is therefore recommended instead of make install since it only installs exec_prefix/bin/pythonversion.


exec_prefix (${exec_prefix}) is installation-dependent and should be interpreted as for GNU software. For example, on most Linux systems, the default is /usr.


./python을 실행하면 컴파일된 파이썬이 실행 된다.


간단히 python명령어로 실행하기 위해 /usr/bin에 소프트 링크를 만들어 준다.


파이썬 홈페이지에서 다운 받았던 압축 파일은 삭제 한다.


dnf로 최신 버전 파이썬을 간단히 설치 할 수 도 있다.



설치가 완료되면 파이썬[버전] 형식으로 실행 할 수 있다.


Python package installer인 pip도 설치 한다. 


pip3 --version 명령으로 pip버전을 확인할 수 있다.


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

Visual Studio 설치 시 'Python 개발' 항목을 선택 하면 Python 언어 지원, Python miniconda등 여러 가지 프로그램이 함께 설치 된다. 다른 응용 프로그램 설치 시 또 다른 버전의 Python이 설치 되기도 하고 업데이트 하기 위해 Python 홈페이지에서 받은 최신 버전 Python을 설치 했다면 최신 버전의 또 다른 Python이 컴퓨터에 설치된다.


Visual Studio에서 컴퓨터에 설치된 여러가지 Python 중 원하는 버전을 선택해 사용할 수 있다.


Python 프로젝트를 만들고 Solution Explorer - Python Environments 마우스 우클릭 - Add Environments... 를 선택 한다.


Existing environment - Environment - 원하는 버전의 Python을 선택 한다. (3.8)


다시 Solution Explorer에서 확인해 보면 원하는 Python이 선택되어 있다. (3.8)



Visual Studio 설치 시 'Python 개발' 항목을 선택하면 'Python 언어 지원'외 특정 버전의 Python이 몇 가지 항목과 함께 설치 된다.


특정 버전의 Python과 기타 항목을 모두 선택 해제 한다.


Python 프로젝트를 만들면 따로 설치한 최신 버전의 Python으로 환경이 구성 된다.


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

SQLite는 별도의 서버 없이 디스크 기반으로 SQL 쿼리를 지원하는 가벼운 C 라이브러리 데이터베이스 이다.


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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import sqlite3
 
dbpath = "fruit.db"
conn = sqlite3.connect(dbpath)
# Opens a connection to the SQLite database file database.
# By default returns a Connection object, unless a custom factory
# is given. You can use ":memory:" to open a database connection to 
# a database that resides in RAM instead of on disk.
cur = conn.cursor()
# The cursor method accepts a single optional parameter factory.
# If supplied, this must be a callable returning an instance of
# Cursor or its subclasses.
 
cur.executescript("""
drop table if exists items;
create table items(
    item_id integer primary key,
    name text unique,
    price integer
);
insert into items(name, price) values("Apple", 800);
insert into items(name, price) values("Orange", 700);
insert into items(name, price) values("Banana", 430);
""")
# This is a nonstandard convenience method for executing
# multiple SQL statements at once. It issues a COMMIT statement
# first, then executes the SQL script it gets as a parameter.
 
conn.commit()
# This method commits the current transaction. If you don’t call
# this method, anything you did since the last call to commit()
# is not visible from other database connections. If you wonder
# why you don’t see the data you’ve written to the database, please
# check you didn’t forget to call this method.
 
cur.execute("select * from items")
# This is a nonstandard shortcut that creates a cursor object by
# calling the cursor() method, calls the cursor’s execute() method
# with the parameters given, and returns the cursor.
item_list = cur.fetchall()
# Fetches all (remaining) rows of a query result, returning a list.
# Note that the cursor’s arraysize attribute can affect the performance
# of this operation. An empty list is returned when no rows are available.
for it in item_list:
    print(it)
 
print()
 
cur.execute("insert into items(name, price) values('Grape', 500)")
conn.commit()
 
cur.execute("select item_id, name, price from items")
item_list = cur.fetchall()
for it in item_list:
    print(it)
 
print()
 
cur.execute("insert into items(name, price) values(?, ?)", ("Strawberry"800))
#conn.commit() 67라인에서 commit()을 호출 하므로 굳이 여기서 할 필요는 없다.
 
data = [("Mango"250), ("Kiwi"740), ("Peach"650)]
cur.executemany("insert into items(name, price) values(?, ?)", data)
# Executes an SQL command against all parameter sequences or mappings found in the
# sequence seq_of_parameters.
conn.commit()
 
cur.execute("select item_id, name, price from items")
item_list = cur.fetchall()
for it in item_list:
    print(it)
 
print()
 
price_range = (600700)
cur.execute("select * from items where name = 'Kiwi' or (price >= ? and price <= ?)",
            price_range)
item_list = cur.fetchall()
for it in item_list:
    print("Name: ", it[1], ", Price: ", it[2])
 
for it in item_list:
    print("ID: %s, Name: %s, Price: %s" %it) # it 자체(튜플)를 전달해도 된다.
 
print("\nStrawberry를 Watermelon으로 변경, Orange 삭제")
 
cur.execute("update items set name = 'Watermelon', price = 1500 where name = 'Strawberry'")
cur.execute("delete from items where name = 'Orange'")
cur.execute("select * from items")
conn.commit()
 
item_list = cur.fetchall()
for it in item_list:
    print(it)
 
cur.close()
conn.close()
cs




fruit.db 파일이 생성 된다.



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

아래와 같은 도로 이미지에서 차선 부분만 감지 한다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from PIL import Image
from PIL import ImageFilter
 
source = Image.open("road.jpg")
result = Image.new("RGB", source.size)
# Creates a new image with the given mode and size.
sx, sy = source.size
horizon = 550 # 550픽셀 아래에 도로가 있다고 가정.
 
for y in range(horizon, sy):
    for x in range(sx):
        if min(source.getpixel((x, y))) > 0xf0:
            result.putpixel((x, y), (0xff0xff0xff))
            # RGB값 중 최소값이 0xf0이상이면 흰색으로 변경
 
result = result.filter(ImageFilter.FIND_EDGES)
#result = result.filter(ImageFilter.BoxBlur(1))
# Filters this image using the given filter.
result.save("result.jpg")
# Saves this image under the given filename.
result.show()
cs


결과:

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

'Pillow 이미지 서치(Image search) 1' 은 target과 source의 모든 픽셀이 정확히 일치하는 경우만 True로 판단 하기 때문에 PNG나 BMP같은 무손실 압축 그래픽 파일에만 적용 가능하다. JPEG같은 손실 압축 그래픽 파일은 target과 source의 오차를 감안해야 한다.

 

2018/11/30 - [Software/Python] - Pillow 이미지 서치(Image Search) 1

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: 93 X 47

 

Source: 600 X 600

 

강아지의 앞발에 위치한 타겟 위치를 찾아 보자.

 

Tolerance: 30

Step: 2

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
59
60
61
62
63
from PIL import Image
from PIL import ImageDraw
from PIL import ImageChops
from PIL import ImageStat
import sys
import time
 
source = Image.open("source.jpg")
sx, sy = source.size
target = Image.open("target.jpg")
tx, ty = target.size
tolerance = 30 # 오차 범위는 30 정도면 적당한거 같다.
step = 2 # 모든 픽셀을 검사하면 너무 오랜 시간이 걸린다. 한 개 건너 한 개 픽셀만 검사.
 
print("Source size: ", source.size)
print("Target size: ", target.size)
 
trial = 0 # Image search 시도 횟수.
 
def Search(cx, cy, tolerance):
    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 max(max(stat.extrema[0]), max(stat.extrema[1]), max(stat.extrema[2])) <= tolerance:
        print("Target found(Min, max): ", stat.extrema)
        return True
    else:
        trial += 1
        return False
 
draw = ImageDraw.Draw(source)    # Creates an object that can be used to draw in the given image.
start = time.time()
 
for y in range(sy - ty):                # 소스의 처음부터 타겟 사이즈를 뺀 위치 까지 전체 검색을 시작 한다.
    for x in range(0, sx - tx, step):    # 처음 (10 X 10)개 픽셀의 값이 비슷 하다면 Search()로 타겟 사이즈 전체를 다시 확인한다.
        compare = source.crop((x, y, x + 10, y + 10))
        partial_target = target.crop((001010))
        diff = ImageChops.difference(compare, partial_target) # 각 픽셀값 차의 절대값이 반환 된다.
        # Returns the absolute value of the pixel-by-pixel difference between the two images.
        stat = ImageStat.Stat(diff)
 
        if max(max(stat.extrema[0]), max(stat.extrema[1]), max(stat.extrema[2])) < tolerance:
            if Search(x, y, tolerance) == 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. 소스 이미지의 타겟 부분에 빨간 사각형을 그린다.
                end = time.time()
                print("Seraching time: ", end - start)
                source.show()
                sys.exit()
            else:
                print("At (%d, %d): Target not found" %(x, y))
                print("Wrong detection count: ", trial)
 
end = time.time()
print("Image search failed.")
print("Seraching time: ", end - start)
 
 

 

소스를 입력하고 빌드한다.

 

 

결과

 

123번 잘못된 지점을 검색했고 (232, 497)위치의 Target을 찾는데 총 15.66초가 걸렸다.

JPEG파일의 손실 압축 때문에 Target과 Source의 픽셀이 최대 RGB(16, 9, 15)만큼 차이가 발생 했다.

Target을 찾지 못한다면 Step과 Tolerance 값을 적당히 수정해야 한다.

 

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

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
: