Skip to content

Commit

Permalink
Auto resize to the input image's resolution or force a component and …
Browse files Browse the repository at this point in the history
…adjust the other
  • Loading branch information
Tremeschin committed Mar 28, 2024
1 parent e5d7adb commit a75ba5e
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 38 deletions.
78 changes: 45 additions & 33 deletions DepthFlow/DepthFlow.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from typer import Option

from Broken.Base import BrokenThread
from Broken.Loaders.LoaderPIL import LoadableImage, LoaderImage
from Broken.Loaders.LoaderPIL import LoaderImage
from DepthFlow import DEPTHFLOW


Expand All @@ -31,53 +31,52 @@ class DepthFlowScene(ShaderScene):
# DepthFlow objects
mde: Monocular = field(factory=Monocular)

# Parallax parameters
parallax_fixed = field(default=True)
parallax_height = field(default=0.2)
parallax_focus = field(default=1.0)
parallax_zoom = field(default=1.0)
parallax_isometric = field(default=0.0)
parallax_dolly = field(default=0.0)
parallax_x = field(default=0.0)
parallax_y = field(default=0.0)

# ------------------------------------------|
# Parallax MDE and Loading screen tricky implementation

_loading: Thread = None
_load_image: Image = None
_load_depth: Image = None

def parallax(self,
image: LoadableImage,
depth: LoadableImage=None,
cache: bool=True
):
self._load_image = LoaderImage(image)
self._load_depth = LoaderImage(depth) or self.mde(image, cache=cache)

def input(self,
image: Annotated[str, Option("--image", "-i", help="Image to parallax (path, url)")],
depth: Annotated[str, Option("--depth", "-d", help="Depth map of the Image, None to estimate")]=None,
cache: Annotated[bool, Option("--cache", "-c", help="Cache the Depth Map estimations")]=True,
block: Annotated[bool, Option("--block", "-b", help="Freeze until Depth Map is estimated, no loading screen")]=False
image: Annotated[str, Option("--image", "-i", help="Image to parallax (Path, URL, NumPy, PIL)")],
depth: Annotated[str, Option("--depth", "-d", help="Depth map of the Image, None to estimate")]=None,
cache: Annotated[bool, Option("--cache", "-c", help="Cache the Depth Map estimations")]=True,
width: Annotated[int, Option("--width", "-w", help="Final video Width, None for the Image's one. Adjusts to Aspect Ratio")]=None,
height: Annotated[int, Option("--height", "-h", help="Final video Height, None for the Image's one. Adjusts to Aspect Ratio")]=None,
scale: Annotated[float, Option("--scale", "-s", help="Premultiply the Image resolution by a factor")]=1.0,
block: Annotated[bool, Option("--block", "-b", help="Freeze until Depth Map is estimated, no loading screen")]=False
):
"""
Load a new parallax image and depth map. If depth is None, it will be estimated.
• If block is True, the function will wait until the images are loaded (implied on rendering)
"""
# Already loading something
if self._loading and not block:
return

def load():
nonlocal image, depth, cache, width, height, scale
self._load_image = LoaderImage(image)
iwidth, iheight = self._load_image.size
aspect_ratio = (iwidth/iheight)

# Force resolution if both set or image's one, else ajust to aspect ratio
if (bool(width) == bool(height)):
resolution = ((width or iwidth), (height or iheight))
else:
resolution = (
((height or 0)*aspect_ratio) or width,
((width or 0)/aspect_ratio) or height,
)

# The order of calling imports here for rendering
self.eloop.once(callback=self.resize, args=[x*scale for x in resolution])
self._load_depth = LoaderImage(depth) or self.mde(image, cache=cache)
self.time = 0

# Start loading process
self.shader.fragment = self.LOADING_SHADER
self._loading = BrokenThread.new(self.parallax,
image=image, depth=depth, cache=cache
)
self._loading = BrokenThread.new(load)

# Wait until loading finish
if block: self._loading.join()
self.time = 0

# ------------------------------------------|

Expand All @@ -87,7 +86,7 @@ def _ui_(self) -> None:
if (state := imgui.input_float("Height", self.parallax_height, 0.01, 0.01, "%.2f"))[0]:
self.parallax_height = max(0, state[1])

def _default_image(self):
def _load_new_or_default(self):

# Set default image if none provided
if self.image.is_empty():
Expand All @@ -107,16 +106,29 @@ def _default_image(self):

# ------------------------------------------|

# Parallax parameters
parallax_fixed = field(default=True)
parallax_height = field(default=0.2)
parallax_focus = field(default=1.0)
parallax_zoom = field(default=1.0)
parallax_isometric = field(default=0.0)
parallax_dolly = field(default=0.0)
parallax_x = field(default=0.0)
parallax_y = field(default=0.0)

def commands(self):
self.broken_typer.command(self.input)

def setup(self):
self._load_new_or_default()

def build(self):
ShaderScene.build(self)
self.image = ShaderTexture(scene=self, name="image").repeat(False)
self.depth = ShaderTexture(scene=self, name="depth").repeat(False)

def update(self):
self._default_image()
self._load_new_or_default()

# In and out dolly zoom
self.parallax_dolly = 0.5*(1 + math.cos(self.time))
Expand Down
1 change: 1 addition & 0 deletions DepthFlow/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import Broken
import DepthFlow.Resources as DepthFlowResources
from Broken.Base import BrokenTorch
Expand Down
16 changes: 11 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,25 +111,31 @@ After activating the Virtual Environment on `.venv`, install [**PyTorch**](https
With PyTorch installed, simply run `depthflow`, a window will open
- Models will be Downloaded on the first run

### Rendering Options
- Run `depthflow --help` for options and rendering

### Selecting the input image
- Run `depthflow input --help` for options
- Run `depthflow input --help` for options on the CLI/Rendering
- Drag and drop an Image File or URL From your Browser

### Rendering Options
- Run `depthflow --help` for options and rendering
**Note**: This resizes the Window to the image size, there's options:
- Only sending `--width` or `--height` adjusts the other to Aspect Ratio
- Sending Both will force the resolution (can also be set on `main -w -h`)
- Sending None will use the Image's resolution (default)
- Use `--scale` to post-multiply the new resolution

### Animation Presets
There's currently no mechanism for presets, but it is planned

- For now, manually change the `.update()` function on `DepthFlow/DepthFlow.py`

### Full Examples
- `depthflow (--render | -r)`
- `depthflow -r -w 1280 -h 720 -f 30`
- `depthflow -r -f 30`
- `depthflow -r -o ./video_name --format mkv`
- `depthflow input --image (url | path) main --render -s 2`
- `depthflow -r -t 2 --open`
- `depthflow input -i (image) -d (depth) main`
- `depthflow input -i (image) -w 600 --scale 2 main -r`

<b>Note</b>: A high SSAA `-s 1.5` is recommended for antialiasing due the Steep Parallax

Expand Down

0 comments on commit a75ba5e

Please sign in to comment.