Config saving of pipeline in/out

This commit is contained in:
2025-08-03 17:16:13 +02:00
parent 9801f69d0b
commit bfb4db633d
8 changed files with 303 additions and 136 deletions

View File

@ -11,6 +11,16 @@ class ImagePipeline:
self.stagedata = {}
self.stagedata_full = {}
def load_stages(self, stages:dict):
self.stages = stages
self.stagedata.clear()
self.stagedata_full.clear()
self.id_counter = len(stages)
for id, stage in self.stages.items():
print(id, stage)
self.stagedata[id] = None
self.stagedata_full[id] = None
def register_stage(self, name: str):
self.stages[self.id_counter] = name
self.stagedata[self.id_counter] = None
@ -37,13 +47,19 @@ class ImagePipeline:
"pipeline_stage", (id, self.stagedata[id]))
def get_stage_data(self, id: int):
if id >= 0 and id < len(self.stages):
if id in self.stagedata:
return self.stagedata[id]
else:
return None
def get_stage_data_full(self, id: int):
if id in self.stagedata_full:
return self.stagedata_full[id]
else:
return None
def get_stage_name(self, id: int):
if id >= 0 and id < len(self.stages):
if id in self.stages:
return self.stages[id]
else:
return None

View File

@ -20,12 +20,15 @@ class LayoutManager:
def save_layout(self):
self.logger.info("Saving layout...")
dpg.save_init_file(self.INI_PATH)
widget_data = [
{"widget_type": type(w).__name__, "config": w.get_config()}
for w in self.manager.widgets
]
layout_data = {
"pipeline_order" : { k:v for k, v in self.manager.pipeline.stages.items() },
"widgets": [
{"widget_type": type(w).__name__, "config": w.get_config()}
for w in self.manager.widgets
]
}
with open(self.WIDGET_DATA_PATH, "w") as f:
json.dump(widget_data, f, indent=4)
json.dump(layout_data, f, indent=4)
self.logger.info("Layout saved successfully.")
def load_layout(self):
@ -33,10 +36,17 @@ class LayoutManager:
if not os.path.exists(self.WIDGET_DATA_PATH):
return
with open(self.WIDGET_DATA_PATH, "r") as f:
widget_data = json.load(f)
layout_data = json.load(f)
# Load all widgets
widget_data = layout_data["widgets"]
for data in widget_data:
if data.get("widget_type") in self.manager.widget_classes:
self.manager._add_widget(widget_type=data.get("widget_type"))
self.manager._add_widget(widget_type=data.get("widget_type"), config=data.get("config"))
# Reset the image pipeline and reload it
pipelinestages = { int(k):v for k, v in layout_data["pipeline_order"].items() }
self.manager.pipeline.load_stages(pipelinestages)
if os.path.exists(self.INI_PATH):
dpg.configure_app(init_file=self.INI_PATH)

View File

