1 Commits
Author SHA1 Message Date
Manatsawin Hanmongkolchai 6edf87ba7b OpenCV 2021-02-12 21:44:36 +07:00
13 changed files with 420 additions and 116 deletions

No files matched your search

+16
View File
@@ -14,6 +14,22 @@ The `game` package is the only one allowed to use platform-dependent code. All o
- game: Interact with the game window. Since accessing other application's window is not abstracted by Qt, this package is the only one allowed to be platform dependent
- image: Image processing tools
### Image format
The library has two internal image formats:
- numpy.ndarray of shape (height, width, 4)
- Current standard
- Store pixels in BGRA32 format (ARGB 8 bit per channel in little endian)
- Should be faster as no channel swapping is needed
- Requires copying when accessing raw buffer
- Support OpenCV operation
- PIL Image
- Deprecated
- Store pixels in RGBA32 format
- Slower as when communicating with Alt1 we need to swap to BGRA
- Can access raw buffer without copying
- Easier to work with for basic operations
## App
Packages related to Alt1 app.
Generated
+150 -1
View File
@@ -79,6 +79,14 @@ category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "future"
version = "0.18.2"
description = "Clean single-source support for Python 3 and 2"
category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "idna"
version = "2.10"
@@ -106,6 +114,36 @@ category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "numpy"
version = "1.20.1"
description = "NumPy is the fundamental package for array computing with Python."
category = "main"
optional = false
python-versions = ">=3.7"
[[package]]
name = "opencv-python"
version = "4.5.1.48"
description = "Wrapper package for OpenCV python bindings."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
numpy = ">=1.19.3"
[[package]]
name = "opencv-python-headless"
version = "4.5.1.48"
description = "Wrapper package for OpenCV python bindings."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
numpy = ">=1.19.3"
[[package]]
name = "pathspec"
version = "0.8.1"
@@ -114,6 +152,17 @@ category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pefile"
version = "2019.4.18"
description = "Python PE parsing module"
category = "dev"
optional = false
python-versions = "*"
[package.dependencies]
future = "*"
[[package]]
name = "pillow"
version = "8.1.0"
@@ -152,7 +201,9 @@ python-versions = ">=3.5"
[package.dependencies]
altgraph = "*"
macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
pefile = {version = ">=2017.8.1", markers = "sys_platform == \"win32\""}
pyinstaller-hooks-contrib = ">=2020.6"
pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""}
[package.extras]
encryption = ["tinyaes (>=1.0.0)"]
@@ -234,6 +285,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.10"
[package.dependencies]
shiboken2 = "5.15.2"
[[package]]
name = "pywin32-ctypes"
version = "0.2.0"
description = ""
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "regex"
version = "2020.11.13"
@@ -336,7 +395,7 @@ six = "*"
[metadata]
lock-version = "1.1"
python-versions = "^3.9,<3.10"
content-hash = "e03d69fddabf9d01440a8ce93b9da739a4a0a664c3888c12f0970ce956338a05"
content-hash = "077116eae8dbd00c752035808cd49c268cc8124c705c841a2da69b68d577adee"
[metadata.files]
altgraph = [
@@ -437,6 +496,9 @@ cython = [
{file = "Cython-0.29.21-py2.py3-none-any.whl", hash = "sha256:5c4276fdcbccdf1e3c1756c7aeb8395e9a36874fa4d30860e7694f43d325ae13"},
{file = "Cython-0.29.21.tar.gz", hash = "sha256:e57acb89bd55943c8d8bf813763d20b9099cc7165c0f16b707631a7654be9cad"},
]
future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
]
idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
@@ -449,10 +511,93 @@ mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
numpy = [
{file = "numpy-1.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ae61f02b84a0211abb56462a3b6cd1e7ec39d466d3160eb4e1da8bf6717cdbeb"},
{file = "numpy-1.20.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:65410c7f4398a0047eea5cca9b74009ea61178efd78d1be9847fac1d6716ec1e"},
{file = "numpy-1.20.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d7e27442599104ee08f4faed56bb87c55f8b10a5494ac2ead5c98a4b289e61f"},
{file = "numpy-1.20.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4ed8e96dc146e12c1c5cdd6fb9fd0757f2ba66048bf94c5126b7efebd12d0090"},
{file = "numpy-1.20.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:ecb5b74c702358cdc21268ff4c37f7466357871f53a30e6f84c686952bef16a9"},
{file = "numpy-1.20.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b9410c0b6fed4a22554f072a86c361e417f0258838957b78bd063bde2c7f841f"},
{file = "numpy-1.20.1-cp37-cp37m-win32.whl", hash = "sha256:3d3087e24e354c18fb35c454026af3ed8997cfd4997765266897c68d724e4845"},
{file = "numpy-1.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:89f937b13b8dd17b0099c7c2e22066883c86ca1575a975f754babc8fbf8d69a9"},
{file = "numpy-1.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a1d7995d1023335e67fb070b2fae6f5968f5be3802b15ad6d79d81ecaa014fe0"},
{file = "numpy-1.20.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:60759ab15c94dd0e1ed88241fd4fa3312db4e91d2c8f5a2d4cf3863fad83d65b"},
{file = "numpy-1.20.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:125a0e10ddd99a874fd357bfa1b636cd58deb78ba4a30b5ddb09f645c3512e04"},
{file = "numpy-1.20.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c26287dfc888cf1e65181f39ea75e11f42ffc4f4529e5bd19add57ad458996e2"},
{file = "numpy-1.20.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7199109fa46277be503393be9250b983f325880766f847885607d9b13848f257"},
{file = "numpy-1.20.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:72251e43ac426ff98ea802a931922c79b8d7596480300eb9f1b1e45e0543571e"},
{file = "numpy-1.20.1-cp38-cp38-win32.whl", hash = "sha256:c91ec9569facd4757ade0888371eced2ecf49e7982ce5634cc2cf4e7331a4b14"},
{file = "numpy-1.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:13adf545732bb23a796914fe5f891a12bd74cf3d2986eed7b7eba2941eea1590"},
{file = "numpy-1.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:104f5e90b143dbf298361a99ac1af4cf59131218a045ebf4ee5990b83cff5fab"},
{file = "numpy-1.20.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:89e5336f2bec0c726ac7e7cdae181b325a9c0ee24e604704ed830d241c5e47ff"},
{file = "numpy-1.20.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:032be656d89bbf786d743fee11d01ef318b0781281241997558fa7950028dd29"},
{file = "numpy-1.20.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:66b467adfcf628f66ea4ac6430ded0614f5cc06ba530d09571ea404789064adc"},
{file = "numpy-1.20.1-cp39-cp39-win32.whl", hash = "sha256:12e4ba5c6420917571f1a5becc9338abbde71dd811ce40b37ba62dec7b39af6d"},
{file = "numpy-1.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:9c94cab5054bad82a70b2e77741271790304651d584e2cdfe2041488e753863b"},
{file = "numpy-1.20.1-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:9eb551d122fadca7774b97db8a112b77231dcccda8e91a5bc99e79890797175e"},
{file = "numpy-1.20.1.zip", hash = "sha256:3bc63486a870294683980d76ec1e3efc786295ae00128f9ea38e2c6e74d5a60a"},
]
opencv-python = [
{file = "opencv-python-4.5.1.48.tar.gz", hash = "sha256:78a6db8467639383caedf1d111da3510a4ee1a0aacf2117821cae2ee8f92ce37"},
{file = "opencv_python-4.5.1.48-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:bcb27773cfd5340b2b599b303d9f5499838ef4780c20c038f6030175408c64df"},
{file = "opencv_python-4.5.1.48-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9646875c501788b1b098f282d777b667d6da69801739504f1b2fd1268970d1da"},
{file = "opencv_python-4.5.1.48-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:ebe83901971a6755512424c4fe9f63341cca501b7c497bf608dd38ee31ba3f4c"},
{file = "opencv_python-4.5.1.48-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:d8aefcb30b71064dbbaa2b0ace161a36464c29375a83998fbda39a1d1740f942"},
{file = "opencv_python-4.5.1.48-cp36-cp36m-win32.whl", hash = "sha256:32dee1c9fd3e31e28edef7b56f868e2b40e280b7062304f9fb8a14dbc51547d5"},
{file = "opencv_python-4.5.1.48-cp36-cp36m-win_amd64.whl", hash = "sha256:9c77d508e6822f1f40c727d21b822d017622d8305dce7eccf0ab06caac16d5c6"},
{file = "opencv_python-4.5.1.48-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:4982fa8ccc38310a2bd93e06334ba090b12b6aff2f6fcb8ff9613e3c9bc48f48"},
{file = "opencv_python-4.5.1.48-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c0503bfaa2b7b743d6ff5d81f1dd8428dbf4c33e7e4f836456d11be20c2e7721"},
{file = "opencv_python-4.5.1.48-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:e27d062fa1098d90f48b6c047351c89816492a08906a021c973ce510b04a7b9d"},
{file = "opencv_python-4.5.1.48-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:6d8434a45e8f75c4da5fd0068ce001f4f8e35771cc851d746d4721eeaf517e25"},
{file = "opencv_python-4.5.1.48-cp37-cp37m-win32.whl", hash = "sha256:e2c17714da59d9d516ceef0450766ff9557ee232d62f702665af905193557582"},
{file = "opencv_python-4.5.1.48-cp37-cp37m-win_amd64.whl", hash = "sha256:efac9893d9e21cfb599828801c755ecde8f1e657f05ec6f002efe19422456d5a"},
{file = "opencv_python-4.5.1.48-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:e77d0feaff37326f62b127098264e2a7099deb476e38432b1083ce11cdedf560"},
{file = "opencv_python-4.5.1.48-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:ffc75c614b8dc3d8102f3ba15dafd6ec0400c7ffa71a91953d41511964ee50e0"},
{file = "opencv_python-4.5.1.48-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c1159d91f29a85c3333edef6ca420284566d9bcdae46dda2fe7282515b48c8b6"},
{file = "opencv_python-4.5.1.48-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:d16144c435b816c5536d5ff012c1a2b7e93155017db7103942ff7efb98c4df1f"},
{file = "opencv_python-4.5.1.48-cp38-cp38-win32.whl", hash = "sha256:b2b9ac86aec5f2dd531545cebdea1a1ef4f81ef1fb1760d78b4725f9575504f9"},
{file = "opencv_python-4.5.1.48-cp38-cp38-win_amd64.whl", hash = "sha256:30edebc81b260bcfeb760b3600c367c5261dfb2fe41e5d1408d5357d0867b40d"},
{file = "opencv_python-4.5.1.48-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:e38fbd7b2db03204ec09930609b7313d6b6d2b271c8fe2c0aa271fa69b726a1b"},
{file = "opencv_python-4.5.1.48-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:fc1472b825d26c8a4f1cfb172a90c3cc47733e4af7522276c1c2efe8f6006a8b"},
{file = "opencv_python-4.5.1.48-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:c4ea4f8b217f3e8be6247fc0787fb81797d85202c722523f41070124a7a621c7"},
{file = "opencv_python-4.5.1.48-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:a1dfa0486db367594510c0c799ec7481247dc86e651b69008806d875ab731471"},
{file = "opencv_python-4.5.1.48-cp39-cp39-win32.whl", hash = "sha256:5172cb37dfd8a0b4945b071a493eb36e5f17675a160637fa380f9c1d9d80535c"},
{file = "opencv_python-4.5.1.48-cp39-cp39-win_amd64.whl", hash = "sha256:c8cc1f5ff3c352ebe756119014c4e4ec7ae5ac536d1f66b0316667ced37637c8"},
]
opencv-python-headless = [
{file = "opencv-python-headless-4.5.1.48.tar.gz", hash = "sha256:d16825755e7b5a6d8737f93e116670229e1510199e0af9213004e187ae0dbcc5"},
{file = "opencv_python_headless-4.5.1.48-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:f2011ecb3980bbed283d17d43e0f1221bac88c0cac1a6fb59a056544de2df2f7"},
{file = "opencv_python_headless-4.5.1.48-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:777fb596e04331f73ef5b0c1faa4d33348f29ca58216d9286355c16f5489c939"},
{file = "opencv_python_headless-4.5.1.48-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:924aa4c34ead0b817309f42291dc526b2a7755476afe3009d1e275fc3090d92d"},
{file = "opencv_python_headless-4.5.1.48-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0e02809db2968e54f3c23340be6ff9a1428b3f03f5dca7cd5aceda66e319ce86"},
{file = "opencv_python_headless-4.5.1.48-cp36-cp36m-win32.whl", hash = "sha256:522f12dd994e064a30562adfd63b9439099bd7c80819f5261c37ebe593283c9e"},
{file = "opencv_python_headless-4.5.1.48-cp36-cp36m-win_amd64.whl", hash = "sha256:e3027e0d1b71b68b5cfe1ea9c627e323dff71112c854ba19805258d8fc6c630e"},
{file = "opencv_python_headless-4.5.1.48-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:f5e40a06116460ef2fd2d1c24be3b65f8bfb5fcdfe433f3fc01bcb4c2eb485bf"},
{file = "opencv_python_headless-4.5.1.48-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:ba2f0bd46e9534f29969e39f7895cbea9764173102b0c04b7818b8a9910d66e4"},
{file = "opencv_python_headless-4.5.1.48-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:f7f8e4f7c63c8e95eb210f4cba88d0069a0a964d6335d7a35b07f0d0baa13558"},
{file = "opencv_python_headless-4.5.1.48-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:aa562c520f46283423ba8fac29099458e42deab697a9abd0491622e421c5c454"},
{file = "opencv_python_headless-4.5.1.48-cp37-cp37m-win32.whl", hash = "sha256:657cdd9fbbbbb7e898ae3d9b0649b367d0e440d429c714104d069c5612d578bb"},
{file = "opencv_python_headless-4.5.1.48-cp37-cp37m-win_amd64.whl", hash = "sha256:fe02a943b1a28b505e954fbce24e867119a3eb4351f93adad55c6cfe81a70484"},
{file = "opencv_python_headless-4.5.1.48-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:526b9e19cf6300f0891d8f427eac1048091912332bb781eb4957a4994bfbe608"},
{file = "opencv_python_headless-4.5.1.48-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5f0c7d34fa9953706c2a1a6d2760a91dc5a68cab3df16af61609894c6c8586f1"},
{file = "opencv_python_headless-4.5.1.48-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:1f7c14f5d4e5af4dc4669fc6b4a983b36072a934c439ac11266b930496da8255"},
{file = "opencv_python_headless-4.5.1.48-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:7c75680ffdf32d7044415a215d1fc60dbec14a7f2f0b59a85f0f74ef5efcb6ad"},
{file = "opencv_python_headless-4.5.1.48-cp38-cp38-win32.whl", hash = "sha256:2560dcf3c1158226b066302f777bfe0f65282410b8d90871dd872306c967d1f1"},
{file = "opencv_python_headless-4.5.1.48-cp38-cp38-win_amd64.whl", hash = "sha256:9aa04a491c534531029fbac61da961fae0bf4abb1786eed9c91befde4ca7bd81"},
{file = "opencv_python_headless-4.5.1.48-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:96d1da6ad061d8f3509668d398d14dd8265e529d6407f87eb26e7f4ddf043cc0"},
{file = "opencv_python_headless-4.5.1.48-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:243aea91cc1e36a47c46da4cc408071af39444a48df1fe1539ea8d7990500fd2"},
{file = "opencv_python_headless-4.5.1.48-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2e6a9a88617a0ef7219cff24ba78a58416670a77e6ac63975f9009af3319ab63"},
{file = "opencv_python_headless-4.5.1.48-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:372149d007e20bf556b7687591d22b58b56b3c225f492da051d81587e5dc7411"},
{file = "opencv_python_headless-4.5.1.48-cp39-cp39-win32.whl", hash = "sha256:65c9ea57be5ebcaed009b3fee14fe59f3b6aa1e573fe08c5039ff057ad593c53"},
{file = "opencv_python_headless-4.5.1.48-cp39-cp39-win_amd64.whl", hash = "sha256:a322d4df14c3a5f19701a023b3da91e9b8af8653b0d2ee0c50b0b341212f7343"},
]
pathspec = [
{file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
{file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
]
pefile = [
{file = "pefile-2019.4.18.tar.gz", hash = "sha256:a5d6e8305c6b210849b47a6174ddf9c452b2888340b8177874b862ba6c207645"},
]
pillow = [
{file = "Pillow-8.1.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a"},
{file = "Pillow-8.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2"},
@@ -572,6 +717,10 @@ pyside2 = [
{file = "PySide2-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-none-win32.whl", hash = "sha256:087a0b719bb967405ea85fd202757c761f1fc73d0e2397bc3a6a15376782ee75"},
{file = "PySide2-5.15.2-5.15.2-cp35.cp36.cp37.cp38.cp39-none-win_amd64.whl", hash = "sha256:1316aa22dd330df096daf7b0defe9c00297a66e0b4907f057aaa3e88c53d1aff"},
]
pywin32-ctypes = [
{file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
{file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"},
]
regex = [
{file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"},
{file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"},
+2
View File
@@ -17,6 +17,8 @@ pyobjc-framework-ApplicationServices = [{ version="7.1", platform="darwin" }]
pyobjc-framework-CoreText = [{ version="7.1", platform="darwin" }]
click = "^7.1.2"
psutil = "^5.8.0"
opencv-python = "^4.5.1"
opencv-python-headless = "^4.5.1"
[tool.poetry.dev-dependencies]
Cython = "^0.29.21"
+1 -1
View File
@@ -321,7 +321,7 @@
// return -1;
// },
// bindFindSubImg(id, imgstr, imgwidth, x, y, w, h) {
// return '';
// return syncRpc({func: 'bindFindSubImg', id: id, subimg: imgstr, img_width: imgwidth, x: x, y: y, w: w, h: h});
// },
addOCRFont(){
},
+48 -5
View File
@@ -2,7 +2,8 @@ import base64
import json
import logging
import secrets
from typing import TYPE_CHECKING, Dict, Callable, List
import time
from typing import TYPE_CHECKING, Dict, Callable, List, NamedTuple
from urllib.parse import urljoin
from PySide2.QtCore import (
@@ -27,13 +28,21 @@ from runekit.browser.utils import (
ApiPermissionDeniedException,
image_to_stream,
encode_mouse,
decode_image,
)
from runekit.game.instance import ImageType
from runekit.image.cv import find_subimages
from runekit.image.np_utils import ensure_np_image, np_crop
from runekit.ui.tray import tray_icon
if TYPE_CHECKING:
from runekit.app.app import App
class BoundedRegion(NamedTuple):
image: ImageType
class Alt1Api(QObject):
app: "App"
rpc_funcs: Dict[str, Callable]
@@ -41,7 +50,7 @@ class Alt1Api(QObject):
alt1Signal = Signal(int)
_screen_info: QRect
_bound_regions: List
_bound_regions: List[BoundedRegion]
_game_active = False
_game_position: QRect
_game_scaling: float
@@ -52,11 +61,19 @@ class Alt1Api(QObject):
self.app = app
self._bound_regions = []
self._overlay = OverlayApi(self, parent=self)
self.logger = logging.getLogger(
__name__
+ "."
+ self.__class__.__name__
+ "."
+ self.app.manifest["appName"]
)
self.rpc_funcs = {
"getRegion": self.get_region,
"bindRegion": self.bind_region,
"bindGetRegion": self.bind_get_region,
"bindFindSubImg": self.bind_find_subimage,
}
self._update_screen_info()
@@ -197,7 +214,8 @@ class Alt1Api(QObject):
return 0
# Alt1 only support one region
self._bound_regions = [self.app.game_instance.grab_region(x, y, w, h)]
bound_data = self.app.game_instance.grab_region(x, y, w, h)
self._bound_regions = [BoundedRegion(image=bound_data)]
return 1
def bind_get_region(self, id, x, y, w, h):
@@ -210,10 +228,35 @@ class Alt1Api(QObject):
try:
image = self._bound_regions[id - 1]
except IndexError:
print("no img index %d" % id)
self.logger.warning("bindGetRegion(%d) but image not bound", id)
return ""
return image_to_stream(image, x, y, w, h)
return image_to_stream(image.image, x, y, w, h)
def bind_find_subimage(
self, id: int, subimg: str, img_width: int, x: int, y: int, w: int, h: int
):
if id == 0:
return ""
assert x >= 0
assert y >= 0
try:
image = self._bound_regions[id - 1]
except IndexError:
self.logger.warning("bindGetRegion(%d) but image not bound", id)
return ""
image = ensure_np_image(image.image)
image = np_crop(image, x, y, w, h)
subimg = decode_image(subimg, img_width)
start = time.monotonic()
out = find_subimages(image, subimg)
self.logger.debug("OCR took %fs", time.monotonic() - start)
out = [{"x": int(i[0]), "y": int(i[1])} for i in out]
return json.dumps(out)
# endregion
+29 -13
View File
@@ -1,8 +1,12 @@
import base64
from typing import Union
import numpy as np
from PIL import Image
from PySide2.QtGui import QColor
from runekit.image.np_utils import np_crop
TRANSFER_LIMIT = 4_000_000
@@ -16,24 +20,29 @@ class ApiPermissionDeniedException(Exception):
self.required_permission = required_permission
def image_to_stream(image: Image, x=0, y=0, width=None, height=None) -> bytes:
assert image.mode == "RGB" or image.mode == "RGBA"
def image_to_stream(
image: Union[Image.Image, np.ndarray], x=0, y=0, width=None, height=None
) -> bytes:
if isinstance(image, np.ndarray):
return base64.b64encode(np_crop(image, x, y, width, height).tobytes())
else:
assert image.mode == "RGB" or image.mode == "RGBA"
if width is None:
width = image.width
if height is None:
height = image.height
if width is None:
width = image.width
if height is None:
height = image.height
if width * height * 4 > TRANSFER_LIMIT:
return ""
if width * height * 4 > TRANSFER_LIMIT:
return ""
if image.mode == "RGB":
image = image.convert("RGBA")
if image.mode == "RGB":
image = image.convert("RGBA")
r, g, b, a = image.crop((x, y, x + width, y + height)).split()
image = Image.merge("RGBA", (b, g, r, a))
r, g, b, a = image.crop((x, y, x + width, y + height)).split()
image = Image.merge("RGBA", (b, g, r, a))
return base64.b64encode(image.tobytes())
return base64.b64encode(image.tobytes())
def encode_mouse(x: int, y: int) -> int:
@@ -46,3 +55,10 @@ def decode_color(color: int) -> QColor:
b = (color >> 0) & 0xFF
a = (color >> 24) & 0xFF
return QColor.fromRgb(r, g, b, a)
def decode_image(img: str, width: int) -> np.ndarray:
img = base64.b64decode(img)
img = np.frombuffer(img, "<B")
img.shape = (-1, width, 4)
return img
+13 -5
View File
@@ -1,16 +1,20 @@
import abc
import time
from typing import TYPE_CHECKING, Literal, Optional
from typing import TYPE_CHECKING, Literal, Optional, Union
import numpy as np
from PIL import Image
from PySide2.QtCore import QObject, Signal, Property, QRect, Slot
from PySide2.QtGui import QWindow
from PySide2.QtWidgets import QGraphicsItem
from ..image.np_utils import np_crop
if TYPE_CHECKING:
from .manager import GameManager
PROGRESS_TYPE = Literal["RESET", "IN_PROGRESS", "ERROR", "LOADING", "PAUSED"]
ImageType = Union[np.ndarray, Image.Image]
class GameInstance(QObject):
@@ -64,16 +68,20 @@ class GameInstance(QObject):
world = Property(int, get_world, notify=worldChanged)
@abc.abstractmethod
def grab_game(self) -> Image:
def grab_game(self) -> Union[Image.Image, np.ndarray]:
...
@abc.abstractmethod
def grab_desktop(self, x: int, y: int, w: int, h: int) -> Image:
def grab_desktop(self, x: int, y: int, w: int, h: int) -> ImageType:
...
def grab_region(self, x: int, y: int, w: int, h: int) -> Image:
def grab_region(self, x: int, y: int, w: int, h: int) -> ImageType:
image = self.grab_game()
return image.crop((x, y, x + w, y + h))
if isinstance(image, np.ndarray):
return np_crop(image, x, y, w, h)
else:
return image.crop((x, y, x + w, y + h))
def set_taskbar_progress(self, type_: PROGRESS_TYPE, progress: float):
pass
+32 -8
View File
@@ -1,13 +1,37 @@
import logging
import time
from PIL import Image
from PySide2.QtGui import QGuiApplication, QWindow
import numpy as np
from PySide2.QtCore import QBuffer, QIODevice
from PySide2.QtGui import QGuiApplication, QWindow, QPixmap
import cv2
from runekit.image.np_utils import np_save_image
_debug_dump_file = False
logger = logging.getLogger(__name__)
def qpixmap_to_np(im: QPixmap):
# from PIL.ImageQt.fromqimage
buffer = QBuffer()
buffer.open(QIODevice.ReadWrite)
if im.hasAlphaChannel():
im.save(buffer, "png")
else:
im.save(buffer, "ppm")
npbuf = np.frombuffer(buffer.data(), "<B")
buffer.close()
out = cv2.imdecode(npbuf, cv2.IMREAD_UNCHANGED)
if out.shape[2] == 3:
# Add alpha channel
out = np.pad(out, ((0, 0), (0, 0), (0, 1)), constant_values=0xFF)
return out
class QtBaseMixin:
qwindow: QWindow
@@ -18,30 +42,30 @@ class QtGrabMixin(QtBaseMixin):
__game_last_grab = 0.0
__game_last_image = None
def grab_game(self) -> Image:
def grab_game(self) -> np.ndarray:
if (time.monotonic() - self.__game_last_grab) * 1000 < self.refresh_rate:
return self.__game_last_image
screen = QGuiApplication.primaryScreen()
pixmap = screen.grabWindow(self.qwindow.winId())
image = Image.fromqpixmap(pixmap)
image = qpixmap_to_np(pixmap)
if _debug_dump_file:
logger.debug("dumping file")
pixmap.save("/tmp/qtshot.bmp", None, 100)
np_save_image(image, "/tmp/qtshot.bmp")
self.__game_last_image = image
self.__game_last_grab = time.monotonic()
return self.__game_last_image
def grab_desktop(self, x, y, w, h) -> Image:
def grab_desktop(self, x, y, w, h) -> np.ndarray:
screen = QGuiApplication.primaryScreen()
pixmap = screen.grabWindow(0, x, y, w, h)
image = Image.fromqpixmap(pixmap)
image = qpixmap_to_np(pixmap)
if _debug_dump_file:
logger.debug("dumping file")
pixmap.save("/tmp/qtshot.bmp", None, 100)
np_save_image(image, "/tmp/qtshot.bmp")
return image
+7 -10
View File
@@ -1,16 +1,13 @@
import sysv_ipc
import numpy as np
from PIL import ImageOps, Image
def zpixmap_shm_to_image(
shm: sysv_ipc.SharedMemory, size: int, width: int, height: int
) -> Image:
out = Image.frombytes(
"RGBA",
(width, height),
shm.read(size),
"raw",
)
b, g, r, a = out.split()
a = ImageOps.invert(a)
return Image.merge("RGBA", (r, g, b, a))
) -> np.ndarray:
out = np.frombuffer(shm.read(size), "<B").copy()
out.shape = (height, width, 4)
out[:, :, 3] = 0xFF # Convert BGRX to BGRA
return out
-27
View File
@@ -1,27 +0,0 @@
import logging
import struct
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from PIL import Image
try:
from .format import image_to_bgra
except ImportError:
logging.warning("Cannot import native image code, using pure python")
image_8bpp = struct.Struct("BBBB")
def image_to_bgra(image: "Image", x, y, w, h) -> bytes:
buf = bytearray(w * h * image_8bpp.size)
index = 0
for p in image.crop((x, y, x + w, y + h)).getdata():
r = p[0]
g = p[1]
b = p[2]
a = p[3] if len(p) == 4 else 255
image_8bpp.pack_into(buf, index, b, g, r, a)
index += image_8bpp.size
return buf
+59
View File
@@ -0,0 +1,59 @@
from typing import Tuple, List
import numpy as np
import cv2
_debug_save_images = False
def find_subimages(image: np.ndarray, subimage: np.ndarray) -> List[Tuple[int, int]]:
"""
Detect BGRA subimage in BGRA image with the following limitations
* Image transparency is not supported (alpha channel is removed)
* Subimage semi-translucency is not supported
"""
mask = subimage[:, :, 3]
image_bgr = image[:, :, :3]
subimage_bgr = subimage[:, :, :3]
matched = cv2.matchTemplate(image_bgr, subimage_bgr, cv2.TM_SQDIFF, mask=mask).get()
# allow up to 30 pixel per pixel
threshold = (30 ** 2) * subimage.shape[0] * subimage.shape[1]
loc = np.where((matched < threshold) & (matched != np.inf))
out = []
for pos in zip(*loc[::-1]):
out.append(pos)
if _debug_save_images:
from runekit.image.np_utils import np_save_image
import hashlib
cv2.normalize(matched, matched, 0, 0xFF, cv2.NORM_MINMAX)
matched = matched.astype("uint8")
image_bgr = image_bgr.copy()
subimg_hash = hashlib.blake2b(subimage.data, digest_size=8).hexdigest()
for pos in out:
cv2.rectangle(
matched,
pos,
(pos[0] + subimage.shape[1], pos[1] + subimage.shape[0]),
0,
2,
)
cv2.rectangle(
image_bgr,
pos,
(pos[0] + subimage.shape[1], pos[1] + subimage.shape[0]),
(0, 255, 0),
2,
)
np_save_image(image_bgr, f"/tmp/debug-image-{subimg_hash}.png")
np_save_image(subimage_bgr, f"/tmp/debug-subimage-{subimg_hash}.png")
np_save_image(mask, f"/tmp/debug-mask-{subimg_hash}.png")
np_save_image(matched, f"/tmp/debug-result-{subimg_hash}.png")
return out
-46
View File
@@ -1,46 +0,0 @@
from cpython.mem cimport PyMem_Malloc, PyMem_Free
cdef struct ImageRGBA:
unsigned char r
unsigned char g
unsigned char b
unsigned char a
def image_to_bgra(image, long ix, long iy, unsigned long w, unsigned long h):
ptr = dict(image.im.unsafe_ptrs)['image32']
cdef size_t ptr_int = <size_t> ptr
cdef ImageRGBA **image32 = <ImageRGBA**> ptr_int
if ix < 0:
ix = 0
if iy < 0:
iy = 0
if ix + w > image.width:
w = image.width - ix
if iy + h > image.height:
h = image.height - iy
cdef size_t size = w * h * 4
cdef unsigned char *buf = <unsigned char*> PyMem_Malloc(size)
cdef size_t index, x, y
cdef unsigned char r, g, b, a
with nogil:
for y in range(iy, iy+h):
for x in range(ix, ix+w):
index = (((y-iy) * w) + (x-ix)) * 4
r = image32[y][x].r
g = image32[y][x].g
b = image32[y][x].b
a = image32[y][x].a
buf[index] = b
buf[index+1] = g
buf[index+2] = r
buf[index+3] = a
try:
return buf[:size]
finally:
PyMem_Free(buf)
+63
View File
@@ -0,0 +1,63 @@
from typing import TYPE_CHECKING
import numpy as np
if TYPE_CHECKING:
from runekit.game.instance import ImageType
def np_crop(image: np.ndarray, x: int, y: int, w: int, h: int) -> np.ndarray:
shape = image.shape
img_width = shape[1]
img_height = shape[0]
if w is None:
w = img_width
if h is None:
h = img_height
x_pad_left = max(0, -x)
y_pad_left = max(0, -y)
x1 = max(0, x)
y1 = max(0, y)
x2 = min(x1 + w - x_pad_left, img_width - x_pad_left)
y2 = min(y1 + h - y_pad_left, img_height - y_pad_left)
image = image[y1:y2, x1:x2]
x_pad = (x_pad_left, w - (x2 - x1) - x_pad_left)
y_pad = (y_pad_left, h - (y2 - y1) - y_pad_left)
if x_pad != (0, 0) or y_pad != (0, 0):
image = np.pad(image, (y_pad, x_pad, (0, 0)))
return image
def np_save_image(image: np.ndarray, out: str):
from PIL import Image
size = (image.shape[1], image.shape[0])
if len(image.shape) == 2:
# Grayscale
Image.frombuffer("L", size, image.tobytes(), "raw", "L", 0, 1).save(out)
elif image.shape[2] == 3:
# RGB
Image.frombuffer(
"RGB", size, image[:, :, ::-1].tobytes(), "raw", "RGB", 0, 1
).save(out)
else:
# RGBA
Image.frombuffer(
"RGBA", size, image[:, :, [2, 1, 0, 3]].tobytes(), "raw", "RGBA", 0, 1
).save(out)
def ensure_np_image(image: "ImageType") -> np.ndarray:
if isinstance(image, np.ndarray):
return image
if image.mode == "RGB":
image = image.convert("RGBA")
out = np.array(image)
out = out[:, :, [2, 1, 0, 3]] # B G R A
return out