Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stitching #337

Merged
merged 4 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions pyclesperanto_prototype/_tier3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
from ._standard_deviation_of_touching_neighbors_map import standard_deviation_of_touching_neighbors_map
from ._standard_deviation_of_proximal_neighbors_map import standard_deviation_of_proximal_neighbors_map
from ._standard_deviation_of_proximal_neighbors_map import standard_deviation_of_proximal_neighbors_map as standard_deviation_of_distal_neighbors_map

from ._stitch_horizontally_linear_blending import stitch_horizontally_linear_blending
from ._stitch_vertically_linear_blending import stitch_vertically_linear_blending
from ._subtract_gaussian_background import subtract_gaussian_background
from ._z_position_range_projection import z_position_range_projection
from ._z_position_range_projection import z_position_range_projection
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from .._tier0 import plugin_function
from .._tier0 import create
from .._tier0 import create_none
from .._tier0 import Image
from .._tier1 import paste

@plugin_function(output_creator=create_none, categories=['combine', 'transform', 'in assistant'])
def stitch_horizontally_linear_blending(image1 : Image, image2 : Image, destination : Image = None, num_pixels_overlap:int=0) -> Image:
"""Combines two images in X by linearly blending them in an overlapping region.

Parameters
----------
image1 : Image
image2 : Image
destination : Image, optional
num_pixels_overlap : int, optional

Returns
-------
destination
"""
from .._tier0 import create, asarray
from .._tier1 import set_ramp_x, crop
from .._tier1 import subtract_image_from_scalar
from .._tier2 import combine_horizontally

num_pixels_overlap = int(num_pixels_overlap)
image1_width = image1.shape[-1]
image2_width = image2.shape[-1]
image1_height = image1.shape[-2]
image2_height = image2.shape[-2]
image1_depth = 1 if len(image1.shape) == 2 else image1.shape[-3]
image2_depth = 1 if len(image2.shape) == 2 else image2.shape[-3]

# crop out left, right and the two overlapping parts
left_part = crop(image1, width=image1_width - num_pixels_overlap, height=image1_height, depth=image1_depth)
center_part1 = crop(image1, start_x=image1_width - num_pixels_overlap, width=num_pixels_overlap, height=image1_height, depth=image1_depth)
center_part2 = crop(image2, width=num_pixels_overlap, height=image2_height, depth=image2_depth)
right_part = crop(image2, start_x=num_pixels_overlap, width=image2_width - num_pixels_overlap, height=image2_height, depth=image2_depth)

# setup a gradient for the blending
gradient = create(center_part1.shape)
set_ramp_x(gradient)
gradient_right_left = (gradient + 1) / (gradient.shape[-1]+1)
gradient_left_right = subtract_image_from_scalar(gradient_right_left, scalar=1)

# compute the overlapping image by multiplying both images with the gradient
center_part = asarray(center_part1) * gradient_left_right + asarray(center_part2) * gradient_right_left

# combine images vertically
return combine_horizontally(combine_horizontally(left_part, center_part), right_part, destination)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from .._tier0 import plugin_function
from .._tier0 import create
from .._tier0 import create_none
from .._tier0 import Image
from .._tier1 import paste

@plugin_function(output_creator=create_none, categories=['combine', 'transform', 'in assistant'])
def stitch_vertically_linear_blending(image1 : Image, image2 : Image, destination : Image = None, num_pixels_overlap:int=0) -> Image:
"""Combines two images in Y by linearly blending them in an overlapping region.

Parameters
----------
image1 : Image
image2 : Image
destination : Image, optional
num_pixels_overlap : int, optional

Returns
-------
destination
"""
from .._tier0 import create, asarray
from .._tier1 import set_ramp_y, crop
from .._tier1 import subtract_image_from_scalar
from .._tier2 import combine_vertically

num_pixels_overlap = int(num_pixels_overlap)
image1_width = image1.shape[-1]
image2_width = image2.shape[-1]
image1_height = image1.shape[-2]
image2_height = image2.shape[-2]
image1_depth = 1 if len(image1.shape) == 2 else image1.shape[-3]
image2_depth = 1 if len(image2.shape) == 2 else image2.shape[-3]

# crop out left, right and the two overlapping parts
top_part = crop(image1, width=image1_width, height=image1_height - num_pixels_overlap, depth=image1_depth)
center_part1 = crop(image1, start_y=image1_height-num_pixels_overlap, width=image1_width, height=num_pixels_overlap, depth=image1_depth)
center_part2 = crop(image2, width=image2_width, height=num_pixels_overlap, depth=image2_depth)
bottom_part = crop(image2, start_y=num_pixels_overlap, width=image2_width, height=image2_height-num_pixels_overlap, depth=image2_depth)