@ -74,12 +74,13 @@ class EditorManager:
f"Widget '{name}' is already registered. Overwriting.")
self.widget_classes[name] = widget_class
def _add_widget(self, widget_type: str):
def _add_widget(self, widget_type: str, config:dict = {}):
WidgetClass = self.widget_classes[widget_type]
instance = WidgetClass(self, logger)
logger.info(f'Created instance: {str(instance)}')
self.widgets.append(instance)
instance.create()
instance.set_config(config)
def setup(self):
self._discover_and_register_widgets(

View File

@ -63,6 +63,10 @@ class BaseWidget:
def get_config(self):
"""Caled by negstation itself, returns the saved widget config"""
return self.config
def set_config(self, config):
"""Called by negstation itself but can be overridden by a widget"""
self.config = config
# Callbacks

View File

@ -21,7 +21,7 @@ class OpenRawWidget(PipelineStageWidget):
self.raw_path = None
self.img = None
self.img_full = None
self.config = {
self.rawconfig = {
# Demosaic algorithm
"demosaic_algorithm": rawpy.DemosaicAlgorithm.AHD,
# Output color space
@ -45,9 +45,6 @@ class OpenRawWidget(PipelineStageWidget):
self.manager.bus.subscribe(
"process_full_res", self._on_process_full_res, True)
def get_config(self):
return {}
def create_pipeline_stage_content(self):
with dpg.file_dialog(
directory_selector=False,
@ -73,79 +70,79 @@ class OpenRawWidget(PipelineStageWidget):
label="Demosaic",
items=[alg.name for alg in rawpy.DemosaicAlgorithm],
default_value=rawpy.DemosaicAlgorithm.AHD.name,
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"demosaic_algorithm", rawpy.DemosaicAlgorithm[a])
)
dpg.add_combo(
label="Color Space",
items=[cs.name for cs in rawpy.ColorSpace],
default_value=rawpy.ColorSpace.sRGB.name,
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"output_color", rawpy.ColorSpace[a])
)
dpg.add_combo(
label="Output Bits",
items=["8", "16"],
default_value="16",
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"output_bps", int(a))
)
dpg.add_checkbox(
label="Use Camera WB",
default_value=True,
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"use_camera_wb", a)
)
dpg.add_checkbox(
label="Auto WB",
default_value=False,
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"use_auto_wb", a)
)
dpg.add_slider_float(
label="Manual WB R Gain",
default_value=1.0, min_value=0.1, max_value=4.0,
callback=lambda s, a, u: self.config.__setitem__(
"user_wb", (a, self.config["user_wb"][1], self.config["user_wb"][2], self.config["user_wb"][3]))
"user_wb", (a, self.rawconfig["user_wb"][1], self.rawconfig["user_wb"][2], self.rawconfig["user_wb"][3]))
)
dpg.add_slider_float(
label="Manual WB G Gain",
default_value=1.0, min_value=0.1, max_value=4.0,
callback=lambda s, a, u: self.config.__setitem__(
"user_wb", (self.config["user_wb"][0], a, a, self.config["user_wb"][3]))
"user_wb", (self.rawconfig["user_wb"][0], a, a, self.rawconfig["user_wb"][3]))
)
dpg.add_slider_float(
label="Manual WB B Gain",
default_value=1.0, min_value=0.1, max_value=4.0,
callback=lambda s, a, u: self.config.__setitem__(
"user_wb", (self.config["user_wb"][0], self.config["user_wb"][1], self.config["user_wb"][2], a))
"user_wb", (self.rawconfig["user_wb"][0], self.rawconfig["user_wb"][1], self.rawconfig["user_wb"][2], a))
)
dpg.add_slider_float(
label="Bright",
default_value=1.0, min_value=0.1, max_value=4.0,
callback=lambda s, a, u: self.config.__setitem__("bright", a)
callback=lambda s, a, u: self.rawconfig.__setitem__("bright", a)
)
dpg.add_checkbox(
label="No Auto Bright",
default_value=False,
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"no_auto_bright", a)
)
dpg.add_slider_float(
label="Gamma",
default_value=1.0, min_value=0.1, max_value=3.0,
callback=lambda s, a, u: self.config.__setitem__("gamma", a)
callback=lambda s, a, u: self.rawconfig.__setitem__("gamma", a)
)
dpg.add_checkbox(
label="Half-size",
default_value=False,
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"half_size", a)
)
dpg.add_checkbox(
label="4-color RGB",
default_value=False,
callback=lambda s, a, u: self.config.__setitem__(
callback=lambda s, a, u: self.rawconfig.__setitem__(
"four_color_rgb", a)
)
@ -179,28 +176,28 @@ class OpenRawWidget(PipelineStageWidget):
with rawpy.imread(self.raw_path) as raw:
# Prepare postprocess kwargs from config
postprocess_args = {
'demosaic_algorithm': self.config["demosaic_algorithm"],
'output_color': self.config["output_color"],
'output_bps': self.config["output_bps"],
'bright': self.config["bright"],
'no_auto_bright': self.config["no_auto_bright"],
'gamma': (1.0, self.config["gamma"]),
'half_size': self.config["half_size"],
'four_color_rgb': self.config["four_color_rgb"],
'demosaic_algorithm': self.rawconfig["demosaic_algorithm"],
'output_color': self.rawconfig["output_color"],
'output_bps': self.rawconfig["output_bps"],
'bright': self.rawconfig["bright"],
'no_auto_bright': self.rawconfig["no_auto_bright"],
'gamma': (1.0, self.rawconfig["gamma"]),
'half_size': self.rawconfig["half_size"],
'four_color_rgb': self.rawconfig["four_color_rgb"],
}
if self.config["use_camera_wb"]:
if self.rawconfig["use_camera_wb"]:
postprocess_args['use_camera_wb'] = True
elif self.config["use_auto_wb"]:
elif self.rawconfig["use_auto_wb"]:
postprocess_args['use_auto_wb'] = True
else:
postprocess_args['user_wb'] = self.config["user_wb"]
postprocess_args['user_wb'] = self.rawconfig["user_wb"]
# Postprocess into RGB
rgb = raw.postprocess(**postprocess_args)
# Normalize to float32 in 0.0-1.0 range depending on output_bps
max_val = (2 ** self.config["output_bps"]) - 1
max_val = (2 ** self.rawconfig["output_bps"]) - 1
rgb_float = rgb.astype(np.float32) / max_val
# Add alpha channel (fully opaque)

View File

@ -23,6 +23,7 @@ class PipelineStageWidget(BaseWidget):
self.pipeline_stage_out_id = None
self.pipeline_config_group_tag = dpg.generate_uuid()
self.stage_in_combo = dpg.generate_uuid()
self.stage_out_input = dpg.generate_uuid()
self._last_full = False
if self.has_pipeline_out:
@ -30,14 +31,13 @@ class PipelineStageWidget(BaseWidget):
default_stage_out
)
self.manager.bus.subscribe(
"pipeline_stages", self._on_stage_list, True)
self.manager.bus.subscribe("pipeline_stages", self._on_stage_list, True)
if self.has_pipeline_in:
self.pipeline_stage_in_id = 0
self.manager.bus.subscribe("pipeline_stage", self._on_stage_data, True)
self.manager.bus.subscribe(
"pipeline_stage", self._on_stage_data, True)
self.manager.bus.subscribe(
"pipeline_stage_full", self._on_stage_data_full, True)
"pipeline_stage_full", self._on_stage_data_full, True
)
# force getting all available pipeline stages
self.manager.pipeline.republish_stages()
@ -50,7 +50,7 @@ class PipelineStageWidget(BaseWidget):
callback=self._on_stage_in_select,
default_value=f"{
self.manager.pipeline.get_stage_name(0)} : 0",
tag=self.stage_in_combo
tag=self.stage_in_combo,
)
if self.has_pipeline_out:
dpg.add_input_text(
@ -61,6 +61,7 @@ class PipelineStageWidget(BaseWidget):
callback=lambda s, a, u: self.manager.pipeline.rename_stage(
self.pipeline_stage_out_id, a
),
tag=self.stage_out_input,
)
dpg.add_separator()
self.create_pipeline_stage_content()
@ -77,7 +78,58 @@ class PipelineStageWidget(BaseWidget):
"""Publishes an image to output stage"""
if self.has_pipeline_out:
self.manager.pipeline.publish(
self.pipeline_stage_out_id, img, full_res=self._last_full)
self.pipeline_stage_out_id, img, full_res=self._last_full
)
def get_config(self):
return {
"pipeline_config": {
"stage_in": self.pipeline_stage_in_id,
"stage_out": self.pipeline_stage_out_id,
}
}
def set_config(self, config):
# Set pipelinedata
if "pipeline_config" in config:
if self.has_pipeline_in:
self.pipeline_stage_in_id = config["pipeline_config"]["stage_in"]
if self.has_pipeline_out:
self.pipeline_stage_out_id = config["pipeline_config"]["stage_out"]
self._update_ui_from_state()
def _update_ui_from_state(self):
"""
Refresh the Stage In combo (and Stage Out input) so
that:
1. its items list matches the current pipeline stages, and
2. its displayed value matches the saved ID.
"""
# --- Build the ordered list of "name : id" labels ---
ordered = sorted(self.manager.pipeline.stages.items(), key=lambda kv: kv[0])
labels = [f"{name} : {sid}" for sid, name in ordered]
# --- Update Stage In combo ---
if self.has_pipeline_in:
dpg.configure_item(self.stage_in_combo, items=labels)
# set the combo's value if the saved ID still exists
sid = self.pipeline_stage_in_id
if sid in self.manager.pipeline.stages:
name = self.manager.pipeline.get_stage_name(sid)
dpg.set_value(self.stage_in_combo, f"{name} : {sid}")
else:
# clear if it no longer exists
dpg.set_value(self.stage_in_combo, "")
# --- Update Stage Out input text ---
if self.has_pipeline_out:
# show the stage name (without ID) or blank if missing
sid = self.pipeline_stage_out_id
if sid in self.manager.pipeline.stages:
name = self.manager.pipeline.get_stage_name(sid)
dpg.set_value(self.stage_out_input, name)
else:
dpg.set_value(self.stage_out_input, "")
# Callbacks
@ -88,8 +140,7 @@ class PipelineStageWidget(BaseWidget):
def _on_stage_list(self, stagelist):
if self.has_pipeline_in:
stages = [f"{stage} : {id}" for id, stage in stagelist.items()]
dpg.configure_item(self.stage_in_combo, items=stages)
self._update_ui_from_state()
def _on_stage_in_select(self, sender, selected_stage: str):
d = selected_stage.split(" : ")
@ -121,8 +172,7 @@ class PipelineStageWidget(BaseWidget):
def _on_window_resize(self, data):
win_w, win_h = dpg.get_item_rect_size(self.window_tag)
group_w, group_h = dpg.get_item_rect_size(
self.pipeline_config_group_tag)
group_w, group_h = dpg.get_item_rect_size(self.pipeline_config_group_tag)
group_x, group_y = dpg.get_item_pos(self.pipeline_config_group_tag)
self.window_height = win_h - group_h - group_y - 12
self.window_width = win_w - 7

