11# General imports
2+ from os .path import splitext
23import PIL .Image
34import numpy as np
45from matplotlib import patches
910
1011# ETS imports
1112from traits .api import (
12- Dict ,
13- File ,
14- HasStrictTraits ,
15- Instance ,
16- List ,
17- observe ,
13+ Array , cached_property , Dict , File , HasStrictTraits , Instance , List ,
14+ observe , Property
1815)
1916from traitsui .api import Item , ModelView , OKButton , View
2017
2118# Local imports
2219from ets_tutorial .util .mpl_figure_editor import MplFigureEditor
2320
21+ SUPPORTED_FORMATS = [".png" , ".jpg" , ".jpeg" , ".PNG" , ".JPG" , ".JPEG" ]
22+
2423
2524class ImageFile (HasStrictTraits ):
2625 """ Model to hold an image file.
2726 """
2827 filepath = File
2928
29+ metadata = Property (Dict , depends_on = "filepath" )
30+
31+ data = Property (Array , depends_on = "filepath" )
32+
3033 faces = List
3134
32- metadata = Dict
35+ def _is_valid_file (self ):
36+ return (
37+ bool (self .filepath ) and
38+ splitext (self .filepath )[1 ].lower () in SUPPORTED_FORMATS
39+ )
3340
34- def to_array (self ):
35- if not self .filepath :
41+ @cached_property
42+ def _get_data (self ):
43+ if not self ._is_valid_file ():
3644 return np .array ([])
37-
3845 with PIL .Image .open (self .filepath ) as img :
3946 return np .asarray (img )
4047
41- @observe ("filepath" )
42- def _update_faces_and_metadata (self , event ):
43- self .metadata = {}
44- self ._update_metadata_with_exif ()
45- self ._detect_faces ()
46- print (self .metadata )
47-
48- def _update_metadata_with_exif (self ):
49- if not self .filepath :
50- return
48+ @cached_property
49+ def _get_metadata (self ):
50+ if not self ._is_valid_file ():
51+ return {}
5152 with PIL .Image .open (self .filepath ) as img :
5253 exif = img ._getexif ()
5354 if not exif :
54- return
55- self .metadata .update (
56- {TAGS [k ]: v for k , v in exif .items () if k in TAGS }
57- )
55+ return {}
56+ return {TAGS [k ]: v for k , v in exif .items () if k in TAGS }
5857
59- def _detect_faces (self ):
60- self .faces = []
61- if not self .filepath :
62- return
58+ def detect_faces (self ):
6359 # Load the trained file from the module root.
6460 trained_file = data .lbp_frontal_face_cascade_filename ()
61+
6562 # Initialize the detector cascade.
6663 detector = Cascade (trained_file )
67- faces = detector .detect_multi_scale (
68- img = self .to_array (),
69- scale_factor = 1.2 ,
70- step_ratio = 1 ,
71- min_size = (60 , 60 ),
72- max_size = (600 , 600 )
73- )
74- self .faces .extend (faces )
75- self .metadata ['Number of faces' ] = len (self .faces )
64+
65+ detected = detector .detect_multi_scale (img = self .data ,
66+ scale_factor = 1.2 ,
67+ step_ratio = 1 ,
68+ min_size = (60 , 60 ),
69+ max_size = (600 , 600 ))
70+ self .faces = detected
71+ return self .faces
7672
7773
7874class ImageFileView (ModelView ):
@@ -96,8 +92,8 @@ def build_mpl_figure(self, event):
9692 return
9793 figure = Figure ()
9894 axes = figure .add_subplot (111 )
99- axes .imshow (self .model .to_array () )
100- for patch in self .model .faces :
95+ axes .imshow (self .model .data )
96+ for patch in self .model .detect_faces () :
10197 axes .add_patch (
10298 patches .Rectangle (
10399 (patch ['c' ], patch ['r' ]),
0 commit comments