Place pins arbitrarily (not just image corners)

This commit is contained in:
Ruben van de Ven 2024-11-08 18:14:14 +01:00
parent 12349dfd55
commit 348a96b12c
2 changed files with 31 additions and 21 deletions

View file

@ -29,7 +29,7 @@ def on_key_press(symbol, modifiers):
exit() exit()
pins = PygletCornerPin(window) pins = PygletCornerPin(window, source_points=[[100,100], [700,100], [100,500], [300,300]])
# event handlers for dragging: # event handlers for dragging:
window.push_handlers(pins) window.push_handlers(pins)

View file

@ -11,6 +11,7 @@ incidently so won't really hurt performance.
import pyglet import pyglet
from typing import Optional from typing import Optional
import logging import logging
import copy
def adj(m): # Compute the adjugate of m def adj(m): # Compute the adjugate of m
return [ return [
@ -63,8 +64,17 @@ def general2DProjection(
d = basisToPoints(x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d) d = basisToPoints(x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d)
return multmm(d, adj(s)) return multmm(d, adj(s))
def transform2d(w, h, x1, y1, x2, y2, x3, y3, x4, y4): def transform2d_wh(w, h, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d):
t = general2DProjection(0, 0, x1, y1, w, 0, x2, y2, 0, h, x3, y3, w, h, x4, y4) """
Transform the image corners based on width and height of the image
"""
return transform2d(0, 0, x1d, y1d, w, 0, x2d, y2d, 0, h, x3d, y3d, w, h, x4d, y4d)
def transform2d(x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d):
"""
Transform the image based on 4 arbitrarily placed pins
"""
t = general2DProjection(x1s, y1s, x1d, y1d, x2s, y2s, x2d, y2d, x3s, y3s, x3d, y3d, x4s, y4s, x4d, y4d)
for i in range(9): for i in range(9):
t[i] = t[i] / t[8] t[i] = t[i] / t[8]
@ -77,7 +87,7 @@ def transform2d(w, h, x1, y1, x2, y2, x3, y3, x4, y4):
# Below are all pyglet specific functions # Below are all pyglet specific functions
class PygletCornerPin(pyglet.event.EventDispatcher): class PygletCornerPin(pyglet.event.EventDispatcher):
def __init__(self, window: pyglet.window.Window, corners: Optional[list[list[float]]] = None) -> None: def __init__(self, window: pyglet.window.Window, corners: Optional[list[list[float]]] = None, source_points: Optional[list[list[float]]] = None) -> None:
""" """
Creates CornerPin utility for a given Pyglet window. If not given, corners default to the Creates CornerPin utility for a given Pyglet window. If not given, corners default to the
bottom left, bottom right, top left, top right corners of the window (i.e. no transform) bottom left, bottom right, top left, top right corners of the window (i.e. no transform)
@ -85,21 +95,23 @@ class PygletCornerPin(pyglet.event.EventDispatcher):
Do not forget to register event handlers by running `window.register_handlers(pins)`. Do not forget to register event handlers by running `window.register_handlers(pins)`.
""" """
self.window = window self.window = window
self.corners = corners if corners else [ self.source_points = source_points if source_points else [
[0, 0], [0, 0],
[self.window.width, 0], [self.window.width, 0],
[0, self.window.height], [0, self.window.height],
[self.window.width, self.window.height], [self.window.width, self.window.height],
] ]
self.pin_positions = corners if corners else copy.deepcopy(self.source_points)
self.batch = pyglet.graphics.Batch() self.batch = pyglet.graphics.Batch()
self.dragging: Optional[int] = None self.dragging: Optional[int] = None
self.handles = [ self.handles = [
pyglet.shapes.Arc(c[0],c[1],20, thickness=2, color=(0,0,255,255), batch=self.batch) for c in self.corners pyglet.shapes.Arc(c[0],c[1],20, thickness=2, color=(0,0,255,255), batch=self.batch) for c in self.pin_positions
] ]
self.current_corner = None self.current_corner = None
def update_handles(self): def update_handles(self):
for i, c in enumerate(self.corners): for i, c in enumerate(self.pin_positions):
self.handles[i].x = c[0] self.handles[i].x = c[0]
self.handles[i].y = c[1] self.handles[i].y = c[1]
@ -109,14 +121,12 @@ class PygletCornerPin(pyglet.event.EventDispatcher):
""" """
self.batch.draw() self.batch.draw()
def transform2d_matrix(self, x1, y1, x2, y2, x3, y3, x4, y4): def transform2d_matrix(self,x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d):
""" """
Calculate the transform matrix Calculate the transform matrix
""" """
t = transform2d( t = transform2d(
self.window.width, x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s, x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d)
self.window.height,
x1, y1, x2, y2, x3, y3, x4, y4 )
return pyglet.math.Mat4(t) return pyglet.math.Mat4(t)
# event handlers # event handlers
@ -126,8 +136,8 @@ class PygletCornerPin(pyglet.event.EventDispatcher):
currentcorner = None currentcorner = None
dist = r * r dist = r * r
for i in range(4): for i in range(4):
dx = x - self.corners[i][0] dx = x - self.pin_positions[i][0]
dy = y - self.corners[i][1] dy = y - self.pin_positions[i][1]
if dist > dx**2 + dy ** 2: if dist > dx**2 + dy ** 2:
dist = dx**2 + dy ** 2 dist = dx**2 + dy ** 2
currentcorner = i currentcorner = i
@ -139,15 +149,15 @@ class PygletCornerPin(pyglet.event.EventDispatcher):
if self.dragging is None: if self.dragging is None:
return pyglet.event.EVENT_UNHANDLED return pyglet.event.EVENT_UNHANDLED
self.dragging = None self.dragging = None
logging.debug(f"Corner pins set to {self.corners}") logging.debug(f"Corner pins set to {self.pin_positions}")
return pyglet.event.EVENT_HANDLED return pyglet.event.EVENT_HANDLED
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
if self.dragging is None: if self.dragging is None:
return pyglet.event.EVENT_UNHANDLED return pyglet.event.EVENT_UNHANDLED
self.corners[self.dragging][0] = x self.pin_positions[self.dragging][0] = x
self.corners[self.dragging][1] = y self.pin_positions[self.dragging][1] = y
self.update_view() self.update_view()
def on_key_release(self, symbol: int, modifiers: int): def on_key_release(self, symbol: int, modifiers: int):
@ -186,15 +196,15 @@ class PygletCornerPin(pyglet.event.EventDispatcher):
base *= 2 base *= 2
if symbol == pyglet.window.key.RIGHT: if symbol == pyglet.window.key.RIGHT:
self.corners[self.current_corner][0] += base self.pin_positions[self.current_corner][0] += base
if symbol == pyglet.window.key.LEFT: if symbol == pyglet.window.key.LEFT:
self.corners[self.current_corner][0] -= base self.pin_positions[self.current_corner][0] -= base
if symbol == pyglet.window.key.UP: if symbol == pyglet.window.key.UP:
self.corners[self.current_corner][1] += base self.pin_positions[self.current_corner][1] += base
if symbol == pyglet.window.key.DOWN: if symbol == pyglet.window.key.DOWN:
self.corners[self.current_corner][1] -= base self.pin_positions[self.current_corner][1] -= base
self.update_view() self.update_view()
def update_view(self): def update_view(self):
self.window.view = self.transform2d_matrix(*[x for c in self.corners for x in c]) self.window.view = self.transform2d_matrix(*[x for c in self.source_points for x in c], *[x for c in self.pin_positions for x in c])