English | ็ฎไฝไธญๆ
๐ ไธบ Python ่ชๅจๅ่็็็ชๅฃๆ่ทๅบ
180+ FPS ๆ่ดๆง่ฝ ยท ้ถ่ตๆบๅพ ๆบ ยท ๆ ่ง้ฎๆก ยท API ๆ็ฎ
ไฝ ๆฏๅฆๅจไธบไปฅไธ้ฎ้ขๅฐๆฐ๏ผ
- mss/BitBlt๏ผๆ ๆณๆ่ท่ขซ้ฎๆกๆๅๅฐ็ชๅฃ
- PrintWindow๏ผๆง่ฝ็ถ้ข๏ผๅบๅฎ 26ms+ ๅปถ่ฟ
- ๅ ถไป WGC ๅฐ่ฃ ๏ผๆ็ปญ่ฟ่กๅ ็จ่ตๆบ๏ผ้ข็นๅฏๅๅผ้ๅทจๅคง๏ผ50ms+๏ผ
wgc_python ้่ฟ็ฌๅ็ Pause/Resume ๆบๅถ๏ผๅฎ็พ่งฃๅณไบ่ฟไธช็็พ๏ผ
# ไผ ็ปๆนๅผ๏ผ่ฆไนๆ็ปญ็ฉบ่ฝฌๆตช่ดน่ตๆบ๏ผ่ฆไน้ข็นๅฏๅๆฟๅๅปถ่ฟ
start_capture() # 50ms ๅผ้
get_frame() # ่ทๅๆชๅพ
stop_capture() # ้ๆฏไผ่ฏ๏ผ50ms๏ผ
# ไธๆฌกๆชๅพๅ่ฆ้ๆฐๅผๅง...
# wgc_python ๆนๅผ๏ผไธๆฌกๅฏๅจ๏ผๆ้ๆชๅพ๏ผ้ถๅผ้ๅพ
ๆบ
with WindowCapture("็ชๅฃ", "็ฑปๅ") as cap:
while running:
frame = cap.capture_one() # auto Resume โ ็ญๅพ
ๅธง โ ๆท่ด โ Pause
# ๅค็ๅพๅ...| ๆนๆก | FPS | ๅๅฐๆ่ท | CPU ๅ ็จ | ้ข็นๅๆขๅผ้ | ๆๅๅ GPU ๅ ็จ |
|---|---|---|---|---|---|
| python-mss / BitBlt | ~60 | โ | ้ซ | ไฝ | N/A (ๆ ๆๅๆฆๅฟต) |
| PrintWindow | ~38 | โ | ไธญ | ไฝ | N/A (ๆฏๆฌก่ฐ็จๅณๆ่ท) |
| ๅ ถไป WGC ๅฐ่ฃ | 180+ | โ | ้ซ๏ผๆ็ปญ็ฉบ่ฝฌ๏ผ | ๆ้ซ (50ms+) | ้ซ (ๆ ๆณ็ๆญฃๆๅ) |
| wgc_python | 180+ | โ | ๆไฝ๏ผPauseๆถๅฝ้ถ๏ผ | <1ฮผs๏ผๅๅญๆ ๅฟไฝ๏ผ | ๅฝ้ถ๏ผๆ D3D ๆไฝ๏ผ |
- 180+ FPS ้ซๅธง็ๆ่ท๏ผๆฏ PrintWindow ๅฟซ 5 ๅ
- ๅ็ผๅฒ Staging ็บน็๏ผGPU ๅผๆญฅๆท่ด๏ผ่ฏปๅไบไธ้ปๅก
- ้ถๆท่ดๅๅฅฝ๏ผ
np.ndarray(strides=...)็ดๆฅไป GPU ๆ ๅฐๅ ๅญๆ้ ่งๅพ
- Pause/Resume <1ฮผs ่ฝฏๆๅ๏ผไธ้ๆฏไธ้ๅปบ WGC session๏ผไป ๅๅญๆ ๅฟไฝ่ทณ่ฟๅธงๅค็
- capture_one() ่ชๅจ็ฎก็๏ผResume โ ็ญๅพ ๅธง โ ๆท่ด โ Pause๏ผ้ด้ GPU ้ฉฑๅจ้ถๅผ้
- ไผ่ฏๅค็จ๏ผ้ฟๅ ้ข็นๅๅปบ/้ๆฏ D3D ่ฎพๅค็ๅผ้
- capture_one()๏ผไธ่กไปฃ็ ๅฎๆๆ้ๆ่ท๏ผ่ฟๅ numpy ๆฐ็ป
- get_frame()๏ผ้ถๆท่ด่ฃธๆ้่ทฏๅพ๏ผ้ซ็บงไฝฟ็จ๏ผ
- ็บฟ็จๅฎๅ จ๏ผC++ ๅฑๅค็ๆๆๅค็บฟ็จๅคๆๆง
- ๅไธ่ฟ็จๅ ๅฏๅๆถๅๅปบๅคไธชๆ่ทไผ่ฏ๏ผไบไธๅนฒๆฐ
- ๆฏไธชไผ่ฏ็ฌ็ซ D3D11 ่ฎพๅค + ็ฌ็ซ็บน็ + ็ฌ็ซ WinRT session๏ผๅฎๅ จ้็ฆป
- ๆฏๆๅ็ชๅฃๅค่ทฏๅนถๅๆ่ท
- ้ป่ฎค
client_area_only=True๏ผๅชๆ่ท็ชๅฃๅฎขๆทๅบๅ ๅฎน๏ผ่ชๅจ่ฃๅชๆ ้ขๆ ๅ่พนๆก๏ผ็ดๆฅ่พๅบๆๆๅ็ด - ่ฎพ็ฝฎ
client_area_only=False๏ผๆ่ทๆดไธช็ชๅฃ๏ผๅซๆ ้ขๆ ๅ่พนๆก๏ผ๏ผๆปก่ถณ UI ่ฎฐๅฝๅบๆฏ - DPI ๆ็ฅ๏ผ่ชๅจไฟฎๆญฃ้ซ DPI ็ผฉๆพๅ็งป๏ผ่ฃๅช็ฒพๅบฆๅ็ด ็บง
- GPU ็บง่ฃๅช๏ผ
CopySubresourceRegionๅจ GPU ไธๅฎๆ่ฃๅช๏ผไธๆตช่ดนๅธฆๅฎฝๅ CPU
- ๆฏๆๆ่ท่ขซ้ฎๆกใๆๅฐๅใๅๅฐ็ชๅฃ
- ๅฎ็พ้้ ๆธธๆใๆก้ขๅบ็จ็ญๅ็งๅบๆฏ
pip install wgc-pythonfrom wgc_python import WindowCapture, enumerate_windows
# ๆไธพๆๆ็ชๅฃ
for title, class_name in enumerate_windows():
print(f"{title} ({class_name})")
# ๆ้ๆ่ท๏ผๆจ่ โโ ้ถๅผ้ๅพ
ๆบ๏ผ
with WindowCapture("็ชๅฃๆ ้ข", "็ชๅฃ็ฑปๅ") as cap:
frame = cap.capture_one() # BGRA numpy ๆฐ็ป๏ผshape (h, w, 4)
if frame is not None:
print(f"ๆ่ทๆๅ: {frame.shape}")
# ๅฎขๆทๅบ่ฃๅชๆผ็คบ
# ้ป่ฎค client_area_only=True๏ผๅชๆชๅๅฎขๆทๅบ๏ผไธๅซๆ ้ขๆ /่พนๆก
cap_client = WindowCapture("่ฎฐไบๆฌ", "Notepad") # ๅชๆชๅ
ๅฎน
cap_full = WindowCapture("่ฎฐไบๆฌ", "Notepad", client_area_only=False) # ๅซๆ ้ขๆ
frame_client = cap_client.capture_one() # ๅชๆ็ผ่พๅบ
frame_full = cap_full.capture_one() # ๅซๆ ้ขๆ + ่ๅ + ็ผ่พๅบ
cap_client.close()
cap_full.close()from wgc_python import WindowCapture
cap = WindowCapture("ๆธธๆ็ชๅฃ", "UnityWndClass")
while True:
frame = cap.capture_one(timeout=1.0)
if frame is not None:
# frame ๆฏ BGRA numpy ๆฐ็ป๏ผ็ดๆฅ็จไบ OpenCV/ๆจกๆฟๅน้
pass
time.sleep(1)
cap.close()from wgc_python import WindowCapture
import numpy as np
import ctypes
with WindowCapture("็ชๅฃ", "็ฑปๅ") as cap:
cap.resume()
r = cap.get_frame() # (ptr, w, h, row_pitch) โ GPU ๆ ๅฐ่ฃธๆ้
if r:
ptr, w, h, rp = r
arr = np.ndarray((h, w, 4), dtype=np.uint8,
buffer=(ctypes.c_ubyte * (h * rp)).from_address(ptr),
strides=(rp, 4, 1))
# arr ๆฏ GPU ๅ
ๅญ็้ถๆท่ด่งๅพ
cap.release_frame()
cap.pause()from wgc_python import WindowCapture
import cv2
with WindowCapture("็ชๅฃๆ ้ข", "็ชๅฃ็ฑปๅ") as cap:
while True:
frame = cap.capture_one()
if frame is not None:
cv2.imshow("Capture", cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR))
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()from wgc_python import (
WindowCapture, # ็ชๅฃๆ่ท็ฑป๏ผไธไธๆ็ฎก็ๅจๆฏๆ๏ผ
enumerate_windows, # ๆไธพๆๆๅฏ่ง็ชๅฃ
get_last_error, # ่ทๅๆๅ้่ฏฏไฟกๆฏ๏ผ็บฟ็จๅฎๅ
จ๏ผ
get_active_capture_count, # ่ทๅๆดป่ทๆ่ทๆฐ
)
# WindowCapture ็ฑปๆนๆณ:
# cap = WindowCapture(title, class_name, client_area_only=True)
#
# cap.capture_one(timeout=0.5) -> np.ndarray | None โ
ๆจ่
# ่ชๅจ Resume โ ็ญๅพ
ๅธง โ ๆท่ดไธบ numpy โ Pause
# ๆ่ท้ด้ WGC ๅฎๅ
จไผ็ ๏ผGPU ้ฉฑๅจ้ถๅผ้
#
# cap.get_frame() -> (ptr, w, h, row_pitch) | None
# cap.release_frame() # ้ๆพ GPU ๆ ๅฐ
# cap.pause() # ๆๅๆ่ท๏ผ้ถ่ตๆบๅพ
ๆบ๏ผ
# cap.resume() # ๆขๅคๆ่ท
# cap.stop() # ๅๆญขๅธงๅฐ่พพ
# cap.close() # ้ๆฏไผ่ฏ
# cap.is_capturing() -> bool
# cap.is_paused() -> bool
# cap.get_frame_count() -> int
# cap.handle -> int (DLL handle)WGCๆ่ท โ GPU Surface็บน็
โ
โโโโโโโโโโผโโโโโโโโโ
โ FrameArrived โ
โ if pausing โ โ โ โ Pauseๆถ็ดๆฅ่ฟๅ๏ผ้ถ D3D ๆไฝ
โโโโโโโโโโฌโโโโโโโโโโ
โ
CopyResource (GPUๅผๆญฅๅคๅถ)
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๅ็ผๅฒStaging็บน็ โ
โ [0] ๅๅ
ฅ โโ [1] ่ฏปๅ โ
โ m_textureInUse ้ฒๅฒๆ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Map (ๆฐธไน
ๆ ๅฐ GPU ๅ
ๅญ)
โ
โโโโโโโ ้ถๆท่ด่พๅบ โโโโโโโโ
โ get_frame() โ
โ ่ฟๅ่ฃธๆ้ โ numpy้ถๆท่ด โ
โ ้ๆๅจ release_frame() โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโ ไธ้ฎๆ่ท โโโโโโโโโโโ
โ capture_one() โ
โ auto Pause/Resume โ
โ ่ฟๅ numpy ๆฐ็ป โ
โ ้ด้ GPU ้ฉฑๅจ้ถๅผ้ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
็จๆท่ฐ็จ cap.pause()
โ
m_isPaused = true โโโโโ ๅๅญๆ ๅฟไฝ๏ผ<1ฮผs
m_readableStagingIndex = -1
โ
โโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ FrameArrived ๅ่ฐ๏ผWGC ไปไผ่งฆๅ๏ผ โ
โ โ
โ lock(mutex); โ
โ if (m_isPaused) return; // โ ็บฏCPUๅคๆญ๏ผ่ทณ่ฟโ
โ // โ ไปฅไธๅชๅจ resume ๅๆง่ก โ โ
โ CopyResource(staging, frame); โ
โ m_readableStagingIndex = idx; โ
โ unlock(mutex); โ
โโโโโโฒโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
็จๆท่ฐ็จ cap.resume() MapFrame ๆฃๆฅ readableStagingIndex
m_isPaused = false <0 โ ๆ่ฟๅธงๅฐๆชๅฐฑ็ปช๏ผ่ฟๅ false
ไธ้ๆฏ WGC session / ไธ้ๅปบ D3D ่ฎพๅค / ไธ้ๆฐๆณจๅๅ่ฐ
โ ๆขๅค้ถๅปถ่ฟ๏ผๆ ็ชๅบ
wgc_python/
โโโ wgc_python/ # Python ๅ
โ โโโ __init__.py # Python API๏ผctypes FFI๏ผ
โ โโโ wgc_python.dll # ็ผ่ฏๅ็ DLL
โโโ wgc_python_dll/ # C++ DLL ้กน็ฎ
โ โโโ WGCWindowCapture.h/cpp # WGC ๆ่ทๆ ธๅฟ๏ผๅ็ผๅฒ + ้ถๆท่ด๏ผ
โ โโโ WGCExport.h/cpp # DLL ๅฏผๅบ๏ผๅซ็บฟ็จๅฎๅ
จ้่ฏฏๅค็๏ผ
โ โโโ D3DInterop.cpp # D3D11 ่ฎพๅคไบๆไฝ
โ โโโ WindowEnumerator.h/cpp # ็ชๅฃๆไธพ
โ โโโ pch.h # ้ข็ผ่ฏๅคด
โ โโโ packages/ # NuGet ๅ
โโโ test.py # ๅ่ฝๆต่ฏ
โโโ test_mt.py # ๅค็บฟ็จๆ้ๆ่ท็คบไพ
โโโ pyproject.toml # pip ๆๅปบ้
็ฝฎ
โโโ BUILD.md / BUILD_EN.md # ๆๅปบ่ฏดๆ๏ผไธญ/่ฑ๏ผ
โโโ README.md / README_EN.md # ไฝฟ็จๆๆกฃ๏ผไธญ/่ฑ๏ผ
โโโ CONTRIBUTING.md # ่ดก็ฎๆๅ
โโโ CODE_OF_CONDUCT.md # ่กไธบๅๅ
โโโ LICENSE # MIT ่ฎธๅฏ่ฏ
โโโ requirements.txt # Python ไพ่ต
- Windows 10 1903+ (Build 18362)
- Python 3.6+
่ฏฆ่ง BUILD.md
| ้ฎ้ข | ่งฃๅณๆนๆก |
|---|---|
| DLL ๆชๆพๅฐ | ็กฎไฟ wgc_python.dll ๅจๆญฃ็กฎไฝ็ฝฎ |
| ๆ่ทๅคฑ่ดฅ | ๆฃๆฅ็ชๅฃๆฏๅฆๅฏ่ง๏ผWindows ็ๆฌ >= 1903 |
| ไธญๆ่ทฏๅพไฟๅญๅคฑ่ดฅ | ไฝฟ็จ cv2.imencode + open().write() ไปฃๆฟ cv2.imwrite |
| ไพ่ต็ผบๅคฑ | pip install numpy opencv-python |
- โ ๆธธๆ AI / ่ชๅจๅ่ๆฌ
- โ RPA ๆต็จ่ชๅจๅ
- โ ๅฑๅนๅฝๅถ / ็ดๆญ
- โ UI ่ชๅจๅๆต่ฏ
- โ ่ฎก็ฎๆบ่ง่งๅบ็จ
ๆฌ้กน็ฎๅบไบ robmikh/Win32CaptureSample ๅผๅใ
MIT License