# setup a gradient for the blending
gradient = create(center_part1.shape)
set_ramp_y(gradient)
gradient_right_left = (gradient + 1) / (gradient.shape[-2]+1)
gradient_left_right = subtract_image_from_scalar(gradient_right_left, scalar=1)

# compute the overlapping image by multiplying both images with the gradient
center_part = asarray(center_part1) * gradient_left_right + asarray(center_part2) * gradient_right_left

# combine images vertically
return combine_vertically(combine_vertically(top_part, center_part), bottom_part, destination)
80 changes: 80 additions & 0 deletions tests/test_stitch_horizontally_linear_blending.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import pyclesperanto_prototype as cle
import numpy as np


def test_stitch_horizontally_linear_blending_overlap0():
test1 = cle.push(np.asarray([
[1, 1],
[1, 1]
]))
test2 = cle.push(np.asarray([
[2, 2, 2],
[2, 2, 2]
]))

reference = cle.push(np.asarray([
[1, 1, 2, 2, 2],
[1, 1, 2, 2, 2]
]))

result = cle.stitch_horizontally_linear_blending(test1, test2)

a = cle.pull(result)
b = cle.pull(reference)

print(a)
print(b)

assert (np.allclose(a, b, 0.01))

def test_stitch_horizontally_linear_blending_overlap1():
test1 = cle.push(np.asarray([
[1, 1],
[1, 1]
]))
test2 = cle.push(np.asarray([
[2, 2, 2],
[2, 2, 2]
]))

reference = cle.push(np.asarray([
[1, 1.5, 2, 2],
[1, 1.5, 2, 2]
]))

result = cle.stitch_horizontally_linear_blending(test1, test2, num_pixels_overlap=1)

a = cle.pull(result)
b = cle.pull(reference)

print(a)
print(b)

assert (np.allclose(a, b, 0.01))


def test_stitch_horizontally_linear_blending_overlap2():
test1 = cle.push(np.asarray([
[1, 1, 1],
[1, 1, 1]
]))
test2 = cle.push(np.asarray([
[2, 2, 2],
[2, 2, 2]
]))

reference = cle.push(np.asarray([
[1, 1.33, 1.67, 2],
[1, 1.33, 1.67, 2]
]))

result = cle.stitch_horizontally_linear_blending(test1, test2, num_pixels_overlap=2)

a = cle.pull(result)
b = cle.pull(reference)

print(a)
print(b)

assert (np.allclose(a, b, 0.01))

96 changes: 96 additions & 0 deletions tests/test_stitch_vertically_linear_blending.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import pyclesperanto_prototype as cle
import numpy as np


def test_stitch_vertically_linear_blending_overlap0():
test1 = cle.push(np.asarray([
[1, 1],
[1, 1],
[1, 1]
]))
test2 = cle.push(np.asarray([
[2, 2],
[2, 2],
[2, 2]
]))

reference = cle.push(np.asarray([
[1, 1],
[1, 1],
[1, 1],
[2, 2],
[2, 2],
[2, 2],
]))

result = cle.stitch_vertically_linear_blending(test1, test2)

a = cle.pull(result)
b = cle.pull(reference)

print(a)
print(b)

assert (np.allclose(a, b, 0.01))


def test_stitch_vertically_linear_blending_overlap1():
test1 = cle.push(np.asarray([
[1, 1],
[1, 1],
[1, 1]
]))
test2 = cle.push(np.asarray([
[2, 2],
[2, 2],
[2, 2]
]))

reference = cle.push(np.asarray([
[1, 1],
[1, 1],
[1.5, 1.5],
[2, 2],
[2, 2],
]))

result = cle.stitch_vertically_linear_blending(test1, test2, num_pixels_overlap=1)

a = cle.pull(result)
b = cle.pull(reference)

print(a)
print(b)

assert (np.allclose(a, b, 0.01))


def test_stitch_vertically_linear_blending_overlap2():
test1 = cle.push(np.asarray([
[1, 1],
[1, 1],
[1, 1]
]))
test2 = cle.push(np.asarray([
[2, 2],
[2, 2],
[2, 2]
]))

reference = cle.push(np.asarray([
[1, 1],
[1.33, 1.33],
[1.67, 1.67],
[2, 2],
]))

result = cle.stitch_vertically_linear_blending(test1, test2, num_pixels_overlap=2)

a = cle.pull(result)
b = cle.pull(reference)

print(a)
print(b)

assert (np.allclose(a, b, 0.01))

Loading