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

feat(tests): Improve pixano.core unit tests #67

Merged
merged 7 commits into from
Feb 1, 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
2 changes: 0 additions & 2 deletions pixano/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
is_image_type,
is_integer,
is_string,
pyarrow_array_from_list,
)

__all__ = [
Expand All @@ -53,5 +52,4 @@
"is_image_type",
"is_integer",
"is_string",
"pyarrow_array_from_list",
]
17 changes: 12 additions & 5 deletions pixano/core/depth_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,21 @@ def to_grayscale(
return DepthImage(depth_map=depth_n.astype(np.uint8), shape=depth.shape)

def display(self):
"""Display Depth image with matplotlib"""
"""Display Depth image with matplotlib

plt.imshow(self.depth_map.astype(np.int8), cmap="gray", vmin=0, vmax=255)
plt.axis("off")
if self._shape is not None:
plt.figure(figsize=self._shape)
Returns:
plt.Figure: Plotted image
"""

fig, ax = plt.subplots(figsize=self._shape)
ax.imshow(self.depth_map.astype(np.int8), cmap="gray", vmin=0, vmax=255)
ax.axis("off")

plt.ion()
plt.show()

return fig

@staticmethod
def to_struct() -> pa.StructType:
"""Return DepthImage type as PyArrow Struct
Expand Down
28 changes: 0 additions & 28 deletions pixano/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,31 +95,3 @@ def is_image_type(t: pa.DataType) -> bool:
ImageType.equals(t)
or str(t) == "struct<uri: string, bytes: binary, preview_bytes: binary>"
)


def pyarrow_array_from_list(
list_data: list, pyarrow_type: pa.ExtensionType | pa.DataType
) -> pa.Array:
"""Convert data from Python list to PyArrow array

Args:
list_data (list): Data as Python list
pyarrow_type (pa.ExtensionType | pa.DataType): PyArrow base or custom extension type

Raises:
ValueError: Unknow type

Returns:
pa.Array: Data as PyArrow array
"""

if pa.types.is_list(pyarrow_type):
pyarrow_type = pyarrow_type.value_type

if isinstance(pyarrow_type, pa.ExtensionType):
return pyarrow_type.Array.from_pylist(list_data)
if isinstance(pyarrow_type, pa.DataType) and not isinstance(
pyarrow_type, pa.ExtensionType
):
return pa.array(list_data)
raise ValueError("Unknow type")
46 changes: 46 additions & 0 deletions tests/core/test_bbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import pyarrow.parquet as pq

from pixano.core import BBox, BBoxType
from pixano.core.compressed_rle import CompressedRLE


class BBoxTestCase(unittest.TestCase):
Expand Down Expand Up @@ -101,6 +102,51 @@ def test_normalization(self):

self.assertTrue(np.allclose(denormalized_bbox.xyxy_coords, self.coords["xyxy"]))

def test_from_mask(self):
"""Test BBox from_mask method"""

mask = np.array(
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
],
dtype="uint8",
)
coords = [0.4, 0.5, 0.1, 0.1]

self.assertEqual(BBox.from_mask(mask).coords, coords)

def test_from_rle(self):
"""Test BBox from_rle method"""

mask = np.array(
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
],
dtype="uint8",
)
rle = CompressedRLE.from_mask(mask)
coords = [0.4, 0.5, 0.1, 0.1]

self.assertEqual(BBox.from_rle(rle).coords, coords)


class TestParquetBBox(unittest.TestCase):
"""BBox test case for Parquet storage"""
Expand Down
101 changes: 101 additions & 0 deletions tests/core/test_camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# @Copyright: CEA-LIST/DIASI/SIALV/LVA (2023)
# @Author: CEA-LIST/DIASI/SIALV/LVA <pixano@cea.fr>
# @License: CECILL-C
#
# This software is a collaborative computer program whose purpose is to
# generate and explore labeled data for computer vision applications.
# This software is governed by the CeCILL-C license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL-C
# license as circulated by CEA, CNRS and INRIA at the following URL
#
# http://www.cecill.info

import tempfile
import unittest

import pyarrow as pa
import pyarrow.parquet as pq

from pixano.core import Camera, CameraType


class CameraTestCase(unittest.TestCase):
"""Camera test case"""

def setUp(self):
"""Tests setup"""

self.depth_scale = 0.5
self.cam_k = [0.2, 0.6, 0.3]
self.cam_r_w2c = [0.2, 0.6, 0.3, 0.2, 0.6, 0.3, 0.2, 0.6, 0.3]
self.cam_t_w2c = [0.2, 0.6, 0.3]

def test_init(self):
"""Test Camera init method"""

partial_camera = Camera(
depth_scale=self.depth_scale,
cam_k=self.cam_k,
)
full_camera = Camera(
depth_scale=self.depth_scale,
cam_k=self.cam_k,
cam_r_w2c=self.cam_r_w2c,
cam_t_w2c=self.cam_t_w2c,
)

self.assertEqual(partial_camera.depth_scale, self.depth_scale)
self.assertEqual(partial_camera.cam_k, self.cam_k)
self.assertEqual(partial_camera.cam_r_w2c, [0.0] * 9)
self.assertEqual(partial_camera.cam_t_w2c, [0.0] * 3)

self.assertEqual(full_camera.depth_scale, self.depth_scale)
self.assertEqual(full_camera.cam_k, self.cam_k)
self.assertEqual(full_camera.cam_r_w2c, self.cam_r_w2c)
self.assertEqual(full_camera.cam_t_w2c, self.cam_t_w2c)


class TestParquetCamera(unittest.TestCase):
"""Camera test case for Parquet storage"""

def setUp(self):
"""Tests setup"""

self.depth_scale = 0.5
self.cam_k = [0.2, 0.6, 0.3]
self.cam_r_w2c = [0.2, 0.6, 0.3, 0.2, 0.6, 0.3, 0.2, 0.6, 0.3]
self.cam_t_w2c = [0.2, 0.6, 0.3]

self.camera_list = [
Camera(
depth_scale=self.depth_scale,
cam_k=self.cam_k,
),
Camera(
depth_scale=self.depth_scale,
cam_k=self.cam_k,
cam_r_w2c=self.cam_r_w2c,
cam_t_w2c=self.cam_t_w2c,
),
]

def test_camera_table(self):
"""Test Camera Parquet storage"""

cam_arr = CameraType.Array.from_pylist(self.camera_list)
table = pa.Table.from_arrays(
[cam_arr],
schema=pa.schema([pa.field("camera", CameraType)]),
)

with tempfile.NamedTemporaryFile(suffix=".parquet") as temp_file:
temp_file_path = temp_file.name
pq.write_table(table, temp_file_path, store_schema=True)
re_table = pq.read_table(temp_file_path)

self.assertEqual(re_table.column_names, ["camera"])

cam_1 = re_table.take([0])["camera"][0].as_py()

self.assertIsInstance(cam_1, Camera)
16 changes: 12 additions & 4 deletions tests/core/test_depth_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class DepthImageTestCase(unittest.TestCase):
def setUp(self):
"""Tests setup"""

self.depth_map = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.uint16)
self.depth_map = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
self.shape = self.depth_map.shape
self.bytes = self.depth_map.tobytes()
self.depth_image = DepthImage(
Expand All @@ -47,10 +47,13 @@ def test_bytes(self):
def test_depth_map(self):
"""Test DepthImage depth_map property"""

depth_map = self.depth_image.depth_map
image_without_depth_map = DepthImage(shape=self.shape, bytes=self.bytes)
depth_map_from_bytes = image_without_depth_map.depth_map

self.assertIsInstance(depth_map, np.ndarray)
self.assertEqual(depth_map.tolist(), self.depth_map.tolist())
self.assertIsInstance(self.depth_image.depth_map, np.ndarray)
self.assertIsInstance(depth_map_from_bytes, np.ndarray)
self.assertEqual(self.depth_image.depth_map.tolist(), self.depth_map.tolist())
self.assertEqual(depth_map_from_bytes.tolist(), self.depth_map.tolist())

def test_load_npy(self):
"""Test DepthImage load_npy method"""
Expand Down Expand Up @@ -91,6 +94,11 @@ def test_open(self):
loaded_bytes = io_obj.read()
self.assertEqual(loaded_bytes, self.bytes)

def test_display(self):
"""Test DepthImage display method"""

self.depth_image.display()

def test_to_grayscale(self):
"""Test DepthImage to_grayscale method"""

Expand Down
98 changes: 98 additions & 0 deletions tests/core/test_gt_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# @Copyright: CEA-LIST/DIASI/SIALV/LVA (2023)
# @Author: CEA-LIST/DIASI/SIALV/LVA <pixano@cea.fr>
# @License: CECILL-C
#
# This software is a collaborative computer program whose purpose is to
# generate and explore labeled data for computer vision applications.
# This software is governed by the CeCILL-C license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL-C
# license as circulated by CEA, CNRS and INRIA at the following URL
#
# http://www.cecill.info

import tempfile
import unittest

import pyarrow as pa
import pyarrow.parquet as pq

from pixano.core import BBox, GtInfo, GtInfoType


class GtInfoTestCase(unittest.TestCase):
"""GtInfo test case"""

def setUp(self):
"""Tests setup"""

self.bbox_obj = BBox([0.1, 0.1, 0.1, 0.1], "xywh")
self.bbox_visib = BBox([0.2, 0.2, 0.1, 0.1], "xywh")
self.px_count_all = 10
self.px_count_valid = 5
self.px_count_visib = 5
self.visib_fract = 0.5

def test_init(self):
"""Test GtInfo init method"""

gtinfo = GtInfo(
bbox_obj=self.bbox_obj,
bbox_visib=self.bbox_visib,
px_count_all=self.px_count_all,
px_count_valid=self.px_count_valid,
px_count_visib=self.px_count_visib,
visib_fract=self.visib_fract,
)

self.assertEqual(gtinfo.bbox_obj, self.bbox_obj)
self.assertEqual(gtinfo.bbox_visib, self.bbox_visib)
self.assertEqual(gtinfo.px_count_all, self.px_count_all)
self.assertEqual(gtinfo.px_count_valid, self.px_count_valid)
self.assertEqual(gtinfo.px_count_visib, self.px_count_visib)
self.assertEqual(gtinfo.visib_fract, self.visib_fract)


class TestParquetGtInfo(unittest.TestCase):
"""GtInfo test case for Parquet storage"""

def setUp(self):
"""Tests setup"""

self.bbox_obj = BBox([0.1, 0.1, 0.1, 0.1], "xywh")
self.bbox_visib = BBox([0.2, 0.2, 0.1, 0.1], "xywh")
self.px_count_all = 10
self.px_count_valid = 5
self.px_count_visib = 5
self.visib_fract = 0.5

self.gtinfo_list = [
GtInfo(
bbox_obj=self.bbox_obj,
bbox_visib=self.bbox_visib,
px_count_all=self.px_count_all,
px_count_valid=self.px_count_valid,
px_count_visib=self.px_count_visib,
visib_fract=self.visib_fract,
)
]

def test_gt_info_table(self):
"""Test GtInfo Parquet storage"""

gt_arr = GtInfoType.Array.from_pylist(self.gtinfo_list)
table = pa.Table.from_arrays(
[gt_arr],
schema=pa.schema([pa.field("gtinfo", GtInfoType)]),
)

with tempfile.NamedTemporaryFile(suffix=".parquet") as temp_file:
temp_file_path = temp_file.name
pq.write_table(table, temp_file_path, store_schema=True)
re_table = pq.read_table(temp_file_path)

self.assertEqual(re_table.column_names, ["gtinfo"])

gt_1 = re_table.take([0])["gtinfo"][0].as_py()

self.assertIsInstance(gt_1, GtInfo)
Loading
Loading