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

Generic read file #16

Merged
merged 4 commits into from
Dec 15, 2023
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
25 changes: 8 additions & 17 deletions grand_challenge_forge/generation_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,17 @@ def enrich_phase_context(context):
*phase_context["inputs"],
*phase_context["outputs"],
]:
ci["is_json"] = ci["kind"] == "Anything" or ci[
ci["is_json"] = ci["relative_path"].endswith(".json")
ci["is_image"] = ci["super_kind"] == "Image"
ci["is_file"] = ci["super_kind"] == "File" and not ci[
"relative_path"
].endswith(".json")
ci["is_image"] = ci["super_kind"] == "Image"

phase_context["has_input_json"] = any(
ci["is_json"] for ci in phase_context["inputs"]
)

phase_context["has_output_json"] = any(
ci["is_json"] for ci in phase_context["outputs"]
)

phase_context["has_input_image"] = any(
ci["is_image"] for ci in phase_context["inputs"]
)

phase_context["has_output_image"] = any(
ci["is_image"] for ci in phase_context["outputs"]
)
for _type in ["json", "image", "file"]:
for in_out in ["input", "output"]:
phase_context[f"has_{in_out}_{_type}"] = any(
ci[f"is_{_type}"] for ci in phase_context[f"{in_out}s"]
)


def create_civ_stub_file(*, target_dir, component_interface):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,13 @@ def run():
print(f.read())

# For now, let us set make bogus predictions
{% for ci in cookiecutter.phase.outputs -%}
{%- for ci in cookiecutter.phase.outputs %}
{{ ci.slug | replace("-", "_")}} =
{%- if ci.is_image %} numpy.eye(4, 2)
{%- else %} {"content": "should match the required format"}
{%- elif ci.is_json %} {"content": "should match the required format"}
{%- elif ci.is_file %} "content: should match the required format"
{% endif %}
{% endfor -%}
{%- endfor %}

# Save your output
{% for ci in cookiecutter.phase.outputs -%}
Expand All @@ -77,27 +78,33 @@ def run():
content={{ py_slug }}
)
{% endif -%}
{% if ci.is_file -%}
write_file(
location=OUTPUT_PATH / "{{ ci.relative_path }}",
content={{ py_slug }}
)
{% endif -%}
{% endfor %}
return 0
{%- if cookiecutter.phase.has_input_json %}


{% if cookiecutter.phase.has_input_json -%}
def load_json_file(*, location):
# Reads a json file
with open(location, 'r') as f:
return json.loads(f.read())
{%- endif %}
{%- if cookiecutter.phase.has_output_json %}


{% if cookiecutter.phase.has_output_json -%}
def write_json_file(*, location, content):
# Writes a json file
with open(location, 'w') as f:
f.write(json.dumps(content, indent=4))
{%- endif %}
{%- if cookiecutter.phase.has_input_image %}


{% if cookiecutter.phase.has_input_image -%}
def load_image_file_as_array(*, location):
# Use SimpleITK to read a file
input_files = glob(str(location / "*"))
Expand All @@ -106,9 +113,9 @@ def load_image_file_as_array(*, location):
# Convert it to a Numpy array
return SimpleITK.GetArrayFromImage(result)
{%- endif %}
{%- if cookiecutter.phase.has_output_image %}


{% if cookiecutter.phase.has_output_image -%}
def write_array_as_image_file(*, location, array):
location.mkdir(parents=True, exist_ok=True)

Expand All @@ -119,6 +126,28 @@ def write_array_as_image_file(*, location, array):
useCompression=True,
)
{%- endif %}
{%- if cookiecutter.phase.has_input_file %}


# Note to the challenge hosts:
# the following function is very generic and should likely
# be adopted to something more specific for your challenge
def load_file(*, location):
# Reads the content of a file
with open(location) as f:
return f.read()
{%- endif %}
{%- if cookiecutter.phase.has_output_file %}


# Note to the challenge hosts:
# the following function is very generic and should likely
# be adopted to something more specific for your challenge
def write_file(*, location, content):
# Write the content to a file
with open(location, 'w') as f:
return f.write(content)
{%- endif %}


def _show_torch_cuda_info():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,40 +67,59 @@ def process(job):
report += pformat(job)
report += "\n"

# First read the results
{% for ci in cookiecutter.phase.outputs -%}
{% set py_slug = ci.slug | replace("-", "_") -%}

# Firstly, find the location of the results
{% for ci in cookiecutter.phase.outputs %}
{%- set py_slug = ci.slug | replace("-", "_") -%}
{{ py_slug }}_location = get_file_location(
job_pk=job["pk"],
values=job["outputs"],
slug="{{ ci.slug }}",
)
{% endfor %}

