endoreg-db 0.3.5__py3-none-any.whl → 0.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. endoreg_db/admin.py +3 -3
  2. endoreg_db/apps.py +6 -6
  3. endoreg_db/data/__init__.py +64 -64
  4. endoreg_db/data/active_model/data.yaml +2 -2
  5. endoreg_db/data/case_template/rule/00_patient_lab_sample_add_default_value.yaml +167 -167
  6. endoreg_db/data/case_template/rule/01_patient-set-age.yaml +7 -7
  7. endoreg_db/data/case_template/rule/01_patient-set-gender.yaml +8 -8
  8. endoreg_db/data/case_template/rule/11_create_patient_lab_sample.yaml +22 -22
  9. endoreg_db/data/case_template/rule/12_create-patient_medication-anticoagulation.yaml +18 -18
  10. endoreg_db/data/case_template/rule/13_create-patient_medication_schedule-anticoagulation.yaml +18 -18
  11. endoreg_db/data/case_template/rule/19_create_patient.yaml +16 -16
  12. endoreg_db/data/case_template/rule_type/base_types.yaml +35 -35
  13. endoreg_db/data/case_template/rule_value_type/base_types.yaml +58 -58
  14. endoreg_db/data/case_template/template/base.yaml +7 -7
  15. endoreg_db/data/case_template/template_type/pre_endoscopy.yaml +2 -2
  16. endoreg_db/data/case_template/tmp/_rule_value +13 -13
  17. endoreg_db/data/case_template/tmp/rule/01_atrial_fibrillation.yaml +21 -21
  18. endoreg_db/data/case_template/tmp/rule/02_create_object.yaml +9 -9
  19. endoreg_db/data/case_template/tmp/template/atrial_fibrillation_low_risk.yaml +6 -6
  20. endoreg_db/data/center/data.yaml +59 -59
  21. endoreg_db/data/center_resource/green_endoscopy_dashboard_CenterResource.yaml +144 -144
  22. endoreg_db/data/center_waste/green_endoscopy_dashboard_CenterWaste.yaml +48 -48
  23. endoreg_db/data/disease/cardiovascular.yaml +37 -37
  24. endoreg_db/data/disease/hepatology.yaml +4 -4
  25. endoreg_db/data/disease/misc.yaml +5 -5
  26. endoreg_db/data/disease/renal.yaml +4 -4
  27. endoreg_db/data/disease_classification/chronic_kidney_disease.yaml +5 -5
  28. endoreg_db/data/disease_classification/coronary_vessel_disease.yaml +5 -5
  29. endoreg_db/data/disease_classification_choice/chronic_kidney_disease.yaml +40 -40
  30. endoreg_db/data/disease_classification_choice/coronary_vessel_disease.yaml +19 -19
  31. endoreg_db/data/distribution/date/patient.yaml +6 -6
  32. endoreg_db/data/distribution/single_categorical/patient.yaml +6 -6
  33. endoreg_db/data/emission_factor/green_endoscopy_dashboard_EmissionFactor.yaml +132 -132
  34. endoreg_db/data/endoscope_type/data.yaml +10 -10
  35. endoreg_db/data/endoscopy_processor/data.yaml +45 -45
  36. endoreg_db/data/event/cardiology.yaml +27 -27
  37. endoreg_db/data/event/neurology.yaml +13 -13
  38. endoreg_db/data/event/surgery.yaml +12 -12
  39. endoreg_db/data/event/thrombembolism.yaml +19 -19
  40. endoreg_db/data/examination/examinations/data.yaml +65 -65
  41. endoreg_db/data/examination/time/data.yaml +47 -47
  42. endoreg_db/data/examination/time-type/data.yaml +7 -7
  43. endoreg_db/data/examination/type/data.yaml +5 -5
  44. endoreg_db/data/gender/data.yaml +18 -18
  45. endoreg_db/data/information_source/data.yaml +30 -30
  46. endoreg_db/data/information_source/medication.yaml +5 -5
  47. endoreg_db/data/lab_value/cardiac_enzymes.yaml +30 -30
  48. endoreg_db/data/lab_value/coagulation.yaml +48 -48
  49. endoreg_db/data/lab_value/electrolytes.yaml +189 -189
  50. endoreg_db/data/lab_value/gastrointestinal_function.yaml +121 -121
  51. endoreg_db/data/lab_value/hematology.yaml +169 -169
  52. endoreg_db/data/lab_value/hormones.yaml +53 -53
  53. endoreg_db/data/lab_value/lipids.yaml +44 -44
  54. endoreg_db/data/lab_value/misc.yaml +30 -30
  55. endoreg_db/data/lab_value/renal_function.yaml +10 -10
  56. endoreg_db/data/label/label/data.yaml +62 -62
  57. endoreg_db/data/label/label-set/data.yaml +17 -17
  58. endoreg_db/data/label/label-type/data.yaml +6 -6
  59. endoreg_db/data/medication/anticoagulation.yaml +64 -64
  60. endoreg_db/data/medication/tah.yaml +69 -69
  61. endoreg_db/data/medication_indication/anticoagulation.yaml +120 -120
  62. endoreg_db/data/medication_indication_type/data.yaml +10 -10
  63. endoreg_db/data/medication_indication_type/thrombembolism.yaml +40 -40
  64. endoreg_db/data/medication_intake_time/base.yaml +30 -30
  65. endoreg_db/data/medication_schedule/apixaban.yaml +94 -94
  66. endoreg_db/data/medication_schedule/ass.yaml +12 -12
  67. endoreg_db/data/medication_schedule/enoxaparin.yaml +26 -26
  68. endoreg_db/data/model_type/data.yaml +6 -6
  69. endoreg_db/data/patient_lab_sample_type/generic.yaml +5 -5
  70. endoreg_db/data/pdf_type/data.yaml +28 -28
  71. endoreg_db/data/product/green_endoscopy_dashboard_Product.yaml +66 -66
  72. endoreg_db/data/product_group/green_endoscopy_dashboard_ProductGroup.yaml +33 -33
  73. endoreg_db/data/product_material/green_endoscopy_dashboard_ProductMaterial.yaml +308 -308
  74. endoreg_db/data/product_weight/green_endoscopy_dashboard_ProductWeight.yaml +88 -88
  75. endoreg_db/data/profession/data.yaml +70 -70
  76. endoreg_db/data/reference_product/green_endoscopy_dashboard_ReferenceProduct.yaml +55 -55
  77. endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +26 -26
  78. endoreg_db/data/report_reader_flag/ukw-histology-generic.yaml +19 -19
  79. endoreg_db/data/resource/green_endoscopy_dashboard_Resource.yaml +15 -15
  80. endoreg_db/data/transport_route/green_endoscopy_dashboard_TransportRoute.yaml +12 -12
  81. endoreg_db/data/unit/concentration.yaml +92 -92
  82. endoreg_db/data/unit/data.yaml +17 -17
  83. endoreg_db/data/unit/length.yaml +30 -30
  84. endoreg_db/data/unit/misc.yaml +19 -19
  85. endoreg_db/data/unit/rate.yaml +5 -5
  86. endoreg_db/data/unit/time.yaml +12 -12
  87. endoreg_db/data/unit/volume.yaml +35 -35
  88. endoreg_db/data/unit/weight.yaml +37 -37
  89. endoreg_db/data/waste/data.yaml +11 -11
  90. endoreg_db/forms/__init__.py +2 -2
  91. endoreg_db/forms/questionnaires/tto_questionnaire.py +23 -23
  92. endoreg_db/forms/settings/__init__.py +8 -8
  93. endoreg_db/forms/unit.py +5 -5
  94. endoreg_db/management/commands/_load_model_template.py +40 -40
  95. endoreg_db/management/commands/delete_all.py +18 -18
  96. endoreg_db/management/commands/delete_legacy_images.py +19 -19
  97. endoreg_db/management/commands/delete_legacy_videos.py +16 -16
  98. endoreg_db/management/commands/extract_legacy_video_frames.py +18 -18
  99. endoreg_db/management/commands/fetch_legacy_image_dataset.py +32 -32
  100. endoreg_db/management/commands/fix_auth_permission.py +20 -20
  101. endoreg_db/management/commands/import_legacy_images.py +94 -94
  102. endoreg_db/management/commands/import_legacy_videos.py +76 -76
  103. endoreg_db/management/commands/load_active_model_data.py +44 -44
  104. endoreg_db/management/commands/load_ai_model_data.py +44 -44
  105. endoreg_db/management/commands/load_base_db_data.py +128 -128
  106. endoreg_db/management/commands/load_center_data.py +42 -42
  107. endoreg_db/management/commands/load_disease_classification_choices_data.py +40 -40
  108. endoreg_db/management/commands/load_disease_classification_data.py +40 -40
  109. endoreg_db/management/commands/load_disease_data.py +39 -39
  110. endoreg_db/management/commands/load_distribution_data.py +65 -65
  111. endoreg_db/management/commands/load_endoscope_type_data.py +44 -44
  112. endoreg_db/management/commands/load_endoscopy_processor_data.py +44 -44
  113. endoreg_db/management/commands/load_event_data.py +40 -40
  114. endoreg_db/management/commands/load_examination_data.py +74 -74
  115. endoreg_db/management/commands/load_g_play_data.py +112 -112
  116. endoreg_db/management/commands/load_gender_data.py +43 -43
  117. endoreg_db/management/commands/load_green_endoscopy_wuerzburg_data.py +132 -132
  118. endoreg_db/management/commands/load_information_source.py +44 -44
  119. endoreg_db/management/commands/load_lab_value_data.py +49 -49
  120. endoreg_db/management/commands/load_label_data.py +66 -66
  121. endoreg_db/management/commands/load_medication_data.py +40 -40
  122. endoreg_db/management/commands/load_medication_indication_data.py +62 -62
  123. endoreg_db/management/commands/load_medication_indication_type_data.py +40 -40
  124. endoreg_db/management/commands/load_medication_intake_time_data.py +40 -40
  125. endoreg_db/management/commands/load_medication_schedule_data.py +54 -54
  126. endoreg_db/management/commands/load_pdf_type_data.py +60 -60
  127. endoreg_db/management/commands/load_profession_data.py +43 -43
  128. endoreg_db/management/commands/load_report_reader_flag.py +45 -45
  129. endoreg_db/management/commands/load_unit_data.py +45 -45
  130. endoreg_db/management/commands/load_user_groups.py +28 -28
  131. endoreg_db/management/commands/register_ai_model.py +65 -65
  132. endoreg_db/management/commands/reset_celery_schedule.py +9 -9
  133. endoreg_db/migrations/0001_initial.py +582 -582
  134. endoreg_db/migrations/0002_rawvideofile.py +26 -26
  135. endoreg_db/migrations/0003_rawvideofile_frames_required.py +18 -18
  136. endoreg_db/migrations/0004_rename_hash_rawvideofile_video_hash.py +18 -18
  137. endoreg_db/migrations/0005_ffmpegmeta_remove_videoimportmeta_center_and_more.py +56 -56
  138. endoreg_db/migrations/0006_rawvideofile_center_alter_videometa_processor.py +25 -25
  139. endoreg_db/migrations/0007_rawvideofile_processor.py +19 -19
  140. endoreg_db/migrations/0008_rename_frames_required_rawvideofile_state_frames_required.py +18 -18
  141. endoreg_db/migrations/0009_sensitivemeta_rawvideofile_sensitive_meta.py +31 -31
  142. endoreg_db/migrations/0010_rename_endoscope_serial_number_sensitivemeta_endoscope_sn.py +18 -18
  143. endoreg_db/migrations/0011_rawvideofile_state_sensitive_data_retrieved.py +18 -18
  144. endoreg_db/migrations/0012_rawvideofile_prediction_dir_and_more.py +109 -109
  145. endoreg_db/migrations/0013_rawpdffile.py +31 -31
  146. endoreg_db/migrations/0014_pdftype_alter_rawpdffile_file_pdfmeta.py +38 -38
  147. endoreg_db/migrations/0015_rename_report_processed_rawpdffile_state_report_processed_and_more.py +31 -31
  148. endoreg_db/migrations/0016_rawpdffile_state_report_processing_required.py +18 -18
  149. endoreg_db/migrations/0017_firstname_lastname_center_first_names_and_more.py +37 -37
  150. endoreg_db/migrations/0018_reportreaderflag_reportreaderconfig.py +37 -37
  151. endoreg_db/migrations/0019_pdftype_cut_off_above_lines_and_more.py +42 -42
  152. endoreg_db/migrations/0020_rename_endoscopy_info_line_pdftype_endoscope_info_line.py +18 -18
  153. endoreg_db/migrations/0021_alter_pdftype_endoscope_info_line.py +19 -19
  154. endoreg_db/migrations/0022_alter_pdftype_endoscope_info_line.py +19 -19
  155. endoreg_db/migrations/0023_ttoquestionnaire_alter_pdftype_endoscope_info_line.py +59 -59
  156. endoreg_db/migrations/0024_remove_ttoquestionnaire_infections_and_more.py +27 -27
  157. endoreg_db/migrations/0025_event_alter_rawpdffile_file_patientevent.py +42 -42
  158. endoreg_db/migrations/0026_disease_diseaseclassification_and_more.py +166 -166
  159. endoreg_db/migrations/0027_labvalue_abbreviation_labvalue_default_normal_range_and_more.py +38 -38
  160. endoreg_db/migrations/0028_alter_unit_abbreviation.py +18 -18
  161. endoreg_db/migrations/0029_medicationintaketime_and_more.py +75 -75
  162. endoreg_db/migrations/0030_medicationindicationtype_and_more.py +101 -101
  163. endoreg_db/migrations/0031_rename_adapt_to_liver_function_medication_adapt_to_age_and_more.py +38 -38
  164. endoreg_db/migrations/0032_alter_medicationschedule_therapy_duration_d.py +18 -18
  165. endoreg_db/migrations/0033_medicationindication_sources.py +18 -18
  166. endoreg_db/migrations/0034_alter_rawpdffile_file.py +20 -20
  167. endoreg_db/migrations/0035_alter_medicationindication_sources.py +18 -18
  168. endoreg_db/migrations/0036_alter_rawpdffile_file.py +20 -20
  169. endoreg_db/migrations/0037_alter_medicationindication_sources.py +18 -18
  170. endoreg_db/migrations/0038_emissionfactor_material_product_productgroup_and_more.py +164 -164
  171. endoreg_db/migrations/0039_referenceproduct_name.py +19 -19
  172. endoreg_db/migrations/0040_quizanswertype_quizquestiontype_quizquestion_and_more.py +50 -50
  173. endoreg_db/migrations/0041_gender_patientmedication_medication_indication_and_more.py +40 -40
  174. endoreg_db/migrations/0042_casetemplateruletype_casetemplaterulevalue_and_more.py +74 -74
  175. endoreg_db/migrations/0043_casetemplatetype_name_de_casetemplatetype_name_en.py +23 -23
  176. endoreg_db/migrations/0044_casetemplateruletype_name_de_and_more.py +23 -23
  177. endoreg_db/migrations/0045_casetemplaterulevalue_value_type.py +19 -19
  178. endoreg_db/migrations/0046_casetemplaterulevalue_target_field.py +18 -18
  179. endoreg_db/migrations/0047_casetemplaterule_target_model.py +18 -18
  180. endoreg_db/migrations/0048_remove_casetemplaterule_chained_rules_and_more.py +22 -22
  181. endoreg_db/migrations/0049_remove_casetemplaterule_rule_values.py +17 -17
  182. endoreg_db/migrations/0050_casetemplaterule_rule_values.py +18 -18
  183. endoreg_db/migrations/0051_remove_casetemplaterule_calling_rules_and_more.py +27 -27
  184. endoreg_db/migrations/0052_rename_case_template_type_casetemplate_template_type.py +18 -18
  185. endoreg_db/migrations/0053_patientlabsampletype_patientlabsample_and_more.py +38 -38
  186. endoreg_db/migrations/0054_multiplecategoricalvaluedistribution_and_more.py +69 -69
  187. endoreg_db/migrations/0055_remove_casetemplaterule_rule_values_and_more.py +59 -59
  188. endoreg_db/migrations/0056_datevaluedistribution_and_more.py +32 -32
  189. endoreg_db/migrations/0057_remove_datevaluedistribution_max_date_and_more.py +72 -72
  190. endoreg_db/migrations/0058_datevaluedistribution_description_and_more.py +28 -28
  191. endoreg_db/migrations/0059_casetemplaterule_rule_values.py +18 -18
  192. endoreg_db/migrations/0060_labvalue__default_date_value_distribution_and_more.py +44 -44
  193. endoreg_db/migrations/0061_remove_patientlabvalue_date_patientlabvalue_datetime.py +24 -24
  194. endoreg_db/migrations/0062_labvalue_numeric_precision.py +18 -18
  195. endoreg_db/migrations/0063_alter_labvalue_numeric_precision.py +18 -18
  196. endoreg_db/migrations/0064_casetemplaterule_extra_parameters_and_more.py +23 -23
  197. endoreg_db/migrations/0065_rename__date_value_distribution_casetemplaterule_date_value_distribution_and_more.py +58 -58
  198. endoreg_db/migrations/0066_alter_patientlabvalue_patient_and_more.py +29 -29
  199. endoreg_db/migrations/0067_alter_medicationindication_indication_type.py +19 -19
  200. endoreg_db/models/__init__.py +74 -74
  201. endoreg_db/models/ai_model/__init__.py +3 -3
  202. endoreg_db/models/ai_model/active_model.py +9 -9
  203. endoreg_db/models/ai_model/model_meta.py +24 -24
  204. endoreg_db/models/ai_model/model_type.py +25 -25
  205. endoreg_db/models/ai_model/utils.py +8 -8
  206. endoreg_db/models/annotation/__init__.py +1 -1
  207. endoreg_db/models/annotation/binary_classification_annotation_task.py +80 -80
  208. endoreg_db/models/annotation/image_classification.py +26 -26
  209. endoreg_db/models/case_template/__init__.py +5 -5
  210. endoreg_db/models/case_template/case_template.py +81 -81
  211. endoreg_db/models/case_template/case_template_rule.py +276 -276
  212. endoreg_db/models/case_template/case_template_rule_value.py +73 -73
  213. endoreg_db/models/case_template/case_template_type.py +27 -27
  214. endoreg_db/models/center/__init__.py +4 -4
  215. endoreg_db/models/center/center.py +24 -24
  216. endoreg_db/models/center/center_product.py +33 -33
  217. endoreg_db/models/center/center_resource.py +18 -18
  218. endoreg_db/models/center/center_waste.py +10 -10
  219. endoreg_db/models/data_file/__init__.py +5 -5
  220. endoreg_db/models/data_file/base_classes/__init__.py +2 -2
  221. endoreg_db/models/data_file/base_classes/abstract_frame.py +50 -50
  222. endoreg_db/models/data_file/base_classes/abstract_video.py +200 -200
  223. endoreg_db/models/data_file/frame.py +45 -45
  224. endoreg_db/models/data_file/import_classes/__init__.py +31 -31
  225. endoreg_db/models/data_file/import_classes/processing_functions/__init__.py +34 -34
  226. endoreg_db/models/data_file/import_classes/processing_functions/pdf.py +28 -28
  227. endoreg_db/models/data_file/import_classes/processing_functions/video.py +260 -260
  228. endoreg_db/models/data_file/import_classes/raw_pdf.py +188 -188
  229. endoreg_db/models/data_file/import_classes/raw_video.py +343 -343
  230. endoreg_db/models/data_file/metadata/__init__.py +3 -3
  231. endoreg_db/models/data_file/metadata/pdf_meta.py +70 -70
  232. endoreg_db/models/data_file/metadata/sensitive_meta.py +31 -31
  233. endoreg_db/models/data_file/metadata/video_meta.py +132 -132
  234. endoreg_db/models/data_file/report_file.py +89 -89
  235. endoreg_db/models/data_file/video/__init__.py +6 -6
  236. endoreg_db/models/data_file/video/import_meta.py +25 -25
  237. endoreg_db/models/data_file/video/video.py +25 -25
  238. endoreg_db/models/data_file/video_segment.py +107 -107
  239. endoreg_db/models/disease.py +55 -55
  240. endoreg_db/models/emission/emission_factor.py +19 -19
  241. endoreg_db/models/event.py +21 -21
  242. endoreg_db/models/examination/__init__.py +3 -3
  243. endoreg_db/models/examination/examination.py +26 -26
  244. endoreg_db/models/examination/examination_time.py +27 -27
  245. endoreg_db/models/examination/examination_time_type.py +24 -24
  246. endoreg_db/models/examination/examination_type.py +18 -18
  247. endoreg_db/models/hardware/__init__.py +1 -1
  248. endoreg_db/models/hardware/endoscope.py +44 -44
  249. endoreg_db/models/hardware/endoscopy_processor.py +143 -143
  250. endoreg_db/models/information_source.py +29 -29
  251. endoreg_db/models/label/label.py +84 -84
  252. endoreg_db/models/laboratory/lab_value.py +102 -102
  253. endoreg_db/models/legacy_data/__init__.py +3 -3
  254. endoreg_db/models/legacy_data/image.py +34 -34
  255. endoreg_db/models/medication/medication.py +148 -148
  256. endoreg_db/models/other/__init__.py +4 -4
  257. endoreg_db/models/other/distribution.py +215 -215
  258. endoreg_db/models/other/material.py +16 -16
  259. endoreg_db/models/other/resource.py +17 -17
  260. endoreg_db/models/other/transport_route.py +20 -20
  261. endoreg_db/models/other/waste.py +20 -20
  262. endoreg_db/models/patient_examination/__init__.py +35 -35
  263. endoreg_db/models/permissions/__init__.py +44 -44
  264. endoreg_db/models/persons/__init__.py +6 -6
  265. endoreg_db/models/persons/examiner/__init__.py +1 -1
  266. endoreg_db/models/persons/examiner/examiner.py +15 -15
  267. endoreg_db/models/persons/examiner/examiner_type.py +1 -1
  268. endoreg_db/models/persons/first_name.py +17 -17
  269. endoreg_db/models/persons/gender.py +22 -22
  270. endoreg_db/models/persons/last_name.py +19 -19
  271. endoreg_db/models/persons/patient/__init__.py +7 -7
  272. endoreg_db/models/persons/patient/case/case.py +30 -30
  273. endoreg_db/models/persons/patient/patient.py +216 -216
  274. endoreg_db/models/persons/patient/patient_disease.py +16 -16
  275. endoreg_db/models/persons/patient/patient_event.py +22 -22
  276. endoreg_db/models/persons/patient/patient_lab_sample.py +106 -106
  277. endoreg_db/models/persons/patient/patient_lab_value.py +176 -176
  278. endoreg_db/models/persons/patient/patient_medication.py +43 -43
  279. endoreg_db/models/persons/patient/patient_medication_schedule.py +27 -27
  280. endoreg_db/models/persons/person.py +31 -31
  281. endoreg_db/models/persons/portal_user_information.py +27 -27
  282. endoreg_db/models/prediction/__init__.py +1 -1
  283. endoreg_db/models/prediction/image_classification.py +37 -37
  284. endoreg_db/models/prediction/video_prediction_meta.py +244 -244
  285. endoreg_db/models/product/__init__.py +4 -4
  286. endoreg_db/models/product/product.py +97 -97
  287. endoreg_db/models/product/product_group.py +19 -19
  288. endoreg_db/models/product/product_material.py +24 -24
  289. endoreg_db/models/product/product_weight.py +26 -26
  290. endoreg_db/models/product/reference_product.py +99 -99
  291. endoreg_db/models/questionnaires/__init__.py +114 -114
  292. endoreg_db/models/quiz/__init__.py +1 -1
  293. endoreg_db/models/quiz/quiz_answer.py +41 -41
  294. endoreg_db/models/quiz/quiz_question.py +54 -54
  295. endoreg_db/models/report_reader/__init__.py +1 -1
  296. endoreg_db/models/report_reader/report_reader_config.py +53 -53
  297. endoreg_db/models/report_reader/report_reader_flag.py +19 -19
  298. endoreg_db/models/rules/__init__.py +4 -4
  299. endoreg_db/models/rules/rule.py +23 -23
  300. endoreg_db/models/rules/rule_applicator.py +224 -224
  301. endoreg_db/models/rules/rule_attribute_dtype.py +18 -18
  302. endoreg_db/models/rules/rule_type.py +21 -21
  303. endoreg_db/models/rules/ruleset.py +19 -19
  304. endoreg_db/models/unit.py +21 -21
  305. endoreg_db/queries/__init__.py +4 -4
  306. endoreg_db/queries/annotations/__init__.py +2 -2
  307. endoreg_db/queries/annotations/legacy.py +159 -159
  308. endoreg_db/queries/get/__init__.py +5 -5
  309. endoreg_db/queries/get/center.py +42 -42
  310. endoreg_db/queries/get/model.py +13 -13
  311. endoreg_db/queries/get/patient.py +14 -14
  312. endoreg_db/queries/get/patient_examination.py +20 -20
  313. endoreg_db/queries/get/report_file.py +33 -33
  314. endoreg_db/queries/get/video.py +31 -31
  315. endoreg_db/serializers/__init__.py +9 -9
  316. endoreg_db/serializers/ai_model.py +18 -18
  317. endoreg_db/serializers/annotation.py +17 -17
  318. endoreg_db/serializers/center.py +11 -11
  319. endoreg_db/serializers/examination.py +32 -32
  320. endoreg_db/serializers/frame.py +13 -13
  321. endoreg_db/serializers/hardware.py +20 -20
  322. endoreg_db/serializers/label.py +22 -22
  323. endoreg_db/serializers/patient.py +10 -10
  324. endoreg_db/serializers/prediction.py +15 -15
  325. endoreg_db/serializers/report_file.py +7 -7
  326. endoreg_db/serializers/video.py +27 -27
  327. endoreg_db/tests.py +3 -3
  328. endoreg_db/utils/cropping.py +28 -28
  329. endoreg_db/utils/dataloader.py +92 -92
  330. endoreg_db/utils/file_operations.py +30 -30
  331. endoreg_db/utils/hashs.py +33 -33
  332. endoreg_db/utils/legacy_ocr.py +201 -201
  333. endoreg_db/utils/ocr.py +197 -197
  334. endoreg_db/utils/uuid.py +4 -4
  335. endoreg_db/utils/video_metadata.py +87 -87
  336. endoreg_db/views.py +3 -3
  337. {endoreg_db-0.3.5.dist-info → endoreg_db-0.3.6.dist-info}/LICENSE +674 -674
  338. {endoreg_db-0.3.5.dist-info → endoreg_db-0.3.6.dist-info}/METADATA +2 -2
  339. endoreg_db-0.3.6.dist-info/RECORD +357 -0
  340. {endoreg_db-0.3.5.dist-info → endoreg_db-0.3.6.dist-info}/WHEEL +1 -1
  341. endoreg_db-0.3.5.dist-info/RECORD +0 -357
