Added histogram widget

This commit is contained in:
2025-08-02 17:12:31 +02:00
parent bc4f10a7ad
commit af2bbe93cc
5 changed files with 185 additions and 37 deletions

View File

@ -87,7 +87,7 @@ class EditorManager:
)
self.layout_manager.load_layout()
dpg.create_viewport(title="NegStation", width=800, height=600)
dpg.create_viewport(title="NegStation", width=1200, height=800)
dpg.configure_app(docking=True, docking_space=True)
with dpg.viewport_menu_bar():

View File

@ -0,0 +1,69 @@
import dearpygui.dearpygui as dpg
import numpy as np
from .pipeline_stage_widget import PipelineStageWidget
class HistogramWidget(PipelineStageWidget):
name = "Histogram"
register = True
has_pipeline_in = True
has_pipeline_out = False
def __init__(self, manager, logger):
super().__init__(manager, logger, default_stage_in="monochrome")
self.plot_tag = dpg.generate_uuid()
self.axis_x = dpg.generate_uuid()
self.axis_y = dpg.generate_uuid()
self.needs_redraw = False
self.img = None
self.series_tags = {
"R": dpg.generate_uuid(),
"G": dpg.generate_uuid(),
"B": dpg.generate_uuid(),
"L": dpg.generate_uuid(),
}
def create_pipeline_stage_content(self):
with dpg.plot(label="Histogram", height=200, width=-1, tag=self.plot_tag):
dpg.add_plot_legend()
dpg.add_plot_axis(
dpg.mvXAxis, tag=self.axis_x)
with dpg.plot_axis(dpg.mvYAxis, tag=self.axis_y):
for channel, tag in self.series_tags.items():
dpg.add_line_series([], [], label=channel, tag=tag)
dpg.set_axis_limits(self.axis_x, 0.0, 1.0)
dpg.set_axis_limits(self.axis_y, 0.0, 1.0)
def on_pipeline_data(self, img: np.ndarray):
if img is None or img.ndim != 3 or img.shape[2] < 3:
return
self.img = img
self.needs_redraw = True
def update(self):
# TODO move calculations to on_pipeline_data
if not self.needs_redraw or self.img is None:
return
self.needs_redraw = False
img = np.clip(self.img, 0.0, 1.0)
r, g, b = img[..., 0], img[..., 1], img[..., 2]
luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
bins = 64
hist_range = (0.0, 1.0)
bin_edges = np.linspace(*hist_range, bins)
def compute_hist(channel):
hist, _ = np.histogram(channel, bins=bin_edges)
x = bin_edges[:-1]
y = np.log1p(hist)
y = y / np.max(y)
return x.tolist(), y.tolist()
dpg.set_value(self.series_tags["R"], compute_hist(r))
dpg.set_value(self.series_tags["G"], compute_hist(g))
dpg.set_value(self.series_tags["B"], compute_hist(b))
dpg.set_value(self.series_tags["L"], compute_hist(luminance))

View File

@ -0,0 +1,31 @@
import dearpygui.dearpygui as dpg
import numpy as np
from .pipeline_stage_widget import PipelineStageWidget
class MonochromeStage(PipelineStageWidget):
name = "Monochrome"
register = True
has_pipeline_in = True
has_pipeline_out = True
def __init__(self, manager, logger):
super().__init__(manager, logger, default_stage_out="monochrome")
def create_pipeline_stage_content(self):
dpg.add_text("Converting to grayscale...")
def on_pipeline_data(self, img):
if img is None:
return
gray = img.copy()
rgb = gray[..., :3]
alpha = gray[..., 3:] if gray.shape[2] == 4 else np.ones_like(
rgb[..., :1])
luminance = np.dot(rgb, [0.2126, 0.7152, 0.0722])[..., np.newaxis]
gray_rgba = np.concatenate(
[luminance, luminance, luminance, alpha], axis=-1)
self.publish_stage(gray_rgba.astype(np.float32))

View File