# Secondly, read the results
{% for ci in cookiecutter.phase.outputs -%}
{% set py_slug = ci.slug | replace("-", "_") -%}
{% if ci.is_image -%}
{{ py_slug }} = load_image_file(location={{ py_slug }}_location)
{{ py_slug }} = load_image_file(
location={{ py_slug }}_location,
)
{% endif -%}
{% if ci.is_json -%}
{{ py_slug }} = load_json_file(location={{ py_slug }}_location)
{{ py_slug }} = load_json_file(
location={{ py_slug }}_location,
)
{% endif -%}
{% endfor -%}
# Retrieve the input image name to match it with an image in your ground truth
{% if ci.is_file -%}
{{ py_slug }} = load_file(
location={{ py_slug }}_location,
)
{% endif -%}
{%- endfor %}


# Thirdly, retrieve the input image name to match it with an image in your ground truth
{% for ci in cookiecutter.phase.inputs -%}
{% set py_slug = ci.slug | replace("-", "_") -%}
{% if ci.is_image -%}
{{ py_slug }}_image_name = get_image_name(
values=job["inputs"],
slug="{{ ci.slug }}",
)

)
{% endif -%}
{% endfor -%}
{%- endfor %}

# Now you would need to load your ground truth
# make sure to include it in your evaluation container
# Fourthly, your load your ground truth
# Include it in your evaluation container by placing it in ground_truth/
with open(GROUND_TRUTH_DIRECTORY / "some_resource.txt", "r") as f:
report += f.read()
# compare the results to your ground truth and compute some metrics

print(report)


# Finally, calculate by comparing the ground truth to the actual results
return {
"my_metric": random.choice([1, 0]),
}
Expand All @@ -119,16 +138,18 @@ def read_predictions():
# The prediction file tells us the location of the users' predictions
with open(INPUT_DIRECTORY / "predictions.json") as f:
return json.loads(f.read())
{%- if cookiecutter.phase.has_input_image or cookiecutter.phase.has_output_image %}


{% if cookiecutter.phase.has_input_image or cookiecutter.phase.has_output_image%}
def get_image_name(*, values, slug):
# This tells us the user-provided name of the input or output image
for value in values:
if value["interface"]["slug"] == slug:
return value["image"]["name"]

raise RuntimeError(f"Image with interface {slug} not found!")
{% endif %}
{%- endif %}


def get_interface_relative_path(*, values, slug):
# Gets the location of the interface relative to the input or output
Expand All @@ -143,15 +164,17 @@ def get_file_location(*, job_pk, values, slug):
# Where a job's output file will be located in the evaluation container
relative_path = get_interface_relative_path(values=values, slug=slug)
return INPUT_DIRECTORY / job_pk / "output" / relative_path
{%- if cookiecutter.phase.has_output_json %}


{% if cookiecutter.phase.has_output_json %}
def load_json_file(*, location):
# Reads a json file
with open(location) as f:
return json.loads(f.read())
{% endif %}
{%- endif %}
{%- if cookiecutter.phase.has_output_image %}


{% if cookiecutter.phase.has_output_image -%}
def load_image_file(*, location):
# Use SimpleITK to read a file
input_files = glob(str(location / "*"))
Expand All @@ -160,6 +183,14 @@ def load_image_file(*, location):
# Convert it to a Numpy array
return SimpleITK.GetArrayFromImage(result)
{%- endif %}
{%- if cookiecutter.phase.has_output_file %}


def load_file(*, location):
# Reads the content of a file
with open(location) as f:
return f.read()
{%- endif %}


def write_metrics(*, metrics):
Expand Down
20 changes: 19 additions & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@
"slug": "yet-another-input-ci-slug",
"kind": "Anything",
"super_kind": "Value",
"relative_path": "another-input-value.json"
"relative_path": "yet-another-input-value.json"
},
{
"slug": "yet-another-non-json-input-ci-slug",
"kind": "Anything",
"super_kind": "File",
"relative_path": "yet-another-non-json-input-value"
}
],
"outputs": [
Expand All @@ -44,6 +50,18 @@
"kind": "Anything",
"super_kind": "File",
"relative_path": "output-value.json"
},
{
"slug": "yet-another-output-ci-slug",
"kind": "Anything",
"super_kind": "Value",
"relative_path": "yet-another-output-value.json"
},
{
"slug": "yet-another-non-json-output-ci-slug",
"kind": "Anything",
"super_kind": "File",
"relative_path": "yet-another-non-json-output-value"
}
]
},
Expand Down