1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
"""
Profile extraction unit test
"""
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
import numpy as np
import pytest
import sigima.objects
import sigima.params
import sigima.proc.image
from sigima.tests.data import create_sincos_image
from sigima.tests.helpers import check_array_result
@pytest.mark.validation
def test_line_profile() -> None:
"""Test line profile computation"""
width, height = 256, 128
dtype = sigima.objects.ImageDatatypes.UINT16
newparam = sigima.objects.NewImageParam.create(
dtype=dtype, height=height, width=width
)
ima = create_sincos_image(newparam)
# Test horizontal line profile
row = 100
param = sigima.params.LineProfileParam.create(row=row, direction="horizontal")
sig = sigima.proc.image.line_profile(ima, param)
assert sig is not None
assert len(sig.y) == width
exp = np.array(ima.data[row, :], dtype=float)
check_array_result("Horizontal line profile", sig.y, exp)
# Test vertical line profile
col = 50
param = sigima.params.LineProfileParam.create(col=col, direction="vertical")
sig = sigima.proc.image.line_profile(ima, param)
assert sig is not None
assert len(sig.y) == height
exp = np.array(ima.data[:, col], dtype=float)
check_array_result("Vertical line profile", sig.y, exp)
@pytest.mark.validation
def test_segment_profile() -> None:
"""Test segment profile computation"""
width, height = 256, 128
dtype = sigima.objects.ImageDatatypes.UINT16
newparam = sigima.objects.NewImageParam.create(
dtype=dtype, height=height, width=width
)
ima = create_sincos_image(newparam)
# Test segment profile
row1, col1, row2, col2 = 10, 20, 200, 20
param = sigima.params.SegmentProfileParam.create(
row1=row1, col1=col1, row2=row2, col2=col2
)
sig = sigima.proc.image.segment_profile(ima, param)
assert sig is not None
assert len(sig.y) == min(row2, height - 1) - max(row1, 0) + 1
exp = np.array(ima.data[10:200, 20], dtype=float)
check_array_result("Segment profile", sig.y, exp)
@pytest.mark.validation
def test_average_profile() -> None:
"""Test average profile computation"""
width, height = 256, 128
dtype = sigima.objects.ImageDatatypes.UINT16
newparam = sigima.objects.NewImageParam.create(
dtype=dtype, height=height, width=width
)
ima = create_sincos_image(newparam)
row1, col1, row2, col2 = 10, 20, 200, 230
param = sigima.params.AverageProfileParam.create(
row1=row1, col1=col1, row2=row2, col2=col2
)
# Test horizontal average profile
param.direction = "horizontal"
sig = sigima.proc.image.average_profile(ima, param)
assert sig is not None
assert len(sig.y) == col2 - col1 + 1
exp = np.array(ima.data[row1 : row2 + 1, col1 : col2 + 1].mean(axis=0), dtype=float)
check_array_result("Horizontal average profile", sig.y, exp)
# Test vertical average profile
param.direction = "vertical"
sig = sigima.proc.image.average_profile(ima, param)
assert sig is not None
assert len(sig.y) == min(row2, height - 1) - max(row1, 0) + 1
exp = np.array(ima.data[row1 : row2 + 1, col1 : col2 + 1].mean(axis=1), dtype=float)
check_array_result("Vertical average profile", sig.y, exp)
def __test_radial_profile_center(
obj: sigima.objects.ImageObj, p: sigima.params.RadialProfileParam
) -> sigima.objects.SignalObj:
"""Test radial profile computation with given center.
Args:
obj: Image object
p: Radial profile parameters
Returns:
Signal object containing the radial profile
"""
sig = sigima.proc.image.radial_profile(obj, p)
assert sig is not None
assert len(sig.x) == len(sig.y)
assert len(sig.y) > 0
# Check that profile values are within expected range
assert np.all(np.isfinite(sig.y))
assert np.all(sig.y >= 0) # Pixel values should be non-negative
return sig
@pytest.mark.validation
def test_radial_profile() -> None:
"""Test radial profile computation"""
width, height = 256, 128
dtype = sigima.objects.ImageDatatypes.UINT16
newparam = sigima.objects.NewImageParam.create(
dtype=dtype, height=height, width=width
)
ima = create_sincos_image(newparam)
# Test radial profile with centroid center
param = sigima.params.RadialProfileParam.create(center="centroid")
param.update_from_obj(ima)
__test_radial_profile_center(ima, param)
# Test radial profile with image center
param = sigima.params.RadialProfileParam.create(center="center")
param.update_from_obj(ima)
__test_radial_profile_center(ima, param)
# Test radial profile with user-defined center
x0, y0 = width // 2, height // 2
param = sigima.params.RadialProfileParam.create(center="user", x0=x0, y0=y0)
sig = __test_radial_profile_center(ima, param)
# Test that the x-axis represents distance from center (symmetric around 0)
assert sig.x[0] < 0 # First element should be negative
assert sig.x[-1] > 0 # Last element should be positive
assert sig.x[len(sig.x) // 2] == 0 # Center should be at distance 0
# Additional validation using the helper function for the last profile
check_array_result("Radial profile", sig.y, sig.y)
if __name__ == "__main__":
test_line_profile()
test_segment_profile()
test_average_profile()
test_radial_profile()
|