Finished getPanoramaMap() functionality

- Created an outter loop to capture multiple columns of the map [dfwindow]
- Crop the image to the map [dfwindow]
- Instead of writing a file, return the image [dfwindow]
- Save the map in the test function [imgtools.test5]
- Experimented with faster timings [imgtools.test5]
This commit is contained in:
Doc
2026-04-18 11:21:50 -04:00
parent 71758c42cc
commit 1f9d234c80
2 changed files with 88 additions and 73 deletions
+74 -73
View File
@@ -10,9 +10,6 @@ from loguru import logger
from .waytools import capActiveWindow, focusWindow, moveMouse
from .waytools import sendKey as _sendKey
# TODO: Consider type hinting images from cv2.typing import MatLike
class DFWINDOW:
class TOOLS:
@staticmethod
@@ -471,11 +468,11 @@ class DFWINDOW:
"map_height": int(self._map_height),
"map_width": int(self._map_width),
}
with open("./calib_info.json", "w") as fh:
with Path("./calib_info.json").open("w") as fh:
json.dump(calib_info, fh)
def test_loadCalib(self):
with open("./calib_info.json") as fh:
with Path("./calib_info.json").open() as fh:
calib_info = json.load(fh)
self._gridx = calib_info["gridx"]
@@ -504,7 +501,13 @@ class DFWINDOW:
return (int(safe_width), int(safe_height))
def getPanoramaMap(self):
def getPanoramaMap(self) -> np.ndarray | None:
"""Capture a full size map from stitching together screen captures that are automatically taken.
"""
# Calibrate the movement on the map
self.calibrateGrid()
# Create the big_map canvas
@@ -523,86 +526,84 @@ class DFWINDOW:
if 1 == 1:
# The initial setup
new_x = self.contentWidth
new_y = self.contentHeight
canvas_pos = [0, 0]
self.setGridPos(0, 0)
pixels_added = (0,0)
# Never do more than this many loops
sanity_steps_left = self.maxGridY + 1
while sanity_steps_left > 0:
# Capture a tile
img = self.capContent()
cap_start_x = max(self.TOOLS.firstNotBlackX(img), self.contentWidth - new_x)
cap_start_y = max(self.TOOLS.firstNotBlackY(img), self.contentHeight - new_y)
sanity_steps_left_x = self.maxGridX + 1
new_x = self.contentWidth
canvas_pos[0] = 0
# Columns
while sanity_steps_left_x > 0:
# use min with other restriction if needed in the future min(lastNotBlack,Other_limit)
cap_end_x = self.TOOLS.lastNotBlackX(img)
cap_end_y = self.TOOLS.lastNotBlackY(img)
# Rows
# Never do more than this many loops
sanity_steps_left = self.maxGridY + 1
new_y = self.contentHeight
canvas_pos[1] = 0
while sanity_steps_left > 0:
# Capture a tile
img = self.capContent()
cap_start_x = max(self.TOOLS.firstNotBlackX(img), self.contentWidth - new_x)
cap_start_y = max(self.TOOLS.firstNotBlackY(img), self.contentHeight - new_y)
pixels_added = self.addToCanvas(
img[cap_start_y : cap_end_y + 1, cap_start_x : cap_end_x + 1], canvas_pos[0], canvas_pos[1]
)
canvas_pos[1] += pixels_added[1]
# use min with other restriction if needed in the future min(lastNotBlack,Other_limit)
cap_end_x = self.TOOLS.lastNotBlackX(img)
cap_end_y = self.TOOLS.lastNotBlackY(img)
# Reasons to finish this column:
# - pixels_added[1] < cap_height
# - (with cur logic) cap_height < self.contentHeight
# - self.curGridY >= self.maxGridY
logger.trace(f"{cap_start_y=} {cap_end_y=} {self.contentHeight=} {pixels_added=} {canvas_pos=}")
logger.trace(f"{self.curGridPos=} {self.map_canvas.shape=}")
pixels_added = self.addToCanvas(
img[cap_start_y : cap_end_y + 1, cap_start_x : cap_end_x + 1], canvas_pos[0], canvas_pos[1]
)
canvas_pos[1] += pixels_added[1]
sanity_steps_left -= 1 # Prevent runaway loops
# Reasons to finish this column:
# - pixels_added[1] < cap_height
# - (with cur logic) cap_height < self.contentHeight
# - self.curGridY >= self.maxGridY
logger.trace(f"{cap_start_y=} {cap_end_y=} {self.contentHeight=} {pixels_added=} {canvas_pos=}")
logger.trace(f"{self.curGridPos=} {self.map_canvas.shape=}")
sanity_steps_left -= 1 # Prevent runaway loops
if not (
(cap_end_y + 1 < self.contentHeight)
or (pixels_added[1] < ((cap_end_y + 1) - cap_start_y))
or (self.curGridY >= self.maxGridY)
or (canvas_pos[1] >= self.map_canvas.shape[0])
):
# pan down for more map, but watch limits
steps_to_pan_down = min(self.maxGridY - self.curGridY, math.floor(self.contentHeight / self.stepSizeY))
self.setGridPos(self.curGridX, self.curGridY + steps_to_pan_down)
new_y = steps_to_pan_down * self.stepSizeY
else:
break
if sanity_steps_left < 1:
logger.debug(f"Our loop in the Y axis ran over. {sanity_steps_left=}")
sanity_steps_left_x -= 1
# Reset to next column
if not (
(cap_end_y + 1 < self.contentHeight)
or (pixels_added[1] < ((cap_end_y + 1) - cap_start_y))
or (self.curGridY >= self.maxGridY)
or (canvas_pos[1] >= self.map_canvas.shape[0])
(cap_end_x + 1 < self.contentWidth) # pyright: ignore[reportPossiblyUnboundVariable]
or (pixels_added[0] < ((cap_end_x + 1) - cap_start_x)) # pyright: ignore[reportPossiblyUnboundVariable]
or (self.curGridX >= self.maxGridX)
or (canvas_pos[0] >= self.map_canvas.shape[1])
):
# pan down for more map, but watch limits
steps_to_pan_down = min(self.maxGridY - self.curGridY, math.floor(self.contentHeight / self.stepSizeY))
self.setGridPos(0, self.curGridY + steps_to_pan_down)
new_y = steps_to_pan_down * self.stepSizeY
steps_to_pan_over = min(self.maxGridX - self.curGridX, math.floor(self.contentWidth / self.stepSizeX))
self.setGridPos(self.curGridX + steps_to_pan_over,0)
new_x = steps_to_pan_over * self.stepSizeX
canvas_pos[0] += pixels_added[0]
else:
break
if sanity_steps_left < 1:
logger.debug(f"Our loop in the Y axis ran over. {sanity_steps_left=}")
if sanity_steps_left_x < 1:
logger.debug(f"Our loop in the X axis ran over. {sanity_steps_left_x=}")
if self.map_canvas is not None:
cv2.imwrite("./test_canvas.png", self.map_canvas)
# if 1 == 0:
# self.setGridPos(0, 0)
# canvas_x = 0
# canvas_y = 0
# img = self.capContent()
# startx = self.TOOLS.firstNotBlackX(img)
# starty = self.TOOLS.firstNotBlackY(img)
# img_ul = img[starty:, startx:]
# # cv2.rectangle(img, (startx, starty), (self.contentWidth, self.contentHeight), (255, 255, 255, 255), 3)
# logger.debug(f"img_ul is {img_ul.shape[1]} x {img_ul.shape[0]}")
# last_add = self.addToCanvas(img_ul, 0, 0)
# steps_to_pan_down = math.floor(self.contentHeight / self.stepSizeY)
# logger.debug(f"{startx=} {starty=} {steps_to_pan_down=}")
# self.setGridPos(0, steps_to_pan_down)
# time.sleep(self.sleep_after_panning)
# img = self.capContent()
# new_starty = self.contentHeight - (steps_to_pan_down * self.stepSizeY)
# img_next = img[new_starty:, startx:]
# logger.debug(f"img_next is {img_next.shape[1]} x {img_next.shape[0]}")
# # cv2.rectangle(img, (startx, new_starty), (self.contentWidth, self.contentHeight), (255, 0, 0), 3)
# self.addToCanvas(img_next, 0, last_add[1])
# cv2.imwrite("./test_canvas.png", self.map_canvas)
# a = 1
# logger.debug(f"{new_starty=}")
logger.debug("place to break")
x, y, w, h = cv2.boundingRect(cv2.findNonZero(cv2.threshold(self.map_canvas[:, :, 3], 230, 255, cv2.THRESH_BINARY)[1]))
# Path("./map_tiles").mkdir(exist_ok=True)
# cv2.imwrite("./map_tiles/test_canvas.png", self.map_canvas[y:h,x:w])
return self.map_canvas[y:h,x:w]
return None
+14
View File
@@ -1,6 +1,8 @@
import json
import subprocess
from pathlib import Path
import cv2
import pydantic as pyd
from .dfwindow import DFWINDOW
@@ -299,7 +301,19 @@ class WAYMONITORS:
def test5():
dfw = DFWINDOW()
# sleep_after_mouse = 0.2 # 2
# sleep_after_key = 0.08 # 08
# sleep_after_focus = 0.2 # 3
# sleep_after_panning = 0.2 # 3
dfw.sleep_after_key = 0.01
dfw.sleep_after_focus = 0.01
dfw.sleep_after_panning = 0.04
map_image = dfw.getPanoramaMap()
if map_image is not None:
Path("./map_tiles").mkdir(exist_ok=True)
cv2.imwrite("./map_tiles/test_canvas.png", map_image)
# img = dfw.capWindow()[60:-60,20:-20]
# gg = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# mm = np.mean(gg, axis=1)