|
1 | | -""" |
2 | | -This app takes in a mmif which has been annotated with bounding boxes. |
3 | | -For each timepoint that has a bounding box, the app produces a larger bounding box |
4 | | -using the outermost coordinates of the initial set. This produces a "concatenation" |
5 | | -effect, wherein the box is guaranteed to contain every other bounding box. This |
6 | | -is a useful bit of processing for downstream tasks. |
7 | | -""" |
8 | | -# ====================================| |
9 | | -# Import Statements |
10 | | -import argparse |
11 | | -import logging |
12 | 1 | from collections import defaultdict |
13 | | -from typing import Dict, List, Tuple, Union |
| 2 | +from typing import Dict, List |
14 | 3 |
|
15 | | -# Imports needed for Clams and MMIF. |
16 | | -# Non-NLP Clams applications will require AnnotationTypes |
| 4 | +from mmif import AnnotationTypes |
17 | 5 |
|
18 | | -from clams import ClamsApp, Restifier |
19 | | -from mmif import Mmif, View, Annotation, Document, AnnotationTypes, DocumentTypes |
20 | | - |
21 | | -# For an NLP tool we need to import the LAPPS vocabulary items |
22 | | -from lapps.discriminators import Uri |
23 | | -# ====================================| |
24 | | - |
25 | | -class BoundingboxConcatenation(ClamsApp): |
26 | | - def __init__(self): |
27 | | - super().__init__() |
28 | | - |
29 | | - def _appmetadata(self): |
30 | | - # see `metadata.py` |
31 | | - pass |
32 | | - |
33 | | - def _annotate(self, mmif: Union[str, dict, Mmif], **parameters) -> Mmif: |
34 | | - |
35 | | - # see https://sdk.clams.ai/autodoc/clams.app.html#clams.app.ClamsApp._annotate |
36 | | - |
37 | | - # initialize mmif view |
38 | | - if not isinstance(mmif, Mmif): |
39 | | - mmif_obj = Mmif(mmif) |
40 | | - else: |
41 | | - mmif_obj = mmif |
42 | | - new_view = mmif_obj.new_view() |
43 | | - self.sign_view(new_view, parameters) |
44 | | - new_view.new_contain( |
45 | | - AnnotationTypes.BoundingBox |
46 | | - ) |
47 | | - |
48 | | - # get bounding-box alignment |
| 6 | +if __name__ == '__main__': |
| 7 | + |
| 8 | + def read_small_boxes(mmif_obj, **parameters): |
49 | 9 | alignment_annotations = mmif_obj.get_alignments( |
50 | 10 | at_type1=AnnotationTypes.TimePoint, at_type2=AnnotationTypes.BoundingBox |
51 | 11 | ) |
@@ -85,14 +45,13 @@ def _annotate(self, mmif: Union[str, dict, Mmif], **parameters) -> Mmif: |
85 | 45 | box_dict[timepoint_anno].append(box_anno) |
86 | 46 |
|
87 | 47 | # concatenate bounding boxes and add to mmif |
88 | | - out_coords = self.make_boxes(box_dict) |
89 | | - mmif_obj = self.annotate_boxes(mmif_obj, new_view, out_coords, **parameters) |
90 | | - |
| 48 | + out_coords = make_big_boxes(box_dict) |
91 | 49 |
|
92 | 50 | return mmif_obj |
93 | 51 |
|
| 52 | + |
94 | 53 | @staticmethod |
95 | | - def make_boxes(boundingbox_dictionary) -> Dict[float, List[List[float]]]: |
| 54 | + def make_big_boxes(boundingbox_dictionary) -> Dict[float, List[List[float]]]: |
96 | 55 | """Perform bounding-box concatenation |
97 | 56 |
|
98 | 57 | ### params |
@@ -138,63 +97,3 @@ def make_boxes(boundingbox_dictionary) -> Dict[float, List[List[float]]]: |
138 | 97 | c, d = current_max_x, current_max_y |
139 | 98 | out[timepoint] = [[a, b], [c, b], [a, d], [c, d]] |
140 | 99 | return out |
141 | | - |
142 | | - @staticmethod |
143 | | - def annotate_boxes(mmif: Mmif, |
144 | | - view: View, |
145 | | - coords: Dict, |
146 | | - **config) -> Mmif: |
147 | | - """Perform mmif annotation with new coordinates. |
148 | | - |
149 | | - ### params |
150 | | - + mmif => Mmif object we are annotating |
151 | | - + view => View to which we are adding annotations |
152 | | - + coords => Dict of individual bounding boxes for each timepoint |
153 | | -
|
154 | | - ### returns |
155 | | - + Mmif object with new view annotations |
156 | | - """ |
157 | | - for time_point, box_coords in coords.items(): |
158 | | - bb_annotation = view.new_annotation(AnnotationTypes.BoundingBox) |
159 | | - tp_annotation = view.new_annotation(AnnotationTypes.TimePoint) |
160 | | - tp_annotation.add_property("timeUnit", config["timeUnit"]) |
161 | | - tp_annotation.add_property("timePoint", time_point) |
162 | | - |
163 | | - bb_annotation.add_property("label", config["label"]) |
164 | | - |
165 | | - bb_annotation.add_property("coordinates", box_coords) |
166 | | - |
167 | | - alignment_annotation = view.new_annotation(AnnotationTypes.Alignment) |
168 | | - alignment_annotation.add_property("source", tp_annotation.id) |
169 | | - alignment_annotation.add_property("target", bb_annotation.id) |
170 | | - |
171 | | - return mmif |
172 | | - |
173 | | - |
174 | | -def get_app(): |
175 | | - """ |
176 | | - This function effectively creates an instance of the app class, without any arguments passed in, meaning, any |
177 | | - external information such as initial app configuration should be set without using function arguments. The easiest |
178 | | - way to do this is to set global variables before calling this. |
179 | | - """ |
180 | | - return BoundingboxConcatenation() |
181 | | - |
182 | | - |
183 | | -if __name__ == "__main__": |
184 | | - parser = argparse.ArgumentParser() |
185 | | - parser.add_argument("--port", action="store", default="5000", help="set port to listen") |
186 | | - parser.add_argument("--production", action="store_true", help="run gunicorn server") |
187 | | - |
188 | | - parsed_args = parser.parse_args() |
189 | | - |
190 | | - # create the app instance |
191 | | - app = get_app() |
192 | | - |
193 | | - http_app = Restifier(app, port=int(parsed_args.port)) |
194 | | - # for running the application in production mode |
195 | | - if parsed_args.production: |
196 | | - http_app.serve_production() |
197 | | - # development mode |
198 | | - else: |
199 | | - app.logger.setLevel(logging.DEBUG) |
200 | | - http_app.run() |
0 commit comments