Skip to content
Open
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
48 changes: 47 additions & 1 deletion biohack_utils/omero_annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ def _create_collection(conn, name, version="0.x"):
return saved.getId().getValue()


def _create_collection_from_dict(conn, json_dict):
map_annotation = MapAnnotationI()
map_annotation.setNs(rstring(NS_COLLECTION))

kv_pairs = [NamedValue(key, value) for (key, value) in json_dict.items()]
map_annotation.setMapValue(kv_pairs)

# We save this in a server.
update_service = conn.getUpdateService()
saved = update_service.saveAndReturnObject(map_annotation)

return saved.getId().getValue()


def _link_collection_to_image(conn, collection_ann_id, image_id):
"""Link an existing collection annotation to an image.
"""
Expand All @@ -97,7 +111,12 @@ def _link_collection_to_image(conn, collection_ann_id, image_id):
if annotation is None:
raise ValueError("Annotation {} not found".format(collection_ann_id))

image.linkAnnotation(annotation)
# Check if image is already linked to collection
ann_ids = [annotation.getId() for annotation in image.listAnnotations()]
if collection_ann_id in ann_ids:
print("Collection ID is already linked to image.")
else:
image.linkAnnotation(annotation)


def _create_map_annotation(conn, kv, namespace):
Expand Down Expand Up @@ -139,6 +158,33 @@ def _add_node_annotation(
image.linkAnnotation(ann)
return ann.getId()


def _add_node_annotation_from_dict(
conn, image_id, collection_id, node_dict
):
"""Add a node annotation to an image describing its role in the collection.
Returns the created annotation id.
"""
kv = {"collection_id": str(collection_id)}
for (key, value) in node_dict.items():
if key == "attributes":
for (a_key, a_val) in node_dict["attributes"]:
kv[f"attributes.{a_key}"] = a_val
else:
kv[key] = value

image = conn.getObject("Image", image_id)
if image is None:
raise ValueError(f"Image {image_id} not found")

# Check if collection id already exists within MapAnnotations
for annotation in image.listAnnotations():
kvpairs = annotation.getMapValue()
for kv in kvpairs:
if kv.name == "collection_id" and kv.value == str(collection_id):
print(f"Node annotation already exists for image id {image_id}.")
return annotation.getId()

ann = _create_map_annotation(conn, kv, NS_NODE)
image.linkAnnotation(ann)
return ann.getId()
Expand Down
126 changes: 109 additions & 17 deletions development/connect_annotations.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
from biohack_utils.util import omero_credential_parser, connect_to_omero
import argparse
import json
from typing import List, Optional

import numpy as np

from biohack_utils.util import connect_to_omero, _upload_image, _upload_volume
from biohack_utils import omero_annotation
from biohack_utils.omero_annotation import NS_NODE


DEFAULT_COLLECTION = {
"version": "0.0.1",
"type": "collection",
"name": "cells",
}


def load_omero_labels_in_napari(conn, image_id, is_3d=False):
Expand Down Expand Up @@ -29,6 +43,65 @@ def load_omero_labels_in_napari(conn, image_id, is_3d=False):
napari.run()


def get_collection_dict(json_dict, target_key="type", target_value="collection"):
for (key, value) in json_dict.items():
if isinstance(value, dict):
if target_key in list(value.keys()):
if value[target_key] == target_value:
return value
return None


def write_annotation_to_image(
conn,
json_dict: str,
image_ids: Optional[List[int]] = None,
image_arr: Optional[np.ndarray] = None,
collection_id: Optional[int] = None,
):
if image_ids is None:
image_ids = [int(key) for key in json_dict[NS_NODE]]

print(image_ids)
if image_ids is None and image_arr is None:
raise ValueError("Supply either image ID or an array.")

if image_arr is not None:
# TODO get correct entry of name
name = json_dict["name"]

if len(image_arr.shape) == 2:
image_id = _upload_image(conn, image_arr, name)

elif len(image_arr.shape) == 3:
image_id = _upload_volume(conn, image_arr, name)

else:
raise ValueError("Input data must have 2D or 3D shape.")
image_ids = [image_id]

# create new collection if collection_id is not supplied
if collection_id is None:
collection_dict = get_collection_dict(json_dict)
if collection_dict is None:
collection_dict = DEFAULT_COLLECTION

collection_id = omero_annotation._create_collection_from_dict(conn, collection_dict)

for image_id in image_ids:
print("Link collection to an image")
omero_annotation._link_collection_to_image(conn, collection_id, image_id)

node_dict = json_dict[NS_NODE][str(image_id)]

omero_annotation._add_node_annotation_from_dict(conn, image_id, collection_id, node_dict)

for iid in image_ids:
print("Build image url")
link = omero_annotation._build_image_url(iid)
omero_annotation._append_link_to_node_annotation(conn, iid, link)


def write_annotations_to_image_and_labels(conn, image_id, label_id):
# Creates a new collection based on label images.
ann_id = omero_annotation._create_collection(conn, "cells", "0.0.1")
Expand All @@ -55,33 +128,52 @@ def write_annotations_to_image_and_labels(conn, image_id, label_id):


def main():
parser = omero_credential_parser()
parser = argparse.ArgumentParser(
description="Connect ids.")

parser.add_argument("-u", "--username", type=str, required=True)
parser.add_argument("-p", "--password", type=str, required=True)

parser.add_argument("--raw_id", nargs="+", type=int, default=None)
parser.add_argument("--label_id", type=int, default=None)

parser.add_argument("--json", type=str, default=None,
help="Path to dictionary in JSON format.")
parser.add_argument("--collection_id", type=str, default=None,
help="Collection ID to add images to. Per default, a new collection will be created.")

args = parser.parse_args()

conn = connect_to_omero(args)

# Scripts to drop metadata.
if args.raw_id is not None and args.label_id is not None:

# 1. For LIVECell (2d)
raw_id = 35394 # The available LIVECell image on the OMERO server.
label_id = 35395 # The corresponding labels image for LIVECell on the OMERO server.
# 1. For LIVECell (2d)
# raw_id = 35394 # The available LIVECell image on the OMERO server.
# label_id = 35395 # The corresponding labels image for LIVECell on the OMERO server.

# 2. For CochleaNet (3d)
# raw_id = 35499
# label_id = 35500
# 2. For CochleaNet (3d)
# raw_id = 35499
# label_id = 35500

# 3. For multi-label images (2d)
# raw_id = 35478
# 3. For multi-label images (2d)
# raw_id = 35478

# 4. For CovidIF HCS data (2d)
# raw_id = [35501, 35502]
# label_id = 35503
# 4. For CovidIF HCS data (2d)
# raw_id = [35501, 35502]
# label_id = 35503

# Writes annotations in expected format.
# write_annotations_to_image_and_labels(conn, raw_id, label_id)
# Writes annotations in expected format.
write_annotations_to_image_and_labels(conn, args.raw_id, args.label_id)

# Loading existing stuff.
load_omero_labels_in_napari(conn, raw_id)
elif args.json is not None:
with open(args.json) as f:
json_dict = json.load(f)
write_annotation_to_image(conn, json_dict, collection_id=args.collection_id)
else:
conn.close()
raise ValueError("Supply either raw or label id or a JSON dictionary.")

conn.close()

Expand Down
48 changes: 48 additions & 0 deletions development/human_cells.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"ome/collection": {
"version": "0.0.1",
"type": "collection",
"name": "cell"
},
"ome/collection/nodes": {
"35515": {
"category": "Intensities",
"origin": "Raw",
"name": "human_cells a",
"description": "Human HT29 from Moffat et al. doi: 10.1016/j.cell.2006.01.040"
},
"35507": {
"category": "Annotations",
"origin": "Masks",
"name": "micro-sam a",
"description": "Automatic micro-sam segmentation",
"source_image_id": 35515
},
"35514": {
"category": "Intensities",
"origin": "Raw",
"name": "human_cells b",
"description": "Human HT29 from Moffat et al. doi: 10.1016/j.cell.2006.01.040"
},
"35508": {
"category": "Annotations",
"origin": "Masks",
"name": "micro-sam b",
"description": "Automatic micro-sam segmentation",
"source_image_id": 35514
},
"35513": {
"category": "Intensities",
"origin": "Raw",
"name": "human_cells c",
"description": "Human HT29 from Moffat et al. doi: 10.1016/j.cell.2006.01.040"
},
"35509": {
"category": "Annotations",
"origin": "Masks",
"name": "micro-sam c",
"description": "Automatic micro-sam segmentation",
"source_image_id": 35513
}
}
}
29 changes: 29 additions & 0 deletions development/template_parse_imageid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"ome/collection": {
"version": "0.0.1",
"type": "collection",
"name": "cell"
},
"ome/collection/nodes": {
"<image_id_01>": {
"category": "Intensities",
"origin": "Raw",
"name": "raw image",
"description": "Lorem ipsum"
},
"<image_id_02>": {
"category": "Intensities",
"origin": "Processed",
"name": "processed image",
"description": "Lorem ipsum",
"source_image_id": ["<image_id_01>"]
},
"<image_id_03>": {
"category": "Annotations",
"origin": "Masks",
"name": "masks",
"description": "Lorem ipsum",
"source_image_id": ["<image_id_01>", "<image_id_02>"]
}
}
}
2 changes: 1 addition & 1 deletion development/upload_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def upload_data(conn, fpath, name, labels=False):

def main():
parser = argparse.ArgumentParser(
description="Upload_ ata to Omero web.")
description="Upload data to Omero web.")

parser.add_argument("-u", "--username", type=str, required=True)
parser.add_argument("-p", "--password", type=str, required=True)
Expand Down