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

Backport changes to release #125

Merged
merged 42 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
421ca9b
All sampled images in image list (#88)
PaulHax Sep 11, 2024
97594f1
feat(transforms): add disable transform option
PaulHax Sep 3, 2024
3707bad
feat(transforms): toggle component to disable transforms
PaulHax Sep 4, 2024
8846751
feat(transforms): toggle switch to disable object detection
PaulHax Sep 11, 2024
a7b5a94
feat(layout): move category filter to bottom
PaulHax Sep 11, 2024
6e0573a
refactor(transforms): extract detection and transform enable/disable …
PaulHax Sep 12, 2024
829877f
feat(filtering): relabel Apply button to Select Images
PaulHax Sep 12, 2024
e6a2957
feat(image_list): slider for image size
PaulHax Sep 12, 2024
f67fc38
fix(project): cleanup dependency structure
jourdain Sep 10, 2024
f30a5fb
fix(embedding): standalone mode works again
jourdain Sep 10, 2024
ef49bd9
fix(embedding): attempt to revive standalone mode
jourdain Sep 13, 2024
6663efd
fix(embeddings): dont send empty lists to dim reducer
PaulHax Sep 13, 2024
1f059f9
fix(ui): use class components
jourdain Sep 13, 2024
997626a
fix(network): ensure network completion before heavy work
jourdain Sep 16, 2024
f106a3e
fix(dep): properly describe expected version
jourdain Sep 16, 2024
eb43492
chore(deps): bump scikit-learn from 1.5.1 to 1.5.2
dependabot[bot] Sep 16, 2024
424ff36
Merge pull request #109 from Kitware/better-network-wait
jourdain Sep 17, 2024
e11c986
fix(transforms): turn on transform enabled switch on apply button
PaulHax Sep 13, 2024
fc201fc
feat(image_list): add switch to hide annotations
PaulHax Sep 13, 2024
a910f28
feat(image_list): use normal switch for show annotations
PaulHax Sep 18, 2024
3bedfd0
feat(image_list): only show spinner if show annotations is on
PaulHax Sep 18, 2024
8291cb2
refactor(images): move module level funcs to class
PaulHax Sep 19, 2024
cf93436
perf(images): add cache backed get_stateful_image funcs
PaulHax Sep 19, 2024
9a30492
fix(images): dont remove image from cache for embeddings
PaulHax Sep 19, 2024
d2070bf
refactor(annotations): reuse LruCache for annotations
PaulHax Sep 20, 2024
497e390
chore(docker): add docker deploy definition
jourdain Sep 24, 2024
1920493
chore(deps): bump rollup from 3.29.4 to 3.29.5 in /vue-components
dependabot[bot] Sep 30, 2024
9d527c0
chore(deps-dev): bump vite from 4.5.3 to 4.5.5 in /vue-components
dependabot[bot] Sep 30, 2024
9893897
Merge pull request #121 from Kitware/dependabot/npm_and_yarn/vue-comp…
vicentebolea Sep 30, 2024
af3cab5
Merge pull request #120 from Kitware/dependabot/npm_and_yarn/vue-comp…
vicentebolea Sep 30, 2024
210d91f
Merge pull request #110 from Kitware/dependabot/pip/scikit-learn-1.5.2
vicentebolea Sep 30, 2024
f624be7
fix(embeddings): disable transforms switch hides points
PaulHax Sep 27, 2024
f8f524f
feat(transforms): add 3 more object detection models
PaulHax Sep 27, 2024
2391c3e
feat(ScatterPlot): dark gray for selected points
PaulHax Sep 30, 2024
627bc08
docs(README): update screenshot
PaulHax Oct 4, 2024
3b1e1db
fix(ScatterPlot): reactive color map control and perf
PaulHax Oct 4, 2024
2459642
feat(ScatterPlot): stay in selection mode after selection
PaulHax Oct 4, 2024
80100f0
feat(core): default to 500 sampled dataset images
PaulHax Oct 4, 2024
98c05a6
fix(core): dataset path does not overflow select dropdown
PaulHax Oct 4, 2024
5676a1f
perf(core): add debounce to sample size slider
PaulHax Oct 4, 2024
0346cfc
fix(ImageDetection): stop tooltip overflow with fudge to center
PaulHax Oct 4, 2024
7f2d827
chore(deps): update build requirement from <0.10.0 to <1.3.0
dependabot[bot] Sep 13, 2024
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: 1 addition & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ jobs:
run: npm run eslint

unit_tests:
needs:
- linters_python
- linters_vue
runs-on: ubuntu-latest
name: ubuntu-latest-tests-python${{ matrix.python-version}}
strategy:
Expand Down Expand Up @@ -81,7 +78,7 @@ jobs:

- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel "build<0.10.0" python-semantic-release
python -m pip install --upgrade pip setuptools wheel "build<1.3.0" python-semantic-release

- name: Python Semantic Release
id: release
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/create_release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:

- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel "build<0.10.0" python-semantic-release
python -m pip install --upgrade pip setuptools wheel "build<1.3.0" python-semantic-release

- name: Python Semantic Release
id: release
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ insights of a image dataset in [COCO][3] format and it evaluate image
transformation and perturbation resilience of object recognition DL models. It
is built using [trame][1] by the [kitware][2] team.

![nrtk explorer](https://raw.githubusercontent.com/Kitware/nrtk-explorer/main/screenshot.png)
![nrtk explorer screenshot](https://github.com/user-attachments/assets/85c95836-3490-40ec-813d-e6841c540d51)


Features
--------
Expand Down
4 changes: 4 additions & 0 deletions captain-definition
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"schemaVersion": 2,
"dockerfilePath": "./docker/Dockerfile"
}
3 changes: 3 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM kitware/trame:py3.10-glvnd-2024-09
COPY --chown=trame-user:trame-user ./docker /deploy
RUN /opt/trame/entrypoint.sh build
Binary file added docker/nrtk_explorer-0.3.1-py2.py3-none-any.whl
Binary file not shown.
17 changes: 17 additions & 0 deletions docker/setup/apps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
trame:
www_modules:
- nrtk_explorer.module
cmd:
- python
- -m
- nrtk_explorer.app.main
- --host
- ${host}
- --port
- ${port}
- --authKey
- ${secret}
- --server
- --banner
- --dataset
- /data/OIRDS_v1_0/oirds.json
1 change: 1 addition & 0 deletions docker/setup/initialize.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pip install /deploy/nrtk_explorer-0.3.1-py2.py3-none-any.whl
2 changes: 2 additions & 0 deletions docker/setup/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
nrtk[headless]
# nrtk-explorer
19 changes: 9 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@ dependencies = [
"numpy",
"Pillow",
"pybsm>=0.6",
"scikit-learn==1.5.1",
"scikit-learn==1.5.2",
"smqtk_image_io",
"tabulate",
"timm>=1.0.3",
"torch",
"torchvision",
"trame",
"trame-client>=2.15.0",
"trame>=3.6",
"trame-quasar",
"trame-server>=2.15.0",
"trame-server>=3.2",
"transformers",
"umap-learn",
]
Expand All @@ -60,7 +59,7 @@ dev = [
]

package = [
"build<0.10.0",
"build<1.3.0",
"python-semantic-release",
"setuptools",
"wheel",
Expand All @@ -78,10 +77,10 @@ build-backend = "hatchling.build"
[tool.hatch.build.hooks.custom]

[project.scripts]
nrtk-explorer = "nrtk_explorer.app:main"
nrtk-explorer-embeddings = "nrtk_explorer.app.embeddings:embeddings"
nrtk-explorer-transforms = "nrtk_explorer.app.transforms:transforms"
nrtk-explorer-filtering = "nrtk_explorer.app.filtering:filtering"
nrtk-explorer = "nrtk_explorer.app.main:main"
nrtk-explorer-embeddings = "nrtk_explorer.app.embeddings:main"
nrtk-explorer-transforms = "nrtk_explorer.app.transforms:main"
nrtk-explorer-filtering = "nrtk_explorer.app.filtering:main"

[tool.black]
line-length = 99
Expand Down Expand Up @@ -126,7 +125,7 @@ build_command = """
python -m venv .venv
source .venv/bin/activate
pip install -U pip
python -m pip install "build<0.10.0" python-semantic-release setuptools wheel
python -m pip install "build<1.3.0" python-semantic-release setuptools wheel
python -m build .
"""

Expand Down
4 changes: 4 additions & 0 deletions src/nrtk_explorer/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .app.main import main

if __name__ == "__main__":
main()
5 changes: 0 additions & 5 deletions src/nrtk_explorer/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
from .main import main

__all__ = [
"main",
]
107 changes: 35 additions & 72 deletions src/nrtk_explorer/app/core.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import logging
from typing import Iterable
from pathlib import Path

from trame.widgets import html
from trame_server.utils.namespace import Translator
from nrtk_explorer.library import images_manager
from nrtk_explorer.library.filtering import FilterProtocol
from nrtk_explorer.library.dataset import get_dataset, get_image_fpath
from nrtk_explorer.library.debounce import debounce

from nrtk_explorer.app.images.images import Images
from nrtk_explorer.app.embeddings import EmbeddingsApp
from nrtk_explorer.app.transforms import TransformsApp
from nrtk_explorer.app.filtering import FilteringApp
Expand All @@ -25,13 +25,13 @@
html.Template.slot_names.add("before")
html.Template.slot_names.add("after")

HORIZONTAL_SPLIT_DEFAULT_VALUE = 17
VERTICAL_SPLIT_DEFAULT_VALUE = 40

DIR_NAME = os.path.dirname(nrtk_explorer.test_data.__file__)
DEFAULT_DATASETS = [
f"{DIR_NAME}/coco-od-2017/test_val2017.json",
]
NUM_IMAGES_DEFAULT = 500
NUM_IMAGES_DEBOUNCE_TIME = 0.3 # seconds


# ---------------------------------------------------------
Expand All @@ -52,41 +52,18 @@ def __init__(self, server=None):

known_args, _ = self.server.cli.parse_known_args()
self.input_paths = known_args.dataset
self.state.current_dataset = str(Path(self.input_paths[0]).resolve())
self.state.current_dataset = self.input_paths[0]

self.ctrl.get_image_fpath = lambda i: get_image_fpath(i, self.state.current_dataset)

self.context["image_objects"] = {}
self.context["images_manager"] = images_manager.ImagesManager()

self.state.collapse_dataset = False
self.state.collapse_embeddings = False
self.state.collapse_filter = False
self.state.collapse_transforms = False
self.state.client_only(
"collapse_dataset", "collapse_embeddings", "collapse_filter", "collapse_transforms"
)

self.state.horizontal_split = HORIZONTAL_SPLIT_DEFAULT_VALUE
self.state.vertical_split = VERTICAL_SPLIT_DEFAULT_VALUE
self.state.client_only("horizontal_split", "vertical_split")

transforms_translator = Translator()
transforms_translator.add_translation(
"feature_extraction_model", "current_transforms_model"
)
images = Images(server=self.server)

self._transforms_app = TransformsApp(
server=self.server.create_child_server(translator=transforms_translator)
)

embeddings_translator = Translator()
embeddings_translator.add_translation(
"feature_extraction_model", "current_embeddings_model"
server=self.server.create_child_server(), images=images
)

self._embeddings_app = EmbeddingsApp(
server=self.server.create_child_server(translator=embeddings_translator),
server=self.server.create_child_server(),
images=images,
)

filtering_translator = Translator()
Expand All @@ -95,15 +72,11 @@ def __init__(self, server=None):
server=self.server.create_child_server(translator=filtering_translator),
)

self._embeddings_app.set_on_select(self._transforms_app.set_selected_dataset_ids)
self._transforms_app.set_on_transform(self._embeddings_app.on_run_transformations)
self._embeddings_app.set_on_hover(self._transforms_app.on_image_hovered)
self._transforms_app.set_on_hover(self._embeddings_app.on_image_hovered)
self._filtering_app.set_on_apply_filter(self.on_filter_apply)

# Set state variable
self.state.trame__title = "nrtk_explorer"

# Bind instance methods to controller
self.ctrl.on_server_reload = self._build_ui
self.ctrl.add("on_server_ready")(self.on_server_ready)
Expand All @@ -112,84 +85,74 @@ def __init__(self, server=None):
self.state.num_images_disabled = True
self.state.random_sampling = False
self.state.random_sampling_disabled = True
self.state.images_id = []
self.state.dataset_ids = []
self.state.hovered_id = None

def clear_hovered(**kwargs):
self.state.hovered_id = None

self.state.change("dataset_ids")(clear_hovered)

self._build_ui()

def on_server_ready(self, *args, **kwargs):
# Bind instance methods to state change
self.state.change("current_dataset")(self.on_dataset_change)
self.state.change("num_images")(self.on_num_images_change)
self.state.change("random_sampling")(self.on_random_sampling_change)
self.state.change("num_images")(
debounce(NUM_IMAGES_DEBOUNCE_TIME, self.state)(self.resample_images)
)
self.state.change("random_sampling")(self.resample_images)

self.on_dataset_change()

def on_dataset_change(self, **kwargs):
# Reset cache
self.context.images_manager = images_manager.ImagesManager()
self.state.dataset_ids = [] # sampled images
self.context.dataset = get_dataset(self.state.current_dataset, force_reload=True)
self.state.num_images_max = len(self.context.dataset.imgs)
self.state.num_images = min(self.state.num_images_max, NUM_IMAGES_DEFAULT)
self.state.dirty("num_images") # Trigger resample_images()
self.state.random_sampling_disabled = False
self.state.num_images_disabled = False

self.reload_images()
self.state.annotation_categories = {
category["id"]: category for category in self.context.dataset.cats.values()
}

def on_filter_apply(self, filter: FilterProtocol[Iterable[int]], **kwargs):
selected_indices = []
for index, image_id in enumerate(self.state.images_ids):
selected_ids = []
for dataset_id in self.state.dataset_ids:
image_annotations_categories = [
annotation["category_id"]
for annotation in self.context.dataset.anns.values()
if annotation["image_id"] == image_id
if annotation["image_id"] == int(dataset_id)
]
include = filter.evaluate(image_annotations_categories)
if include:
selected_indices.append(index)
selected_ids.append(dataset_id)

self._embeddings_app.on_select(selected_indices)

def on_num_images_change(self, **kwargs):
self.reload_images()

def on_random_sampling_change(self, **kwargs):
self.reload_images()

def reload_images(self):
categories = {}
for category in self.context.dataset.cats.values():
categories[category["id"]] = category
self._embeddings_app.on_select(selected_ids)

def resample_images(self, **kwargs):
images = list(self.context.dataset.imgs.values())

selected_images = []
if self.state.num_images:
if self.state.random_sampling:
selected_images = random.sample(images, self.state.num_images)
selected_images = random.sample(images, min(len(images), self.state.num_images))
else:
selected_images = images[: self.state.num_images]
else:
selected_images = images

paths = list()
for image in selected_images:
paths.append(
os.path.join(
os.path.dirname(self.state.current_dataset),
image["file_name"],
)
)

self.context.paths = paths
self.state.annotation_categories = categories
self.state.images_ids = [img["id"] for img in selected_images]
self.state.dataset_ids = [str(img["id"]) for img in selected_images]

def _build_ui(self):
extra_args = {}
if self.server.hot_reload:
ui.reload(ui)
extra_args["reload"] = self._build_ui

self.ui = ui.build_layout(
self.ui = ui.NrtkExplorerLayout(
server=self.server,
dataset_paths=self.input_paths,
embeddings_app=self._embeddings_app,
Expand Down
Loading
Loading