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

Print the color channel format (RGB) for datum stats command #1389

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: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
(<https://github.com/openvinotoolkit/datumaro/pull/1266>)
- Fix each method of the comparator to be used separately
(<https://github.com/openvinotoolkit/datumaro/pull/1290>)
- Print the color channel format (RGB) for datum stats command
(<https://github.com/openvinotoolkit/datumaro/pull/1389>)

### Bug fixes
- Fix wrong example of Datumaro dataset creation in document
Expand Down
30 changes: 15 additions & 15 deletions docs/source/docs/command-reference/context_free/compare.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,21 @@ Firstly, the "High-level comparison" provides information regarding the format,

Secondly, the "Mid-level comparison" displays image means, standard deviations, and label distributions for each subset in the datasets. For example:
```bash
+--------------------+--------------------------+--------------------------+
| Field | First | Second |
+====================+==========================+==========================+
| train - Image Mean | 1.00, 1.00, 1.00 | 1.00, 1.00, 1.00 |
+--------------------+--------------------------+--------------------------+
| train - Image Std | 0.00, 0.00, 0.00 | 0.00, 0.00, 0.00 |
+--------------------+--------------------------+--------------------------+
| Label - a | imgs: 1, percent: 1.0000 | |
+--------------------+--------------------------+--------------------------+
| Label - b | | imgs: 1, percent: 0.5000 |
+--------------------+--------------------------+--------------------------+
| Label - background | | |
+--------------------+--------------------------+--------------------------+
| Label - c | | imgs: 1, percent: 0.5000 |
+--------------------+--------------------------+--------------------------+
+--------------------------+--------------------------+--------------------------+
| Field | First | Second |
+==========================+==========================+==========================+
| train - Image Mean (RGB) | 1.00, 1.00, 1.00 | 1.00, 1.00, 1.00 |
+--------------------------+--------------------------+--------------------------+
| train - Image Std (RGB) | 0.00, 0.00, 0.00 | 0.00, 0.00, 0.00 |
+--------------------------+--------------------------+--------------------------+
| Label - a | imgs: 1, percent: 1.0000 | |
+--------------------------+--------------------------+--------------------------+
| Label - b | | imgs: 1, percent: 0.5000 |
+--------------------------+--------------------------+--------------------------+
| Label - background | | |
+--------------------------+--------------------------+--------------------------+
| Label - c | | imgs: 1, percent: 0.5000 |
+--------------------------+--------------------------+--------------------------+
```

Lastly, the "Low-level comparison" uses ShiftAnalyzer to show Covariate shift and Label shift between the two datasets. For example:
Expand Down
8 changes: 4 additions & 4 deletions docs/source/docs/command-reference/context_free/stats.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Get Project Statistics

This command computes various project statistics, such as:
- image mean and std. dev.
- image mean and std. dev. (RGB)
- class and attribute balance
- mask pixel balance
- segment area distribution
Expand All @@ -19,7 +19,7 @@ Parameters:
[source revpath](../../user-manual/how_to_use_datumaro.md#dataset-path-concepts).
By default, computes statistics of the merged dataset.
- `-s, --subset` (string) - Compute stats only for a specific subset
- `--image-stats` (bool) - Compute image mean and std (default: `True`)
- `--image-stats` (bool) - Compute image mean and std (RGB) (default: `True`)
- `--ann-stats` (bool) - Compute annotation statistics (default: `True`)
- `-p, --project` (string) - Directory of the project to operate on
(default: current directory).
Expand Down Expand Up @@ -282,12 +282,12 @@ Sample output:
"subsets": {
"default": {
"images count": 100,
"image mean": [
"image mean (RGB)": [
107.06903686941979,
79.12831698580979,
52.95829558185416
],
"image std": [
"image std (RGB)": [
49.40237673503467,
43.29600731496902,
35.47373007603151
Expand Down
4 changes: 2 additions & 2 deletions src/datumaro/cli/commands/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def build_parser(parser_ctor=argparse.ArgumentParser):
parser = parser_ctor(
help="Get project statistics",
description="""
Outputs various project statistics like image mean and std,
Outputs various project statistics like image mean and std (RGB),
annotations count etc.|n
|n
Target dataset is specified by a revpath. The full syntax is:|n
Expand Down Expand Up @@ -54,7 +54,7 @@ def build_parser(parser_ctor=argparse.ArgumentParser):
"--image-stats",
type=str_to_bool,
default=True,
help="Compute image mean and std (default: %(default)s)",
help="Compute image mean and std (RGB) (default: %(default)s)",
)
parser.add_argument(
"--ann-stats",
Expand Down
16 changes: 8 additions & 8 deletions src/datumaro/components/comparator.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,27 +521,27 @@ def _create_mid_level_comparison_table(
first_subset_data = first_image_stats["subsets"].get(subset_name, {})
second_subset_data = second_image_stats["subsets"].get(subset_name, {})
mean_str_first = (
", ".join(f"{val:6.2f}" for val in first_subset_data.get("image mean", []))
if "image mean" in first_subset_data
", ".join(f"{val:6.2f}" for val in first_subset_data.get("image mean (RGB)", []))
if "image mean (RGB)" in first_subset_data
else ""
)
std_str_first = (
", ".join(f"{val:6.2f}" for val in first_subset_data.get("image std", []))
", ".join(f"{val:6.2f}" for val in first_subset_data.get("image std (RGB)", []))
if "image std" in first_subset_data
else ""
)
mean_str_second = (
", ".join(f"{val:6.2f}" for val in second_subset_data.get("image mean", []))
if "image mean" in second_subset_data
", ".join(f"{val:6.2f}" for val in second_subset_data.get("image mean (RGB)", []))
if "image mean (RGB)" in second_subset_data
else ""
)
std_str_second = (
", ".join(f"{val:6.2f}" for val in second_subset_data.get("image std", []))
if "image std" in second_subset_data
if "image std (RGB)" in second_subset_data
else ""
)
rows.append([f"{subset_name} - Image Mean", mean_str_first, mean_str_second])
rows.append([f"{subset_name} - Image Std", std_str_first, std_str_second])
rows.append([f"{subset_name} - Image Mean (RGB)", mean_str_first, mean_str_second])
rows.append([f"{subset_name} - Image Std (RGB)", std_str_first, std_str_second])

first_labels = sorted(list(first_ann_stats["annotations"]["labels"]["distribution"].keys()))
second_labels = sorted(
Expand Down
32 changes: 19 additions & 13 deletions src/datumaro/components/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from datumaro.components.dataset_base import CategoriesInfo, DatasetItem, IDataset
from datumaro.components.errors import DatumaroError
from datumaro.components.media import Image
from datumaro.util.image import IMAGE_BACKEND, ImageColorChannel, decode_image_context


def mean_std(dataset: IDataset):
Expand Down Expand Up @@ -164,16 +165,21 @@ def compute_image_statistics(dataset: IDataset):
stats_counter = _MeanStdCounter()
unique_counter = _ItemMatcher()

for item in dataset:
if not isinstance(item.media, Image):
warnings.warn(
f"item (id: {item.id}, subset: {item.subset})"
f" has media_type, {item.media} but only Image media_type is allowed."
)
continue
# NOTE: Force image color channel to RGB
with decode_image_context(
image_backend=IMAGE_BACKEND.get(),
image_color_channel=ImageColorChannel.COLOR_RGB,
):
for item in dataset:
if not isinstance(item.media, Image):
warnings.warn(
f"item (id: {item.id}, subset: {item.subset})"
f" has media_type, {item.media} but only Image media_type is allowed."
)
continue

stats_counter.accumulate(item)
unique_counter.process_item(item)
stats_counter.accumulate(item)
unique_counter.process_item(item)

def _extractor_stats(subset_name):
sub_counter = _MeanStdCounter()
Expand All @@ -194,15 +200,15 @@ def _extractor_stats(subset_name):

stats.update(
{
"image mean": [float(v) for v in mean[::-1]],
"image std": [float(v) for v in std[::-1]],
"image mean (RGB)": [float(v) for v in mean],
"image std (RGB)": [float(v) for v in std],
}
)
else:
stats.update(
{
"image mean": "n/a",
"image std": "n/a",
"image mean (RGB)": "n/a",
"image std (RGB)": "n/a",
}
)
return stats
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/gui/single/test_analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ def stats_image(self):
"subsets": {
"train": {
"images count": 1,
"image mean": [0.0, 0.0, 0.0],
"image std": [0.0, 0.0, 0.0],
"image mean (RGB)": [0.0, 0.0, 0.0],
"image std (RGB)": [0.0, 0.0, 0.0],
}
},
}
Expand Down
27 changes: 18 additions & 9 deletions tests/unit/operations/test_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
#
# SPDX-License-Identifier: MIT

from pathlib import Path
from typing import List, Tuple
from unittest.mock import patch

import cv2
import numpy as np
import pytest

Expand All @@ -24,6 +26,7 @@

@pytest.fixture
def fxt_image_dataset_expected_mean_std():
"""Expected image mean and std (RGB)"""
np.random.seed(3003)
expected_mean = [100, 50, 150]
expected_std = [2, 1, 3]
Expand All @@ -32,20 +35,26 @@ def fxt_image_dataset_expected_mean_std():


@pytest.fixture
def fxt_image_dataset(fxt_image_dataset_expected_mean_std: Tuple[List[int], List[int]]):
def fxt_image_dataset(fxt_image_dataset_expected_mean_std: Tuple[List[int], List[int]], tmpdir):
np.random.seed(3003)

expected_mean, expected_std = fxt_image_dataset_expected_mean_std

fpaths = []
for i, (w, h) in enumerate([(300, 10), (80, 60), (40, 20), (70, 30)]):
fpath = str(Path(tmpdir) / f"img_{i}.png")
# NOTE: cv2 use BGR so that we flip expected_mean and expected_std which are RGB
img_data = np.random.normal(expected_mean[::-1], expected_std[::-1], size=(h, w, 3))
cv2.imwrite(fpath, img_data)
fpaths.append(fpath)

dataset = Dataset.from_iterable(
[
DatasetItem(
id=i,
media=Image.from_numpy(
data=np.random.normal(expected_mean, expected_std, size=(h, w, 3))
),
id=str(i),
media=Image.from_file(path=str(fpath)),
)
for i, (w, h) in enumerate([(3000, 100), (800, 600), (400, 200), (700, 300)])
for i, fpath in enumerate(fpaths)
]
)
dataset.put(dataset.get("1"), id="5", subset="train")
Expand All @@ -55,7 +64,7 @@ def fxt_image_dataset(fxt_image_dataset_expected_mean_std: Tuple[List[int], List
media=Image.from_file(path="invalid.path"),
)
)
return dataset
yield dataset


@pytest.fixture
Expand Down Expand Up @@ -92,8 +101,8 @@ def test_image_stats(
assert actual["subsets"]["default"]["images count"] == 4
assert actual["subsets"]["train"]["images count"] == 1

actual_mean = actual["subsets"]["default"]["image mean"][::-1]
actual_std = actual["subsets"]["default"]["image std"][::-1]
actual_mean = actual["subsets"]["default"]["image mean (RGB)"]
actual_std = actual["subsets"]["default"]["image std (RGB)"]

for em, am in zip(expected_mean, actual_mean):
assert am == pytest.approx(em, 5e-1)
Expand Down
Loading