Start of crop widget
This commit is contained in:
85
negstation/widgets/crop_widget.py
Normal file
85
negstation/widgets/crop_widget.py
Normal file
@ -0,0 +1,85 @@
|
||||
import dearpygui.dearpygui as dpg
|
||||
import numpy as np
|
||||
from .stage_viewer_widget import PipelineStageViewer
|
||||
|
||||
|
||||
class CropWidget(PipelineStageViewer):
|
||||
name = "Crop Image"
|
||||
register = True
|
||||
has_pipeline_in = True
|
||||
has_pipeline_out = True
|
||||
|
||||
def __init__(self, manager, logger):
|
||||
super().__init__(manager, logger)
|
||||
self.crop_start = None # (x, y)
|
||||
self.crop_end = None # (x, y)
|
||||
self.crop_active = False
|
||||
|
||||
self.manager.bus.subscribe("img_clicked", self.on_click)
|
||||
self.manager.bus.subscribe("img_dragged", self.on_drag)
|
||||
|
||||
def create_pipeline_stage_content(self):
|
||||
super().create_pipeline_stage_content()
|
||||
|
||||
# def on_full_res_pipeline_data(self, img):
|
||||
# pass
|
||||
|
||||
def on_pipeline_data(self, img):
|
||||
if img is None:
|
||||
return
|
||||
self.img = img
|
||||
|
||||
if self.crop_start and self.crop_end:
|
||||
x0, y0 = self.crop_start
|
||||
x1, y1 = self.crop_end
|
||||
x0, x1 = sorted((int(x0), int(x1)))
|
||||
y0, y1 = sorted((int(y0), int(y1)))
|
||||
|
||||
x0 = max(0, min(x0, img.shape[1]-1))
|
||||
x1 = max(0, min(x1, img.shape[1]-1))
|
||||
y0 = max(0, min(y0, img.shape[0]-1))
|
||||
y1 = max(0, min(y1, img.shape[0]-1))
|
||||
|
||||
cropped = img[y0:y1, x0:x1, :]
|
||||
self.publish_stage(cropped)
|
||||
else:
|
||||
self.publish_stage(img)
|
||||
|
||||
self.needs_update = True
|
||||
|
||||
def on_click(self, data):
|
||||
if data["obj"] is not self:
|
||||
return
|
||||
if data["button"] == "left":
|
||||
self.crop_start = data["pos"]
|
||||
self.crop_end = data["pos"]
|
||||
self.crop_active = True
|
||||
self.needs_update = True
|
||||
|
||||
def on_drag(self, data):
|
||||
if data["obj"] is not self or not self.crop_active:
|
||||
return
|
||||
self.crop_end = data["pos"]
|
||||
self.needs_update = True
|
||||
|
||||
def update_texture(self, img):
|
||||
super().update_texture(img)
|
||||
if self.crop_start and self.crop_end:
|
||||
# map image coords back to screen coords
|
||||
x0, y0 = self.crop_start
|
||||
x1, y1 = self.crop_end
|
||||
h, w, _ = self.img.shape
|
||||
img_x, img_y = self.image_position
|
||||
img_w, img_h = self.scaled_size
|
||||
|
||||
p0 = (
|
||||
img_x + x0 / w * img_w,
|
||||
img_y + y0 / h * img_h
|
||||
)
|
||||
p1 = (
|
||||
img_x + x1 / w * img_w,
|
||||
img_y + y1 / h * img_h
|
||||
)
|
||||
|
||||
dpg.draw_rectangle(pmin=p0, pmax=p1, color=(255, 255, 0, 255),
|
||||
fill=(255, 255, 0, 50), thickness=2, parent=self.drawlist)
|
Reference in New Issue
Block a user