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
|
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
"""
Image pixel binning computation test
"""
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
# pylint: disable=duplicate-code
import time
import numpy as np
import pytest
from numpy import ma
import sigima.params
import sigima.proc.image
from sigima.enums import BinningOperation
from sigima.tests import guiutils
from sigima.tests.data import get_test_image
from sigima.tests.env import execenv
from sigima.tools.image import binning
def compare_binning_images(data: ma.MaskedArray) -> None:
"""Compare binning images
Args:
data: Image data
"""
# pylint: disable=import-outside-toplevel
import sigima.viz.viz_plotpy as viz
items = []
items += [viz.create_image(data, interpolation="nearest")]
# Computing pixel binning
oa_t0 = time.time()
for ix in range(1, 5):
sx = 2**ix
for iy in range(1, 5):
sy = 2**iy
for operation in BinningOperation:
t0 = time.time()
bdata = binning(data, sx=sx, sy=sy, operation=operation)
title = f"[{sx}x{sy},{operation.value}]"
item = viz.create_image(
bdata,
title=title,
interpolation="nearest",
xdata=[0, data.shape[1]],
ydata=[0, data.shape[0]],
)
item.hide()
items.append(item)
dt = time.time() - t0
execenv.print(f" {title}: {int(dt * 1e3):d} ms")
oa_dt = time.time() - oa_t0
execenv.print(f" Overall calculation time: {int(oa_dt * 1e3):d} ms")
viz.view_image_items(items, title="Binning test", show_itemlist=True)
@pytest.mark.gui
def test_binning_interactive() -> None:
"""Test binning computation and show results"""
with guiutils.lazy_qt_app_context(force=True):
data = get_test_image("*.scor-data").data[:500, :500]
execenv.print(f"Data[dtype={data.dtype},shape={data.shape}]")
compare_binning_images(data.view(ma.MaskedArray))
@pytest.mark.validation
def test_binning() -> None:
"""Validation test for binning computation"""
# Implementation note:
# ---------------------
#
# Pixel binning algorithm is validated graphically by comparing the results of
# different binning operations and sizes: that is the purpose of the
# `test_binning_graphically`` function.
# Formal validation is not possible without reimplementation of the algorithm
# here, which would be redundant and proove nothing. Instead, as a complementary
# test, we only validate some basic properties of the binning algorithm:
# - The output shape is correct
# - The output data type is correct
# - Some basic properties of the output data are correct (e.g. min, max, mean)
src = get_test_image("*.scor-data")
src.data = data = np.array(src.data[:500, :500], dtype=float)
ny, nx = data.shape
p = sigima.params.BinningParam()
for operation in BinningOperation:
p.operation = operation
for sx in range(2, 3):
for sy in range(2, 5):
p.sx = sx
p.sy = sy
rdata = data[: ny - (ny % sy), : nx - (nx % sx)]
dst = sigima.proc.image.binning(src, p)
bdata = dst.data
assert bdata.shape == (data.shape[0] // sy, data.shape[1] // sx)
assert bdata.dtype == data.dtype
if operation == "min":
assert bdata.min() == rdata.min()
elif operation == "max":
assert bdata.max() == rdata.max()
elif operation == "sum":
assert bdata.sum() == rdata.sum()
elif operation == "average":
assert bdata.mean() == rdata.mean()
for src_dtype in (float, np.uint8, np.uint16, np.int16):
src.data = data = np.array(src.data[:500, :500], dtype=src_dtype)
for dtype_str in p.dtypes:
p.dtype_str = dtype_str
dst = sigima.proc.image.binning(src, p)
bdata = dst.data
if dtype_str == "dtype":
assert bdata.dtype is data.dtype
else:
assert bdata.dtype is np.dtype(dtype_str)
if __name__ == "__main__":
test_binning_interactive()
test_binning()
|