View File

@ -19,7 +19,7 @@ DockId=0x00000007,0
Pos=0,19
Size=270,469
Collapsed=0
DockId=0x0000001F,1
DockId=0x00000035,1
[Window][###59]
Pos=0,494
@ -46,9 +46,9 @@ DockId=0x0000000E,0
[Window][###23]
Pos=0,19
Size=270,469
Size=270,567
Collapsed=0
DockId=0x0000001F,0
DockId=0x00000035,0
[Window][###29]
Pos=0,19
@ -60,7 +60,7 @@ DockId=0x00000012,0
Pos=198,19
Size=602,425
Collapsed=0
DockId=0x0000000F,0
DockId=0x00000033,0
[Window][###49]
Pos=0,495
@ -72,7 +72,7 @@ DockId=0x0000000C,0
Pos=246,19
Size=554,379
Collapsed=0
DockId=0x0000000F,0
DockId=0x00000033,0
[Window][###60]
Pos=0,19
@ -88,9 +88,9 @@ DockId=0x00000011,0
[Window][###35]
Pos=272,19
Size=710,625
Size=710,580
Collapsed=0
DockId=0x0000000F,0
DockId=0x00000033,0
[Window][###43]
Pos=0,490
@ -170,50 +170,96 @@ Size=261,245
Collapsed=0
DockId=0x00000016,0
[Docking][Data]
DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=1200,781 Split=X
DockNode ID=0x0000002B Parent=0x7C6B3D9B SizeRef=937,781 Split=X
DockNode ID=0x00000027 Parent=0x0000002B SizeRef=982,781 Split=X
DockNode ID=0x00000023 Parent=0x00000027 SizeRef=982,781 Split=X
DockNode ID=0x0000001B Parent=0x00000023 SizeRef=982,781 Split=X
DockNode ID=0x00000017 Parent=0x0000001B 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=665,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 CentralNode=1 Selected=0x977476CD
DockNode ID=0x00000010 Parent=0x00000001 SizeRef=602,154 Selected=0x083320CE
DockNode ID=0x00000002 Parent=0x00000004 SizeRef=800,200 Selected=0x1834836D
DockNode ID=0x00000018 Parent=0x0000001B SizeRef=300,781 Selected=0x7E9438EA
DockNode ID=0x0000001C Parent=0x00000023 SizeRef=216,781 Split=Y Selected=0x714F2F7B
DockNode ID=0x0000001D Parent=0x0000001C SizeRef=216,344 Split=Y Selected=0x714F2F7B
DockNode ID=0x00000021 Parent=0x0000001D SizeRef=216,579 Split=Y Selected=0x714F2F7B
DockNode ID=0x00000019 Parent=0x00000021 SizeRef=216,391 Selected=0x714F2F7B
DockNode ID=0x0000001A Parent=0x00000021 SizeRef=216,388 Selected=0x7E9438EA
DockNode ID=0x00000022 Parent=0x0000001D SizeRef=216,200 Selected=0x0D80EC84
DockNode ID=0x0000001E Parent=0x0000001C SizeRef=216,435 Selected=0x7740BFE4
DockNode ID=0x00000024 Parent=0x00000027 SizeRef=216,781 Split=Y Selected=0xCF08B82F
DockNode ID=0x00000025 Parent=0x00000024 SizeRef=216,579 Selected=0xCF08B82F
DockNode ID=0x00000026 Parent=0x00000024 SizeRef=216,200 Selected=0x032CD220
DockNode ID=0x00000028 Parent=0x0000002B SizeRef=216,781 Split=Y Selected=0xB5C8EB4F
DockNode ID=0x00000029 Parent=0x00000028 SizeRef=216,609 Selected=0xB5C8EB4F
DockNode ID=0x0000002A Parent=0x00000028 SizeRef=216,170 Selected=0xF8004A44
DockNode ID=0x0000002C Parent=0x7C6B3D9B SizeRef=261,781 Split=Y Selected=0xC8700185
DockNode ID=0x00000011 Parent=0x0000002C SizeRef=142,534 Selected=0x3A881EEF
DockNode ID=0x00000016 Parent=0x0000002C SizeRef=142,245 Selected=0xC8700185
[Window][###97]
Pos=984,19
Size=216,560
Collapsed=0
DockId=0x0000002F,0
[Window][###113]
Pos=984,581
Size=216,219
Collapsed=0
DockId=0x00000030,0
[Window][###44]
Pos=0,588
Size=270,105
Collapsed=0
DockId=0x00000036,0
[Window][###52]
Pos=0,19
Size=270,567
Collapsed=0
DockId=0x00000035,1
[Window][###82]
Pos=272,601
Size=710,199
Collapsed=0
DockId=0x00000034,0
[Window][###88]
Pos=0,695
Size=270,105
Collapsed=0
DockId=0x00000032,0
[Docking][Data]
DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,19 Size=1200,781 Split=X
DockNode ID=0x0000002D Parent=0x7C6B3D9B SizeRef=982,781 Split=X
DockNode ID=0x0000002B Parent=0x0000002D SizeRef=937,781 Split=X
DockNode ID=0x00000027 Parent=0x0000002B SizeRef=982,781 Split=X
DockNode ID=0x00000023 Parent=0x00000027 SizeRef=982,781 Split=X
DockNode ID=0x0000001B Parent=0x00000023 SizeRef=982,781 Split=X
DockNode ID=0x00000017 Parent=0x0000001B 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 Split=Y Selected=0xD36850C8
DockNode ID=0x00000031 Parent=0x0000001F SizeRef=270,674 Split=Y Selected=0xF30D49C0
DockNode ID=0x00000035 Parent=0x00000031 SizeRef=270,567 Selected=0xF30D49C0
DockNode ID=0x00000036 Parent=0x00000031 SizeRef=270,105 Selected=0xB7116FC5
DockNode ID=0x00000032 Parent=0x0000001F SizeRef=270,105 Selected=0x052342BF
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=665,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=0x977476CD
DockNode ID=0x00000033 Parent=0x0000000F SizeRef=710,580 CentralNode=1 Selected=0x977476CD
DockNode ID=0x00000034 Parent=0x0000000F SizeRef=710,199 Selected=0x4F935A1E
DockNode ID=0x00000010 Parent=0x00000001 SizeRef=602,154 Selected=0x083320CE
DockNode ID=0x00000002 Parent=0x00000004 SizeRef=800,200 Selected=0x1834836D
DockNode ID=0x00000018 Parent=0x0000001B SizeRef=300,781 Selected=0x7E9438EA
DockNode ID=0x0000001C Parent=0x00000023 SizeRef=216,781 Split=Y Selected=0x714F2F7B
DockNode ID=0x0000001D Parent=0x0000001C SizeRef=216,344 Split=Y Selected=0x714F2F7B
DockNode ID=0x00000021 Parent=0x0000001D SizeRef=216,579 Split=Y Selected=0x714F2F7B
DockNode ID=0x00000019 Parent=0x00000021 SizeRef=216,391 Selected=0x714F2F7B
DockNode ID=0x0000001A Parent=0x00000021 SizeRef=216,388 Selected=0x7E9438EA
DockNode ID=0x00000022 Parent=0x0000001D SizeRef=216,200 Selected=0x0D80EC84
DockNode ID=0x0000001E Parent=0x0000001C SizeRef=216,435 Selected=0x7740BFE4
DockNode ID=0x00000024 Parent=0x00000027 SizeRef=216,781 Split=Y Selected=0xCF08B82F
DockNode ID=0x00000025 Parent=0x00000024 SizeRef=216,579 Selected=0xCF08B82F
DockNode ID=0x00000026 Parent=0x00000024 SizeRef=216,200 Selected=0x032CD220
DockNode ID=0x00000028 Parent=0x0000002B SizeRef=216,781 Split=Y Selected=0xB5C8EB4F
DockNode ID=0x00000029 Parent=0x00000028 SizeRef=216,609 Selected=0xB5C8EB4F
DockNode ID=0x0000002A Parent=0x00000028 SizeRef=216,170 Selected=0xF8004A44
DockNode ID=0x0000002C Parent=0x0000002D SizeRef=261,781 Split=Y Selected=0xC8700185
DockNode ID=0x00000011 Parent=0x0000002C SizeRef=142,534 Selected=0x3A881EEF
DockNode ID=0x00000016 Parent=0x0000002C SizeRef=142,245 Selected=0xC8700185
DockNode ID=0x0000002E Parent=0x7C6B3D9B SizeRef=216,781 Split=Y Selected=0x4C2F06CB
DockNode ID=0x0000002F Parent=0x0000002E SizeRef=216,560 Selected=0x4C2F06CB
DockNode ID=0x00000030 Parent=0x0000002E SizeRef=216,219 Selected=0x04546B8A

View File

@ -1,34 +1,77 @@
[
{
"widget_type": "OpenImageWidget",
"config": {}
{
"pipeline_order": {
"0": "opened_image",
"1": "inverted_image",
"2": "opened_raw",
"3": "monochrome"
},
{
"widget_type": "PipelineStageViewer",
"config": {}
},
{
"widget_type": "InvertStage",
"config": {}
},
{
"widget_type": "OpenRawWidget",
"config": {}
},
{
"widget_type": "LogWindowWidget",
"config": {}
},
{
"widget_type": "MonochromeStage",
"config": {}
},
{
"widget_type": "HistogramWidget",
"config": {}
},
{
"widget_type": "ExportStage",
"config": {}
}
]
"widgets": [
{
"widget_type": "OpenImageWidget",
"config": {
"pipeline_config": {
"stage_in": null,
"stage_out": 0
}
}
},
{
"widget_type": "PipelineStageViewer",
"config": {
"pipeline_config": {
"stage_in": 3,
"stage_out": null
}
}
},
{
"widget_type": "InvertStage",
"config": {
"pipeline_config": {
"stage_in": 2,
"stage_out": 1
}
}
},
{
"widget_type": "OpenRawWidget",
"config": {
"pipeline_config": {
"stage_in": null,
"stage_out": 2
}
}
},
{
"widget_type": "LogWindowWidget",
"config": {}
},
{
"widget_type": "MonochromeStage",
"config": {
"pipeline_config": {
"stage_in": 1,
"stage_out": 3
}
}
},
{
"widget_type": "HistogramWidget",
"config": {
"pipeline_config": {
"stage_in": 3,
"stage_out": null
}
}
},
{
"widget_type": "ExportStage",
"config": {
"pipeline_config": {
"stage_in": 3,
"stage_out": null
}
}
}
]
}