balthazarneveu / interactive_pipe

create interactive image processing pipeline with friendly sliders
The Unlicense
8 stars 1 forks source link

routing mechanism shall be based on keys rather than integer indexes. #5

Closed balthazarneveu closed 1 year ago

balthazarneveu commented 1 year ago

Original description

This will allow much better comprehension when editing the output canvas Example of "outputs" modifications to change the layout. 0, 1, 2, 3 ...

But ["blended", "bnw", "exposed"] would be way easier to read

Note: Try not to break indexes as we can still access to keys by their indexes & this will allow to make generic functions aswell...

CANVAS_DICT = {
    "horizontal": [[0, 1, 2, 4]],
    "square": [[4, 1], [2, 3]],
    "sbs": [[0, None, 1]],
    "vertical": [[0], [1]],
    "complex": [[0, None, 1], [None, 2, 3]],
}
CANVAS = list(CANVAS_DICT.keys())
@interactive(
    canvas = Control(CANVAS[0], CANVAS, name="canvas")
)
def morph_canvas(canvas=CANVAS[0], global_params={}):
    global_params["__pipeline"].outputs = CANVAS_DICT[canvas]
    return None

Result

Using decorators or manually creating Filters & Pipeline, we're able to route the buffersaccording to string.

CANVAS_DICT = {
    "horizontal": [["rblended", "blended", "bnw", "exposed"]],
    "square": [["rblended", "blended"], ["bnw", "exposed"]], 
    "sbs": [["rblended", None, "img"]],
    "vertical": [["rblended"], ["img"]],
    "complex": [["rblended", None, "blended"], ["img", "bnw", "exposed"]],
}
CANVAS = list(CANVAS_DICT.keys())
@interactive(
    canvas = Control(CANVAS[0], CANVAS, name="canvas")
)
def morph_canvas(canvas=CANVAS[0], global_params={}):
    global_params["__pipeline"].outputs = CANVAS_DICT[canvas]
    return None

SANITY CHECKS (new pytests):

balthazarneveu commented 1 year ago

Example

With object oriented style filters & pipeline

no decorators used, no code inspection

from interactive_pipe.headless.pipeline import HeadlessPipeline
from interactive_pipe.core.filter import FilterCore
import cv2
import numpy as np
#-------------------------------------------------------------------------------------------------
def mad_func(img, coeff = 50, bias=0):
    mad_res = img*coeff/100.+ bias/100.
    return mad_res

#-------------------------------------------------------------------------------------------------
def black_and_white(img, bnw=False):
    return np.repeat(np.expand_dims(np.average(img, axis=-1), -1), img.shape[-1], axis=-1) if bnw else img

#-------------------------------------------------------------------------------------------------
def blend(img1, img2, blend_coeff=0.5):
    blended = blend_coeff*img1+(1-blend_coeff)*img2
    return blended

def get_sample_image():
    img = 0.5*np.ones((1, 1, 3))
    img[:, 100:, 0] *= 0.5
    img[150:, :, 2] *= 1.5
    img[:200, :, :] *= 0.5
    return img

image_in = get_sample_image()

Original indexed buffer style

   mad_filter = FilterCore(mad_func, inputs=[0], outputs=[1])
    black_and_white_filter = FilterCore(black_and_white, inputs=[1], outputs=[2])
    blend_filter = FilterCore(blend, inputs=[1, 2], outputs=[3])
    pipeline_list = [mad_filter, black_and_white_filter, blend_filter]
    pipeline = HeadlessPipeline(pipeline_list, name="pipeline indexed buffers", outputs=[0, 1, 3])
    out = pipeline(get_sample_image())
    pipeline.graph_representation(view=True)

:hankey: This used to be pretty difficult to read!

Named buffers, index inputs

You call your pipeline with pipeline(img_in, img_in_2 , ....)

    mad_filter = FilterCore(mad_func, inputs=[0], outputs=["reexposed"])
    black_and_white_filter = FilterCore(black_and_white, inputs=["reexposed"], outputs=["bnw"])
    blend_filter = FilterCore(blend, inputs=["reexposed", "bnw"], outputs=["blended"])
    pipeline_list = [mad_filter, black_and_white_filter, blend_filter]
    pipeline = HeadlessPipeline(pipeline_list, name="pipeline indexed inputs", outputs=[0, "reexposed", "blended"])
    out = pipeline(image_in)
    pipeline.graph_representation(view=True)

Fully Named buffers

You have to call your pipeline by using a dictionary. pipeline(inputs={"image_in_1": img_in, "my_special_image_2": img_in_2 , ....)

    mad_filter = FilterCore(mad_func, inputs=["my_inp"], outputs=["reexposed"])
    black_and_white_filter = FilterCore(black_and_white, inputs=["reexposed"], outputs=["bnw"])
    blend_filter = FilterCore(blend, inputs=["reexposed", "bnw"], outputs=["blended"])
    pipeline_list = [mad_filter, black_and_white_filter, blend_filter]
    pipeline = HeadlessPipeline(pipeline_list, name="pipeline with fully named buffered", outputs=["my_inp", "reexposed", "blended"])
    out = pipeline(inputs={"my_inp": image_in})
    pipeline.graph_representation(view=True)