2
2
import logging
3
3
from typing import Union , Sequence
4
4
5
+ import copy
5
6
import cv2
6
7
import itertools
7
8
import numpy as np
@@ -22,24 +23,49 @@ def _appmetadata(self):
22
23
pass
23
24
24
25
def _annotate (self , mmif : Union [str , dict , Mmif ], ** parameters ) -> Mmif :
26
+ """Internal Annotate Wrapper Method
27
+
28
+ Generates a new set of annotations for `mmif`
29
+ via EAST Text Detection on Videos and Images.
30
+
31
+ ### params
32
+ + mmif => a mmif object
33
+ + **parameters => runtime parameters (see `metadata.py`)
34
+
35
+ ### returns
36
+ + mmif object, with new app annotations.
37
+ """
38
+
39
+ # Run app on contained VideoDocument(s) in MMIF
25
40
for videodocument in mmif .get_documents_by_type (DocumentTypes .VideoDocument ):
26
41
# one view per video document
27
42
new_view = mmif .new_view ()
28
43
self .sign_view (new_view , parameters )
29
- config = self .get_configuration (** parameters )
30
- new_view .new_contain (AnnotationTypes .BoundingBox , document = videodocument .id , timeUnit = config ["timeUnit" ])
44
+ new_view .new_contain (AnnotationTypes .BoundingBox , document = videodocument .id , timeUnit = parameters ["timeUnit" ])
31
45
self .logger .debug (f"Running on video { videodocument .location_path ()} " )
32
- mmif = self .run_on_video (mmif , videodocument , new_view , ** config )
46
+ mmif = self .run_on_video (mmif , videodocument , new_view , ** parameters )
47
+
48
+ # Run app on contained ImageDocument(s) in MMIF
33
49
if mmif .get_documents_by_type (DocumentTypes .ImageDocument ):
34
50
# one view for all image documents
35
51
new_view = mmif .new_view ()
36
52
self .sign_view (new_view , parameters )
37
53
new_view .new_contain (AnnotationTypes .BoundingBox )
38
54
self .logger .debug (f"Running on all images" )
39
55
mmif = self .run_on_images (mmif , new_view )
56
+
40
57
return mmif
41
58
42
59
def run_on_images (self , mmif : Mmif , new_view : View ) -> Mmif :
60
+ """Run EAST on ImageDocuments
61
+
62
+ ### params
63
+ + mmif => Mmif Object
64
+ + new_view => a single mmif View (representing all ImageDocuments)
65
+
66
+ ### returns
67
+ + mmif, annotated with boundingboxes
68
+ """
43
69
for imgdocument in mmif .get_documents_by_type (DocumentTypes .ImageDocument ):
44
70
image = cv2 .imread (imgdocument .location )
45
71
box_list = image_to_east_boxes (image )
@@ -54,6 +80,16 @@ def run_on_images(self, mmif: Mmif, new_view: View) -> Mmif:
54
80
return mmif
55
81
56
82
def run_on_video (self , mmif : Mmif , videodocument : Document , new_view : View , ** config ) -> Mmif :
83
+ """Run EAST on a VideoDocument
84
+
85
+ ### params
86
+ + mmif => Mmif Object
87
+ + videodocument => VideoDocument file
88
+ + new_view => a single mmif View
89
+
90
+ ### returns
91
+ + mmif, annotated with boundingboxes
92
+ """
57
93
cap = vdh .capture (videodocument )
58
94
views_with_tframe = [v for v in mmif .get_views_for_document (videodocument .id )
59
95
if v .metadata .contains [AnnotationTypes .TimeFrame ]]
@@ -66,20 +102,20 @@ def run_on_video(self, mmif: Mmif, videodocument: Document, new_view: View, **co
66
102
for v in views_with_tframe for a in v .get_annotations (AnnotationTypes .TimeFrame )
67
103
if not frame_type or a .get_property ("frameType" ) in frame_type ])
68
104
target_frames = list (map (int , target_frames ))
69
- self .logger .debug (f"Processing frames { target_frames } from TimeFrame annotations of { frame_type } types" )
70
105
else :
71
106
target_frames = vdh .sample_frames (
72
- sample_ratio = config ['sampleRatio' ], start_frame = 0 ,
73
- end_frame = min (int (config ['stopAt' ]), videodocument .get_property ("frameCount" ))
107
+ start_frame = 0 ,
108
+ end_frame = min (int (config ['stopAt' ]), videodocument .get_property ("frameCount" )),
109
+ sample_rate = config ['sampleRate' ]
74
110
)
111
+
75
112
target_frames .sort ()
76
- self .logger .debug (f"Running on frames { target_frames } " )
77
- for fn , fi in zip (target_frames , vdh .extract_frames_as_images (videodocument , target_frames )):
78
- self .logger .debug (f"Processing frame { fn } " )
113
+
114
+ for fn , fi in zip (target_frames , vdh .extract_frames_as_images (videodocument , copy .deepcopy (target_frames ))):
79
115
result_list = image_to_east_boxes (fi )
80
116
for box in result_list :
81
117
bb_annotation = new_view .new_annotation (AnnotationTypes .BoundingBox )
82
- tp = vdh .convert (time = fn , in_unit = 'frame' , out_unit = config ['timeUnit' ], fps = videodocument .get_property ("fps" ))
118
+ tp = vdh .convert (t = fn , in_unit = 'frame' , out_unit = config ['timeUnit' ], fps = videodocument .get_property ("fps" ))
83
119
self .logger .debug (f"Adding a timepoint at frame: { fn } >> { tp } " )
84
120
85
121
tp_annotation = new_view .new_annotation (AnnotationTypes .TimePoint )
@@ -97,9 +133,16 @@ def run_on_video(self, mmif: Mmif, videodocument: Document, new_view: View, **co
97
133
98
134
return mmif
99
135
100
-
136
+ def get_app ():
137
+ """
138
+ This function effectively creates an instance of the app class, without any arguments passed in, meaning, any
139
+ external information such as initial app configuration should be set without using function arguments. The easiest
140
+ way to do this is to set global variables before calling this.
141
+ """
142
+ return EastTextDetection ()
101
143
102
144
if __name__ == "__main__" :
145
+
103
146
parser = argparse .ArgumentParser ()
104
147
parser .add_argument ("--port" , action = "store" , default = "5000" , help = "set port to listen" )
105
148
parser .add_argument ("--production" , action = "store_true" , help = "run gunicorn server" )
@@ -109,8 +152,8 @@ def run_on_video(self, mmif: Mmif, videodocument: Document, new_view: View, **co
109
152
parsed_args = parser .parse_args ()
110
153
111
154
# create the app instance
112
- app = EastTextDetection ()
113
-
155
+ app = get_app ()
156
+
114
157
http_app = Restifier (app , port = int (parsed_args .port ))
115
158
# for running the application in production mode
116
159
if parsed_args .production :
0 commit comments