#coding:utf-8
"""
Author's Twitter: TonyMooori
基本,自分のメモ用です.
Win10のmspaint.exe上で画像を描画するプログラムでうs
同一ディレクトリにペイントのボタンの画像が無いと動かないので
試しにやってみようとか思ってもだいぶ頑張らないと動きません.ゴメンナサイ.
ただreduce_color関数だけは
画像の色をMiniBatchKMeansで減色してるので,そこだけは多少使えるかと思います
"""
import numpy as np
import cv2
import time
import pyautogui as pa
def set_size(src):
# 対角線の長さが200になるようなスケールを計算
h,w,c = src.shape
scale = 200.0 / np.sqrt( h**2 + w**2 )
h = int(h*scale)
w = int(w*scale)
# リサイズ
return cv2.resize(src,(w,h))
def reduce_color(src):
# k-meansでクラスタリング
# -> 代表値に置き換えることで自然?な減色をする
from sklearn.cluster import MiniBatchKMeans
X = src.reshape(src.shape[0]*src.shape[1],3)
clf = MiniBatchKMeans(16)
y = clf.fit_predict(X)
return clf.cluster_centers_[y].reshape(src.shape).astype(np.uint8)
def to_num(c):
# uint8 x 3 の色データを int 型にする
return c[:,:,0] * ( 2 ** 16 ) + c[:,:,1] * ( 2 ** 8 ) + c[:,:,2]
def to_col(c):
# int型のデータを分割してr,g,bに分ける
r = c % 256
g = ( c//( 2 ** 8 ) ) % 256
b = ( c//( 2 ** 16 ) ) % 256
return np.array([r,g,b])
def img_click(path):
# 指定の画像の場所をクリックする
while True:
pos = pa.locateCenterOnScreen(path)
if pos != None:
pa.click(pos)
return
def change_color(color):
# ペイントの各ボタンを順番にクリックする
r = color[0]
g = color[1]
b = color[2]
# 真っ白とか描画する必要ない
if r > 250 and g > 250 and b > 250:
return True
# ボタンを順にクリックしてく
img_click("color_edit.png")
pos = None
while pos == None:
pos = pa.locateCenterOnScreen("red.png")
pa.click( (pos[0]+30,pos[1]) )
pa.hotkey('ctrl', 'a')
pa.typewrite(str(r))
pa.click( (pos[0]+30,pos[1]+27) )
pa.hotkey('ctrl', 'a')
pa.typewrite(str(g))
pa.click( (pos[0]+30,pos[1]+60) )
pa.hotkey('ctrl', 'a')
pa.typewrite(str(b))
img_click("ok.png")
return False
def draw_img(src):
# 画像を描画する
# 色を抽出してピクセル数が大きい順にソート
# 多分もっとスマートな書き方がある
img = to_num(src)
color_list = np.unique(img)
color_num = np.zeros(len(color_list))
for i in range(len(color_list)):
col = color_list[i]
color_num[i] = len(np.where( img == col )[0])
arg_list = np.argsort(color_num)[::-1]
color_list = color_list[arg_list]
# 高さ・幅を抽出
h,w = img.shape
# 5秒待って
time.sleep(5)
# 初期のマウスの座標を取得
x0 = pa.position()[0]
y0 = pa.position()[1]
# ピクセル間の距離
side = 5
# Python夢の重ループ!!!!
# 色を順番に描画してくよ!!
for col in color_list:
# 色をセットする
if change_color(to_col(col)):
continue
# ドラッグ中ならTrueになるフラグ
isDragging = False
for j in range(h):
for i in range(w):
# 現在の座標取得
x = x0 + side * i
y = y0 + side * j
if col == img[j,i]:
# ドラッグスタート
if isDragging == False:
pa.moveTo(x,y)
pa.mouseDown()
isDragging = True
elif isDragging == True:
# ドラッグ終了
pa.moveTo(x,y)
pa.mouseUp()
isDragging = False
# 一行書いたらmouseUp
pa.mouseUp()
if __name__=="__main__":
pa.PAUSE = 0.000001
src = cv2.imread("miku.jpg")
src = set_size(src) # 大きさ調節
src = reduce_color(src) # k-meansで減色
draw_img(src) # 描画
I2NvZGluZzp1dGYtOAoiIiIKCkF1dGhvcidzIFR3aXR0ZXI6IFRvbnlNb29vcmkKCuWfuuacrO+8jOiHquWIhuOBruODoeODoueUqOOBp+OBme+8jgoKV2luMTDjga5tc3BhaW50LmV4ZeS4iuOBp+eUu+WDj+OCkuaPj+eUu+OBmeOCi+ODl+ODreOCsOODqeODoOOBp+OBhu+9kwoK5ZCM5LiA44OH44Kj44Os44Kv44OI44Oq44Gr44Oa44Kk44Oz44OI44Gu44Oc44K/44Oz44Gu55S75YOP44GM54Sh44GE44Go5YuV44GL44Gq44GE44Gu44GnCuippuOBl+OBq+OChOOBo+OBpuOBv+OCiOOBhuOBqOOBi+aAneOBo+OBpuOCguOBoOOBhOOBtumgkeW8teOCieOBquOBhOOBqOWLleOBjeOBvuOBm+OCk++8juOCtOODoeODs+ODiuOCteOCpO+8jgoK44Gf44GgcmVkdWNlX2NvbG9y6Zai5pWw44Gg44GR44GvCueUu+WDj+OBruiJsuOCkk1pbmlCYXRjaEtNZWFuc+OBp+a4m+iJsuOBl+OBpuOCi+OBruOBp++8jOOBneOBk+OBoOOBkeOBr+WkmuWwkeS9v+OBiOOCi+OBi+OBqOaAneOBhOOBvuOBmQoKIiIiCmltcG9ydCBudW1weSBhcyBucAppbXBvcnQgY3YyCmltcG9ydCB0aW1lCmltcG9ydCBweWF1dG9ndWkgYXMgcGEKCmRlZiBzZXRfc2l6ZShzcmMpOgoJIyDlr77op5Lnt5rjga7plbfjgZXjgYwyMDDjgavjgarjgovjgojjgYbjgarjgrnjgrHjg7zjg6vjgpLoqIjnrpcKCWgsdyxjID0gc3JjLnNoYXBlCglzY2FsZSA9IDIwMC4wIC8gbnAuc3FydCggaCoqMiArIHcqKjIgKQoJaCA9IGludChoKnNjYWxlKQoJdyA9IGludCh3KnNjYWxlKQoJCgkjIOODquOCteOCpOOCugoJcmV0dXJuIGN2Mi5yZXNpemUoc3JjLCh3LGgpKQoKZGVmIHJlZHVjZV9jb2xvcihzcmMpOgoJIyBrLW1lYW5z44Gn44Kv44Op44K544K/44Oq44Oz44KwCgkjIC0+IOS7o+ihqOWApOOBq+e9ruOBjeaPm+OBiOOCi+OBk+OBqOOBp+iHqueEtj/jgarmuJvoibLjgpLjgZnjgosKCWZyb20gc2tsZWFybi5jbHVzdGVyIGltcG9ydCBNaW5pQmF0Y2hLTWVhbnMKCVggPSBzcmMucmVzaGFwZShzcmMuc2hhcGVbMF0qc3JjLnNoYXBlWzFdLDMpCgljbGYgPSBNaW5pQmF0Y2hLTWVhbnMoMTYpCgl5ID0gY2xmLmZpdF9wcmVkaWN0KFgpCglyZXR1cm4gY2xmLmNsdXN0ZXJfY2VudGVyc19beV0ucmVzaGFwZShzcmMuc2hhcGUpLmFzdHlwZShucC51aW50OCkKCmRlZiB0b19udW0oYyk6CgkjIHVpbnQ4IHggMyDjga7oibLjg4fjg7zjgr/jgpIgaW50IOWei+OBq+OBmeOCiwoJcmV0dXJuIGNbOiw6LDBdICogKCAyICoqIDE2ICkgKyBjWzosOiwxXSAqICggMiAqKiA4ICkgKyBjWzosOiwyXQoKZGVmIHRvX2NvbChjKToKCSMgaW505Z6L44Gu44OH44O844K/44KS5YiG5Ymy44GX44GmcixnLGLjgavliIbjgZHjgosKCXIgPSBjICUgMjU2CglnID0gKCBjLy8oIDIgKiogOCApICkgJSAyNTYKCWIgPSAoIGMvLyggMiAqKiAxNiApICkgJSAyNTYKCXJldHVybiBucC5hcnJheShbcixnLGJdKQoKZGVmIGltZ19jbGljayhwYXRoKToKCSMg5oyH5a6a44Gu55S75YOP44Gu5aC05omA44KS44Kv44Oq44OD44Kv44GZ44KLCgl3aGlsZSBUcnVlOgoJCXBvcyA9IHBhLmxvY2F0ZUNlbnRlck9uU2NyZWVuKHBhdGgpCgkJaWYgcG9zICE9IE5vbmU6CgkJCXBhLmNsaWNrKHBvcykKCQkJcmV0dXJuCgpkZWYgY2hhbmdlX2NvbG9yKGNvbG9yKToKCSMg44Oa44Kk44Oz44OI44Gu5ZCE44Oc44K/44Oz44KS6aCG55Wq44Gr44Kv44Oq44OD44Kv44GZ44KLCglyID0gY29sb3JbMF0KCWcgPSBjb2xvclsxXQoJYiA9IGNvbG9yWzJdCgkKCSMg55yf44Gj55m944Go44GL5o+P55S744GZ44KL5b+F6KaB44Gq44GECglpZiByID4gMjUwIGFuZCBnID4gMjUwIGFuZCBiID4gMjUwOgoJCXJldHVybiBUcnVlCgkKCSMg44Oc44K/44Oz44KS6aCG44Gr44Kv44Oq44OD44Kv44GX44Gm44GPCglpbWdfY2xpY2soImNvbG9yX2VkaXQucG5nIikKCXBvcyA9IE5vbmUKCXdoaWxlIHBvcyA9PSBOb25lOgoJCXBvcyA9IHBhLmxvY2F0ZUNlbnRlck9uU2NyZWVuKCJyZWQucG5nIikKCXBhLmNsaWNrKCAocG9zWzBdKzMwLHBvc1sxXSkgKQoJcGEuaG90a2V5KCdjdHJsJywgJ2EnKSAKCXBhLnR5cGV3cml0ZShzdHIocikpCglwYS5jbGljayggKHBvc1swXSszMCxwb3NbMV0rMjcpICkKCXBhLmhvdGtleSgnY3RybCcsICdhJykgCglwYS50eXBld3JpdGUoc3RyKGcpKQoJcGEuY2xpY2soIChwb3NbMF0rMzAscG9zWzFdKzYwKSApCglwYS5ob3RrZXkoJ2N0cmwnLCAnYScpIAoJcGEudHlwZXdyaXRlKHN0cihiKSkKCWltZ19jbGljaygib2sucG5nIikKCQoJcmV0dXJuIEZhbHNlCgpkZWYgZHJhd19pbWcoc3JjKToKCSMg55S75YOP44KS5o+P55S744GZ44KLCgkKCSMg6Imy44KS5oq95Ye644GX44Gm44OU44Kv44K744Or5pWw44GM5aSn44GN44GE6aCG44Gr44K944O844OICgkjIOWkmuWIhuOCguOBo+OBqOOCueODnuODvOODiOOBquabuOOBjeaWueOBjOOBguOCiwoJaW1nID0gdG9fbnVtKHNyYykKCWNvbG9yX2xpc3QgPSBucC51bmlxdWUoaW1nKQoJY29sb3JfbnVtID0gbnAuemVyb3MobGVuKGNvbG9yX2xpc3QpKQoJZm9yIGkgaW4gcmFuZ2UobGVuKGNvbG9yX2xpc3QpKToKCQljb2wgPSBjb2xvcl9saXN0W2ldCgkJY29sb3JfbnVtW2ldID0gbGVuKG5wLndoZXJlKCBpbWcgPT0gY29sIClbMF0pCglhcmdfbGlzdCA9IG5wLmFyZ3NvcnQoY29sb3JfbnVtKVs6Oi0xXQoJY29sb3JfbGlzdCA9IGNvbG9yX2xpc3RbYXJnX2xpc3RdCgkKCSMg6auY44GV44O75bmF44KS5oq95Ye6CgloLHcgPSBpbWcuc2hhcGUKCQoJIyA156eS5b6F44Gj44GmCgl0aW1lLnNsZWVwKDUpCgkKCSMg5Yid5pyf44Gu44Oe44Km44K544Gu5bqn5qiZ44KS5Y+W5b6XCgl4MCA9IHBhLnBvc2l0aW9uKClbMF0KCXkwID0gcGEucG9zaXRpb24oKVsxXQoJCgkjIOODlOOCr+OCu+ODq+mWk+OBrui3nembogoJc2lkZSA9IDUKCQoJIyBQeXRob27lpKLjga7ph43jg6vjg7zjg5fvvIHvvIHvvIHvvIEKCSMg6Imy44KS6aCG55Wq44Gr5o+P55S744GX44Gm44GP44KI77yB77yBCglmb3IgY29sIGluIGNvbG9yX2xpc3Q6CgkJCgkJIyDoibLjgpLjgrvjg4Pjg4jjgZnjgosKCQlpZiBjaGFuZ2VfY29sb3IodG9fY29sKGNvbCkpOgoJCQljb250aW51ZQoJCQoJCSMg44OJ44Op44OD44Kw5Lit44Gq44KJVHJ1ZeOBq+OBquOCi+ODleODqeOCsAoJCWlzRHJhZ2dpbmcgPSBGYWxzZQoJCQoJCWZvciBqIGluIHJhbmdlKGgpOgoJCQlmb3IgaSBpbiByYW5nZSh3KToKCQkJCSMg54++5Zyo44Gu5bqn5qiZ5Y+W5b6XCgkJCQl4ID0geDAgKyBzaWRlICogaQoJCQkJeSA9IHkwICsgc2lkZSAqIGoKCQkJCQoJCQkJaWYgY29sID09IGltZ1tqLGldOgoJCQkJCSMg44OJ44Op44OD44Kw44K544K/44O844OICgkJCQkJaWYgaXNEcmFnZ2luZyA9PSBGYWxzZToKCQkJCQkJcGEubW92ZVRvKHgseSkKCQkJCQkJcGEubW91c2VEb3duKCkKCQkJCQkJaXNEcmFnZ2luZyA9IFRydWUKCQkJCQoJCQkJZWxpZiBpc0RyYWdnaW5nID09IFRydWU6CgkJCQkJIyDjg4njg6njg4PjgrDntYLkuoYKCQkJCQlwYS5tb3ZlVG8oeCx5KQoJCQkJCXBhLm1vdXNlVXAoKQoJCQkJCWlzRHJhZ2dpbmcgPSBGYWxzZQoJCQkKCQkJIyDkuIDooYzmm7jjgYTjgZ/jgoltb3VzZVVwCgkJCXBhLm1vdXNlVXAoKQoJCmlmIF9fbmFtZV9fPT0iX19tYWluX18iOgoJcGEuUEFVU0UgPSAwLjAwMDAwMQoJc3JjID0gY3YyLmltcmVhZCgibWlrdS5qcGciKQoJc3JjID0gc2V0X3NpemUoc3JjKQkJCSMg5aSn44GN44GV6Kq/56+ACglzcmMgPSByZWR1Y2VfY29sb3Ioc3JjKQkJIyBrLW1lYW5z44Gn5rib6ImyCglkcmF3X2ltZyhzcmMpIAkJCQkjIOaPj+eUuwo=