@ -1,6 +1,6 @@
[Window][WindowOverViewport_11111111]
Pos=0,19
Size=800,581
Size=1200,781
Collapsed=0
[Window][###33]
@ -17,9 +17,9 @@ DockId=0x00000007,0
[Window][###51]
Pos=0,19
Size=244,474
Size=270,469
Collapsed=0
DockId=0x00000014,1
DockId=0x0000001F,1
[Window][###59]
Pos=0,494
@ -46,9 +46,9 @@ DockId=0x0000000E,0
[Window][###23]
Pos=0,19
Size=244,474
Size=270,469
Collapsed=0
DockId=0x00000014,0
DockId=0x0000001F,0
[Window][###29]
Pos=0,19
@ -87,45 +87,85 @@ Collapsed=0
DockId=0x00000016,0
[Window][###35]
Pos=246,19
Size=554,425
Pos=272,19
Size=710,625
Collapsed=0
DockId=0x00000011,0
[Window][###43]
Pos=0,495
Size=244,105
Pos=0,490
Size=270,154
Collapsed=0
DockId=0x00000015,0
DockId=0x00000020,0
[Window][###81]
Pos=246,446
Size=554,154
Pos=272,646
Size=710,154
Collapsed=0
DockId=0x00000010,0
[Docking][Data]
DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=800,581 Split=X
DockNode ID=0x00000009 Parent=0x7C6B3D9B SizeRef=244,581 Split=Y Selected=0x3BEDC6B0
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=196,474 Split=Y Selected=0x3BEDC6B0
DockNode ID=0x0000000D Parent=0x0000000B SizeRef=196,99 Split=Y Selected=0x99D84869
DockNode ID=0x00000012 Parent=0x0000000D SizeRef=196,423 Selected=0x0F59680E
DockNode ID=0x00000013 Parent=0x0000000D SizeRef=196,156 Split=Y Selected=0xB4AD3310
DockNode ID=0x00000014 Parent=0x00000013 SizeRef=244,474 Selected=0xB4AD3310
DockNode ID=0x00000015 Parent=0x00000013 SizeRef=244,105 Selected=0x0531B3D5
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=196,373 Selected=0x3BEDC6B0
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=196,105 Selected=0x4F81AB74
DockNode ID=0x0000000A Parent=0x7C6B3D9B SizeRef=554,581 Split=X
DockNode ID=0x00000003 Parent=0x0000000A SizeRef=299,581 Split=Y Selected=0x52849BCC
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=299,473 Split=Y Selected=0x52849BCC
DockNode ID=0x00000007 Parent=0x00000005 SizeRef=299,86 Selected=0x52849BCC
DockNode ID=0x00000008 Parent=0x00000005 SizeRef=299,385 Selected=0xBD79B41E
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=299,106 Selected=0x84DD78D1
DockNode ID=0x00000004 Parent=0x0000000A SizeRef=499,581 Split=Y
DockNode ID=0x00000001 Parent=0x00000004 SizeRef=800,379 Split=Y Selected=0x7FF1E0B5
DockNode ID=0x0000000F Parent=0x00000001 SizeRef=602,425 Split=Y Selected=0x38519A65
DockNode ID=0x00000011 Parent=0x0000000F SizeRef=554,379 CentralNode=1 Selected=0x977476CD
DockNode ID=0x00000016 Parent=0x0000000F SizeRef=554,200 Selected=0x3A881EEF
DockNode ID=0x00000010 Parent=0x00000001 SizeRef=602,154 Selected=0x083320CE
DockNode ID=0x00000002 Parent=0x00000004 SizeRef=800,200 Selected=0x1834836D
[Window][###99]
Pos=0,646
Size=270,154
Collapsed=0
DockId=0x00000015,1
[Window][###87]
Pos=0,646
Size=270,154
Collapsed=0
DockId=0x00000015,0
[Window][###111]
Pos=900,19
Size=300,781
Collapsed=0
DockId=0x0000001A,0
[Window][###96]
Pos=984,19
Size=216,781
Collapsed=0
DockId=0x0000001D,0
[Window][###127]
Pos=984,365
Size=216,435
Collapsed=0
DockId=0x0000001E,0
[Docking][Data]
DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=1200,781 Split=X
DockNode ID=0x0000001B Parent=0x7C6B3D9B SizeRef=982,781 Split=X
DockNode ID=0x00000019 Parent=0x0000001B SizeRef=898,781 Split=X
DockNode ID=0x00000017 Parent=0x00000019 SizeRef=898,781 Split=X
DockNode ID=0x00000009 Parent=0x00000017 SizeRef=270,581 Split=Y Selected=0x3BEDC6B0
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=196,474 Split=Y Selected=0x3BEDC6B0
DockNode ID=0x0000000D Parent=0x0000000B SizeRef=196,99 Split=Y Selected=0x99D84869
DockNode ID=0x00000012 Parent=0x0000000D SizeRef=196,423 Selected=0x0F59680E
DockNode ID=0x00000013 Parent=0x0000000D SizeRef=196,156 Split=Y Selected=0xB4AD3310
DockNode ID=0x00000014 Parent=0x00000013 SizeRef=244,625 Split=Y Selected=0xB4AD3310
DockNode ID=0x0000001F Parent=0x00000014 SizeRef=270,469 Selected=0xB4AD3310
DockNode ID=0x00000020 Parent=0x00000014 SizeRef=270,154 Selected=0x0531B3D5
DockNode ID=0x00000015 Parent=0x00000013 SizeRef=244,154 Selected=0x8773D56E
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=196,373 Selected=0x3BEDC6B0
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=196,105 Selected=0x4F81AB74
DockNode ID=0x0000000A Parent=0x00000017 SizeRef=710,581 Split=X
DockNode ID=0x00000003 Parent=0x0000000A SizeRef=299,581 Split=Y Selected=0x52849BCC
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=299,473 Split=Y Selected=0x52849BCC
DockNode ID=0x00000007 Parent=0x00000005 SizeRef=299,86 Selected=0x52849BCC
DockNode ID=0x00000008 Parent=0x00000005 SizeRef=299,385 Selected=0xBD79B41E
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=299,106 Selected=0x84DD78D1
DockNode ID=0x00000004 Parent=0x0000000A SizeRef=499,581 Split=Y
DockNode ID=0x00000001 Parent=0x00000004 SizeRef=800,379 Split=Y Selected=0x7FF1E0B5
DockNode ID=0x0000000F Parent=0x00000001 SizeRef=602,425 Split=Y Selected=0x38519A65
DockNode ID=0x00000011 Parent=0x0000000F SizeRef=554,379 CentralNode=1 Selected=0x977476CD
DockNode ID=0x00000016 Parent=0x0000000F SizeRef=554,200 Selected=0x3A881EEF
DockNode ID=0x00000010 Parent=0x00000001 SizeRef=602,154 Selected=0x083320CE
DockNode ID=0x00000002 Parent=0x00000004 SizeRef=800,200 Selected=0x1834836D
DockNode ID=0x00000018 Parent=0x00000019 SizeRef=300,781 Selected=0x7E9438EA
DockNode ID=0x0000001A Parent=0x0000001B SizeRef=300,781 Selected=0x7E9438EA
DockNode ID=0x0000001C Parent=0x7C6B3D9B SizeRef=216,781 Split=Y Selected=0x714F2F7B
DockNode ID=0x0000001D Parent=0x0000001C SizeRef=216,344 Selected=0x714F2F7B
DockNode ID=0x0000001E Parent=0x0000001C SizeRef=216,435 Selected=0x7740BFE4

View File

@ -18,5 +18,13 @@
{
"widget_type": "LogWindowWidget",
"config": {}
},
{
"widget_type": "MonochromeStage",
"config": {}
},
{
"widget_type": "HistogramWidget",
"config": {}
}
]