@@ -1,343 +1,343 @@
1
- from django.db import models
2
- from pathlib import Path
3
- from collections import defaultdict, Counter
4
-
5
- from endoreg_db.utils.hashs import get_video_hash
6
- from endoreg_db.utils.file_operations import get_uuid_filename
7
- from endoreg_db.utils.ocr import extract_text_from_rois
8
-
9
- import shutil
10
- import os
11
- import subprocess
12
-
13
- from ..metadata import VideoMeta, SensitiveMeta
14
-
15
- class RawVideoFile(models.Model):
16
- uuid = models.UUIDField()
17
- file = models.FileField(upload_to="raw_data/")
18
-
19
- sensitive_meta = models.OneToOneField(
20
- "SensitiveMeta", on_delete=models.CASCADE, blank=True, null=True
21
- )
22
-
23
- center = models.ForeignKey("Center", on_delete=models.CASCADE)
24
- processor = models.ForeignKey(
25
- "EndoscopyProcessor", on_delete=models.CASCADE, blank=True, null=True
26
- )
27
- video_meta = models.OneToOneField(
28
- "VideoMeta", on_delete=models.CASCADE, blank=True, null=True
29
- )
30
- original_file_name = models.CharField(max_length=255)
31
- video_hash = models.CharField(max_length=255, unique=True)
32
- uploaded_at = models.DateTimeField(auto_now_add=True)
33
-
34
- # Frame Extraction States
35
- state_frames_required = models.BooleanField(default=True)
36
- state_frames_extracted = models.BooleanField(default=False)
37
-
38
- # Video
39
- ## Prediction
40
- state_initial_prediction_required = models.BooleanField(default=True)
41
- state_initial_prediction_completed = models.BooleanField(default=False)
42
- state_initial_prediction_import_required = models.BooleanField(default=True)
43
- state_initial_prediction_import_completed = models.BooleanField(default=False)
44
- ## OCR
45
- state_ocr_required = models.BooleanField(default=True)
46
- state_ocr_completed = models.BooleanField(default=False)
47
- ## Validation
48
- state_outside_validated = models.BooleanField(default=False)
49
- state_ocr_result_validated = models.BooleanField(default=False)
50
-
51
- state_sensitive_data_retrieved = models.BooleanField(default=False)
52
-
53
- # Dataset complete?
54
- state_histology_required = models.BooleanField(blank=True, null=True)
55
- state_histology_available = models.BooleanField(default=False)
56
- state_follow_up_intervention_required = models.BooleanField(blank=True, null=True)
57
- state_follow_up_intervention_available = models.BooleanField(default=False)
58
- state_dataset_complete = models.BooleanField(default=False)
59
-
60
- # Finalizing for Upload
61
- state_anonym_video_required = models.BooleanField(default=True)
62
- state_anonym_video_performed = models.BooleanField(default=False)
63
- state_original_reports_deleted = models.BooleanField(default=False)
64
- state_original_video_deleted = models.BooleanField(default=False)
65
- state_finalized = models.BooleanField(default=False)
66
-
67
- frame_dir = models.CharField(max_length=255)
68
- prediction_dir = models.CharField(max_length=255)
69
-
70
- @classmethod
71
- def create_from_file(
72
- cls,
73
- file_path: Path,
74
- video_dir: Path,
75
- center_name: str,
76
- processor_name: str,
77
- frame_dir_parent: Path,
78
- save: bool = True,
79
- ):
80
- from endoreg_db.models import Center, EndoscopyProcessor
81
-
82
- print(f"Creating RawVideoFile from {file_path}")
83
- original_file_name = file_path.name
84
- # Rename and and move
85
-
86
- new_file_name, uuid = get_uuid_filename(file_path)
87
- framedir: Path = frame_dir_parent / str(uuid)
88
-
89
- if not framedir.exists():
90
- framedir.mkdir(parents=True, exist_ok=True)
91
-
92
- if not video_dir.exists():
93
- video_dir.mkdir(parents=True, exist_ok=True)
94
-
95
- video_hash = get_video_hash(file_path)
96
-
97
- center = Center.objects.get(name=center_name)
98
- assert center is not None, "Center must exist"
99
-
100
- processor = EndoscopyProcessor.objects.get(name=processor_name)
101
- assert processor is not None, "Processor must exist"
102
-
103
- new_filepath = video_dir / new_file_name
104
-
105
- print(f"Moving {file_path} to {new_filepath}")
106
- shutil.move(file_path.resolve().as_posix(), new_filepath.resolve().as_posix())
107
- print(f"Moved to {new_filepath}")
108
-
109
- # Make sure file was transferred correctly and hash is correct
110
- if not new_filepath.exists():
111
- print(f"File {file_path} was not transferred correctly to {new_filepath}")
112
- return None
113
-
114
- new_hash = get_video_hash(new_filepath)
115
- if new_hash != video_hash:
116
- print(f"Hash of file {file_path} is not correct")
117
- return None
118
-
119
- # make sure that no other file with the same hash exists
120
- if cls.objects.filter(video_hash=video_hash).exists():
121
- # log and print warnint
122
- print(f"File with hash {video_hash} already exists")
123
- return None
124
-
125
- else:
126
- print(center)
127
- # Create a new instance of RawVideoFile
128
- raw_video_file = cls(
129
- uuid=uuid,
130
- file=new_filepath.resolve().as_posix(),
131
- center=center,
132
- processor=processor,
133
- original_file_name=original_file_name,
134
- video_hash=video_hash,
135
- frame_dir=framedir.as_posix(),
136
- )
137
-
138
- # Save the instance to the database
139
- raw_video_file.save()
140
-
141
- return raw_video_file
142
-
143
- def __str__(self):
144
- return self.file.name
145
-
146
- def get_endo_roi(self):
147
- endo_roi = self.video_meta.get_endo_roi()
148
- return endo_roi
149
-
150
- # video meta should be created when video file is created
151
- def save(self, *args, **kwargs):
152
- if self.video_meta is None:
153
- center = self.center
154
- processor = self.processor
155
- self.video_meta = VideoMeta.objects.create(
156
- center=center, processor=processor
157
- )
158
- self.video_meta.initialize_ffmpeg_meta(self.file.path)
159
- super(RawVideoFile, self).save(*args, **kwargs)
160
-
161
- def extract_frames(
162
- self,
163
- quality: int = 2,
164
- frame_dir: Path = None,
165
- overwrite: bool = False,
166
- ext="jpg",
167
- ):
168
- """
169
- Extract frames from the video file and save them to the frame_dir.
170
- For this, ffmpeg must be available in in the current environment.
171
- """
172
- if frame_dir is None:
173
- frame_dir = Path(self.frame_dir)
174
- else:
175
- frame_dir = Path(frame_dir)
176
-
177
- if not frame_dir.exists():
178
- frame_dir.mkdir(parents=True, exist_ok=True)
179
-
180
- if not overwrite and len(list(frame_dir.glob("*.jpg"))) > 0:
181
- print(f"Frames already extracted for {self.file.name}")
182
- return
183
-
184
- video_path = Path(self.file.path).resolve().as_posix()
185
-
186
- frame_path_string = frame_dir.resolve().as_posix()
187
- command = [
188
- "ffmpeg",
189
- "-i",
190
- video_path, #
191
- "-q:v",
192
- str(quality),
193
- os.path.join(frame_path_string, f"frame_%07d.{ext}"),
194
- ]
195
-
196
- # Ensure FFmpeg is available
197
- if not shutil.which("ffmpeg"):
198
- raise EnvironmentError(
199
- "FFmpeg could not be found. Ensure it is installed and in your PATH."
200
- )
201
-
202
- # Extract frames from the video file
203
- # Execute the command
204
- result = subprocess.run(command, capture_output=True, text=True)
205
- if result.returncode != 0:
206
- raise Exception(f"Error extracting frames: {result.stderr}")
207
-
208
- self.state_frames_extracted = True
209
-
210
- return f"Frames extracted to {frame_dir} ({frame_path_string}) with quality {quality}"
211
-
212
- def delete_frames(self):
213
- """
214
- Delete frames extracted from the video file.
215
- """
216
- frame_dir = Path(self.frame_dir)
217
- if frame_dir.exists():
218
- shutil.rmtree(frame_dir)
219
- self.state_frames_extracted = False
220
- self.save()
221
- return f"Frames deleted from {frame_dir}"
222
- else:
223
- return f"No frames to delete for {self.file.name}"
224
-
225
- def get_frame_path(self, n: int = 0):
226
- """
227
- Get the path to the n-th frame extracted from the video file.
228
- Note that the frame numbering starts at 1 in our naming convention.
229
- """
230
- # Adjust index
231
- n = n + 1
232
-
233
- frame_dir = Path(self.frame_dir)
234
- return frame_dir / f"frame_{n:07d}.jpg"
235
-
236
- def get_frame_paths(self):
237
- if not self.state_frames_extracted:
238
- return None
239
- frame_dir = Path(self.frame_dir)
240
- paths = [p for p in frame_dir.glob('*')]
241
- indices = [int(p.stem.split("_")[1]) for p in paths]
242
- path_index_tuples = list(zip(paths, indices))
243
- # sort ascending by index
244
- path_index_tuples.sort(key=lambda x: x[1])
245
- paths, indices = zip(*path_index_tuples)
246
-
247
- return paths
248
-
249
- def get_prediction_dir(self):
250
- return Path(self.prediction_dir)
251
-
252
- def get_predictions_path(self, suffix = ".json"):
253
- pred_dir = self.get_prediction_dir()
254
- return pred_dir.joinpath("predictions").with_suffix(suffix)
255
-
256
- def get_smooth_predictions_path(self, suffix = ".json"):
257
- pred_dir = self.get_prediction_dir()
258
- return pred_dir.joinpath("smooth_predictions").with_suffix(suffix)
259
-
260
- def get_binary_predictions_path(self, suffix = ".json"):
261
- pred_dir = self.get_prediction_dir()
262
- return pred_dir.joinpath("binary_predictions").with_suffix(suffix)
263
-
264
- def get_raw_sequences_path(self, suffix = ".json"):
265
- pred_dir = self.get_prediction_dir()
266
- return pred_dir.joinpath("raw_sequences").with_suffix(suffix)
267
-
268
- def get_filtered_sequences_path(self, suffix=".json"):
269
- pred_dir = self.get_prediction_dir()
270
- return pred_dir.joinpath("filtered_sequences").with_suffix(suffix)
271
-
272
- def extract_text_information(self, frame_fraction: float = 0.001):
273
- """
274
- Extract text information from the video file.
275
- Makes sure that frames are extracted and then processes the frames.
276
- gets all frames from frame_dir and selects a fraction of them to process (at least 1)
277
- """
278
- if not self.state_frames_extracted:
279
- print(f"Frames not extracted for {self.file.name}")
280
- return None
281
-
282
- processor = self.processor
283
-
284
- frame_dir = Path(self.frame_dir)
285
- frames = list(frame_dir.glob("*"))
286
- n_frames = len(frames)
287
- n_frames_to_process = max(1, int(frame_fraction * n_frames))
288
-
289
- # Select evenly spaced frames
290
- frames = frames[:: n_frames // n_frames_to_process]
291
-
292
- # extract text from each frame and store the value to
293
- # defaultdict of lists.
294
- # Then, extract the most frequent value from each list
295
- # Finally, return the dictionary of most frequent values
296
-
297
- # Create a defaultdict to store the extracted text from each ROI
298
- rois_texts = defaultdict(list)
299
-
300
- print(f"Processing {n_frames_to_process} frames from {self.file.name}")
301
- # Process frames
302
- for frame_path in frames[:n_frames_to_process]:
303
- extracted_texts = extract_text_from_rois(frame_path, processor)
304
- for roi, text in extracted_texts.items():
305
- rois_texts[roi].append(text)
306
-
307
- # Get the most frequent text values for each ROI using Counter
308
- for key in rois_texts.keys():
309
- counter = Counter([text for text in rois_texts[key] if text])
310
- rois_texts[key] = counter.most_common(1)[0][0] if counter else None
311
-
312
- return rois_texts
313
-
314
- def update_text_metadata(self, ocr_frame_fraction=0.001):
315
- print(f"Updating metadata for {self.file.name}")
316
- texts = self.extract_text_information(ocr_frame_fraction)
317
-
318
- self.sensitive_meta = SensitiveMeta.create_from_dict(texts)
319
- self.state_sensitive_data_retrieved = True
320
- self.save()
321
-
322
- # Resulting dict depends on defined ROIs for this processor type!
323
-
324
- def update_video_meta(self):
325
- video_meta = self.video_meta
326
- video_path = Path(self.file.path)
327
-
328
- if video_meta is None:
329
- video_meta = VideoMeta.create_from_video(video_path)
330
- self.video_meta = video_meta
331
- self.save()
332
-
333
- else:
334
- video_meta.update_meta(video_path)
335
-
336
- def get_fps(self):
337
- if self.video_meta is None:
338
- self.update_video_meta()
339
-
340
- if self.video_meta.ffmpeg_meta is None:
341
- self.video_meta.initialize_ffmpeg_meta(self.file.path)
342
-
343
- return self.video_meta.get_fps()
1
+ from django.db import models
2
+ from pathlib import Path
3
+ from collections import defaultdict, Counter
4
+
5
+ from endoreg_db.utils.hashs import get_video_hash
6
+ from endoreg_db.utils.file_operations import get_uuid_filename
7
+ from endoreg_db.utils.ocr import extract_text_from_rois
8
+
9
+ import shutil
10
+ import os
11
+ import subprocess
12
+
13
+ from ..metadata import VideoMeta, SensitiveMeta
14
+
15
+ class RawVideoFile(models.Model):
16
+ uuid = models.UUIDField()
17
+ file = models.FileField(upload_to="raw_data/")
18
+
19
+ sensitive_meta = models.OneToOneField(
20
+ "SensitiveMeta", on_delete=models.CASCADE, blank=True, null=True
21
+ )
22
+
23
+ center = models.ForeignKey("Center", on_delete=models.CASCADE)
24
+ processor = models.ForeignKey(
25
+ "EndoscopyProcessor", on_delete=models.CASCADE, blank=True, null=True
26
+ )
27
+ video_meta = models.OneToOneField(
28
+ "VideoMeta", on_delete=models.CASCADE, blank=True, null=True
29
+ )
30
+ original_file_name = models.CharField(max_length=255)
31
+ video_hash = models.CharField(max_length=255, unique=True)
32
+ uploaded_at = models.DateTimeField(auto_now_add=True)
33
+
34
+ # Frame Extraction States
35
+ state_frames_required = models.BooleanField(default=True)
36
+ state_frames_extracted = models.BooleanField(default=False)
37
+
38
+ # Video
39
+ ## Prediction
40
+ state_initial_prediction_required = models.BooleanField(default=True)
41
+ state_initial_prediction_completed = models.BooleanField(default=False)
42
+ state_initial_prediction_import_required = models.BooleanField(default=True)
43
+ state_initial_prediction_import_completed = models.BooleanField(default=False)
44
+ ## OCR
45
+ state_ocr_required = models.BooleanField(default=True)
46
+ state_ocr_completed = models.BooleanField(default=False)
47
+ ## Validation
48
+ state_outside_validated = models.BooleanField(default=False)
49
+ state_ocr_result_validated = models.BooleanField(default=False)
50
+
51
+ state_sensitive_data_retrieved = models.BooleanField(default=False)
52
+
53
+ # Dataset complete?
54
+ state_histology_required = models.BooleanField(blank=True, null=True)
55
+ state_histology_available = models.BooleanField(default=False)
56
+ state_follow_up_intervention_required = models.BooleanField(blank=True, null=True)
57
+ state_follow_up_intervention_available = models.BooleanField(default=False)
58
+ state_dataset_complete = models.BooleanField(default=False)
59
+
60
+ # Finalizing for Upload
61
+ state_anonym_video_required = models.BooleanField(default=True)
62
+ state_anonym_video_performed = models.BooleanField(default=False)
63
+ state_original_reports_deleted = models.BooleanField(default=False)
64
+ state_original_video_deleted = models.BooleanField(default=False)
65
+ state_finalized = models.BooleanField(default=False)
66
+
67
+ frame_dir = models.CharField(max_length=255)
68
+ prediction_dir = models.CharField(max_length=255)
69
+
70
+ @classmethod
71
+ def create_from_file(
72
+ cls,
73
+ file_path: Path,
74
+ video_dir: Path,
75
+ center_name: str,
76
+ processor_name: str,
77
+ frame_dir_parent: Path,
78
+ save: bool = True,
79
+ ):
80
+ from endoreg_db.models import Center, EndoscopyProcessor
81
+
82
+ print(f"Creating RawVideoFile from {file_path}")
83
+ original_file_name = file_path.name
84
+ # Rename and and move
85
+
86
+ new_file_name, uuid = get_uuid_filename(file_path)
87
+ framedir: Path = frame_dir_parent / str(uuid)
88
+
89
+ if not framedir.exists():
90
+ framedir.mkdir(parents=True, exist_ok=True)
91
+
92
+ if not video_dir.exists():
93
+ video_dir.mkdir(parents=True, exist_ok=True)
94
+
95
+ video_hash = get_video_hash(file_path)
96
+
97
+ center = Center.objects.get(name=center_name)
98
+ assert center is not None, "Center must exist"
99
+
100
+ processor = EndoscopyProcessor.objects.get(name=processor_name)
101
+ assert processor is not None, "Processor must exist"
102
+
103
+ new_filepath = video_dir / new_file_name
104
+
105
+ print(f"Moving {file_path} to {new_filepath}")
106
+ shutil.move(file_path.resolve().as_posix(), new_filepath.resolve().as_posix())
107
+ print(f"Moved to {new_filepath}")
108
+
109
+ # Make sure file was transferred correctly and hash is correct
110
+ if not new_filepath.exists():
111
+ print(f"File {file_path} was not transferred correctly to {new_filepath}")
112
+ return None
113
+
114
+ new_hash = get_video_hash(new_filepath)
115
+ if new_hash != video_hash:
116
+ print(f"Hash of file {file_path} is not correct")
117
+ return None
118
+
119
+ # make sure that no other file with the same hash exists
120
+ if cls.objects.filter(video_hash=video_hash).exists():
121
+ # log and print warnint
122
+ print(f"File with hash {video_hash} already exists")
123
+ return None
124
+
125
+ else:
126
+ print(center)
127
+ # Create a new instance of RawVideoFile
128
+ raw_video_file = cls(
129
+ uuid=uuid,
130
+ file=new_filepath.resolve().as_posix(),
131
+ center=center,
132
+ processor=processor,
133
+ original_file_name=original_file_name,
134
+ video_hash=video_hash,
135
+ frame_dir=framedir.as_posix(),
136
+ )
137
+
138
+ # Save the instance to the database
139
+ raw_video_file.save()
140
+
141
+ return raw_video_file
142
+
143
+ def __str__(self):
144
+ return self.file.name
145
+
146
+ def get_endo_roi(self):
147
+ endo_roi = self.video_meta.get_endo_roi()
148
+ return endo_roi
149
+
150
+ # video meta should be created when video file is created
151
+ def save(self, *args, **kwargs):
152
+ if self.video_meta is None:
153
+ center = self.center
154
+ processor = self.processor
155
+ self.video_meta = VideoMeta.objects.create(
156
+ center=center, processor=processor
157
+ )
158
+ self.video_meta.initialize_ffmpeg_meta(self.file.path)
159
+ super(RawVideoFile, self).save(*args, **kwargs)
160
+
161
+ def extract_frames(
162
+ self,
163
+ quality: int = 2,
164
+ frame_dir: Path = None,
165
+ overwrite: bool = False,
166
+ ext="jpg",
167
+ ):
168
+ """
169
+ Extract frames from the video file and save them to the frame_dir.
170
+ For this, ffmpeg must be available in in the current environment.
171
+ """
172
+ if frame_dir is None:
173
+ frame_dir = Path(self.frame_dir)
174
+ else:
175
+ frame_dir = Path(frame_dir)
176
+
177
+ if not frame_dir.exists():
178
+ frame_dir.mkdir(parents=True, exist_ok=True)
179
+
180
+ if not overwrite and len(list(frame_dir.glob("*.jpg"))) > 0:
181
+ print(f"Frames already extracted for {self.file.name}")
182
+ return
183
+
184
+ video_path = Path(self.file.path).resolve().as_posix()
185
+
186
+ frame_path_string = frame_dir.resolve().as_posix()
187
+ command = [
188
+ "ffmpeg",
189
+ "-i",
190
+ video_path, #
191
+ "-q:v",
192
+ str(quality),
193
+ os.path.join(frame_path_string, f"frame_%07d.{ext}"),
194
+ ]
195
+
196
+ # Ensure FFmpeg is available
197
+ if not shutil.which("ffmpeg"):
198
+ raise EnvironmentError(
199
+ "FFmpeg could not be found. Ensure it is installed and in your PATH."
200
+ )
201
+
202
+ # Extract frames from the video file
203
+ # Execute the command
204
+ result = subprocess.run(command, capture_output=True, text=True)
205
+ if result.returncode != 0:
206
+ raise Exception(f"Error extracting frames: {result.stderr}")
207
+
208
+ self.state_frames_extracted = True
209
+
210
+ return f"Frames extracted to {frame_dir} ({frame_path_string}) with quality {quality}"
211
+
212
+ def delete_frames(self):
213
+ """
214
+ Delete frames extracted from the video file.
215
+ """
216
+ frame_dir = Path(self.frame_dir)
217
+ if frame_dir.exists():
218
+ shutil.rmtree(frame_dir)
219
+ self.state_frames_extracted = False
220
+ self.save()
221
+ return f"Frames deleted from {frame_dir}"
222
+ else:
223
+ return f"No frames to delete for {self.file.name}"
224
+
225
+ def get_frame_path(self, n: int = 0):
226
+ """
227
+ Get the path to the n-th frame extracted from the video file.
228
+ Note that the frame numbering starts at 1 in our naming convention.
229
+ """
230
+ # Adjust index
231
+ n = n + 1
232
+
233
+ frame_dir = Path(self.frame_dir)
234
+ return frame_dir / f"frame_{n:07d}.jpg"
235
+
236
+ def get_frame_paths(self):
237
+ if not self.state_frames_extracted:
238
+ return None
239
+ frame_dir = Path(self.frame_dir)
240
+ paths = [p for p in frame_dir.glob('*')]
241
+ indices = [int(p.stem.split("_")[1]) for p in paths]
242
+ path_index_tuples = list(zip(paths, indices))
243
+ # sort ascending by index
244
+ path_index_tuples.sort(key=lambda x: x[1])
245
+ paths, indices = zip(*path_index_tuples)
246
+
247
+ return paths
248
+
249
+ def get_prediction_dir(self):
250
+ return Path(self.prediction_dir)
251
+
252
+ def get_predictions_path(self, suffix = ".json"):
253
+ pred_dir = self.get_prediction_dir()
254
+ return pred_dir.joinpath("predictions").with_suffix(suffix)
255
+
256
+ def get_smooth_predictions_path(self, suffix = ".json"):
257
+ pred_dir = self.get_prediction_dir()
258
+ return pred_dir.joinpath("smooth_predictions").with_suffix(suffix)
259
+
260
+ def get_binary_predictions_path(self, suffix = ".json"):
261
+ pred_dir = self.get_prediction_dir()
262
+ return pred_dir.joinpath("binary_predictions").with_suffix(suffix)
263
+
264
+ def get_raw_sequences_path(self, suffix = ".json"):
265
+ pred_dir = self.get_prediction_dir()
266
+ return pred_dir.joinpath("raw_sequences").with_suffix(suffix)
267
+
268
+ def get_filtered_sequences_path(self, suffix=".json"):
269
+ pred_dir = self.get_prediction_dir()
270
+ return pred_dir.joinpath("filtered_sequences").with_suffix(suffix)
271
+
272
+ def extract_text_information(self, frame_fraction: float = 0.001):
273
+ """
274
+ Extract text information from the video file.
275
+ Makes sure that frames are extracted and then processes the frames.
276
+ gets all frames from frame_dir and selects a fraction of them to process (at least 1)
277
+ """
278
+ if not self.state_frames_extracted:
279
+ print(f"Frames not extracted for {self.file.name}")
280
+ return None
281
+
282
+ processor = self.processor
283
+
284
+ frame_dir = Path(self.frame_dir)
285
+ frames = list(frame_dir.glob("*"))
286
+ n_frames = len(frames)
287
+ n_frames_to_process = max(1, int(frame_fraction * n_frames))
288
+
289
+ # Select evenly spaced frames
290
+ frames = frames[:: n_frames // n_frames_to_process]
291
+
292
+ # extract text from each frame and store the value to
293
+ # defaultdict of lists.
294
+ # Then, extract the most frequent value from each list
295
+ # Finally, return the dictionary of most frequent values
296
+
297
+ # Create a defaultdict to store the extracted text from each ROI
298
+ rois_texts = defaultdict(list)
299
+
300
+ print(f"Processing {n_frames_to_process} frames from {self.file.name}")
301
+ # Process frames
302
+ for frame_path in frames[:n_frames_to_process]:
303
+ extracted_texts = extract_text_from_rois(frame_path, processor)
304
+ for roi, text in extracted_texts.items():
305
+ rois_texts[roi].append(text)
306
+
307
+ # Get the most frequent text values for each ROI using Counter
308
+ for key in rois_texts.keys():
309
+ counter = Counter([text for text in rois_texts[key] if text])
310
+ rois_texts[key] = counter.most_common(1)[0][0] if counter else None
311
+
312
+ return rois_texts
313
+
314
+ def update_text_metadata(self, ocr_frame_fraction=0.001):
315
+ print(f"Updating metadata for {self.file.name}")
316
+ texts = self.extract_text_information(ocr_frame_fraction)
317
+
318
+ self.sensitive_meta = SensitiveMeta.create_from_dict(texts)
319
+ self.state_sensitive_data_retrieved = True
320
+ self.save()
321
+
322
+ # Resulting dict depends on defined ROIs for this processor type!
323
+
324
+ def update_video_meta(self):
325
+ video_meta = self.video_meta
326
+ video_path = Path(self.file.path)
327
+
328
+ if video_meta is None:
329
+ video_meta = VideoMeta.create_from_video(video_path)
330
+ self.video_meta = video_meta
331
+ self.save()
332
+
333
+ else:
334
+ video_meta.update_meta(video_path)
335
+
336
+ def get_fps(self):
337
+ if self.video_meta is None:
338
+ self.update_video_meta()
339
+
340
+ if self.video_meta.ffmpeg_meta is None:
341
+ self.video_meta.initialize_ffmpeg_meta(self.file.path)
342
+
343
+ return self.video_meta.get_fps()