Skip to content

Commit f1a1c53

Browse files
Merge branch 'master' into stage2_traited_script
2 parents 1d3faf3 + 573da8a commit f1a1c53

54 files changed

Lines changed: 1183 additions & 77 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ the process, attendees will learn how to design clean, maintainable and
1616
scalable applications, and package them into an installer.
1717

1818
## Set up instructions
19+
First step to set yourself up is to clone this repository
20+
```commandline
21+
git clone git@github.com:jonathanrocher/ets_tutorial.git
22+
```
1923

2024
### Requirements
2125

@@ -37,6 +41,10 @@ edm shell -e ets_tutorial
3741
edm install pandas matplotlib traits traitsui scikits.image pillow pyqt5 ipython
3842
```
3943

44+
```commandline
45+
python etstool.py build
46+
```
47+
4048
### Conda users
4149
[TODO]
4250

@@ -64,24 +72,24 @@ During the tutorial, don't hesitate to ask for help:
6472

6573
## Outline of the tutorial
6674
The tutorial will guide you through all the stages from a basic python script
67-
(stage 0) to a fully packaged and installable application (stage 8). The
75+
(stage 1) to a fully packaged and installable application (stage 8). The
6876
included exercises will walk you through developing the primary product of
69-
each stage.
77+
each stage.
7078
A solution is available for each exercise, though, to ensure all participants
7179
are able to reach the end goal.
7280

73-
- step 0: python script
74-
- step 1: more robust script with ETS-Traits
75-
- step 2: package management tools: etstool, unit test and CI [OPTIONAL]
81+
- step 1: python script
82+
- step 2: more robust script with ETS-Traits
7683
- step 3: GUI: first traitsUI views
7784
- step 4: pyface application: tree navigator and double-click on an image to
7885
display the traitsUI view of the image.
79-
- step 5: pyface application:
86+
- step 5: Fuller pyface application:
8087
- add folder editor to display a table of metadata for all images inside
8188
- add button to launch the face detection on all images
8289
- add widgets to filter images
83-
- step 6: pyface application (adaptation to build central pane editors) [OPTIONAL]
84-
- step 7: pyface application: background run with traits-futures [OPTIONAL]
90+
- INTERLUDE: code structure for scalability
91+
- step 6: pyface application: adding menu and branding
92+
- step 7: pyface application: advanced features [OPTIONAL]
8593
- step 8: 1-click installer
8694

8795

ets_tutorial/util/mpl_figure_editor.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import matplotlib
22
from matplotlib.backends.backend_qt5agg import (
3-
FigureCanvasQTAgg as FigureCanvas,
4-
NavigationToolbar2QT as NavigationToolbar
3+
FigureCanvasQTAgg, NavigationToolbar2QT
54
)
65
from pyface.qt import QtGui
76
from traitsui.api import BasicEditorFactory
@@ -15,21 +14,32 @@ class _MplFigureEditor(Editor):
1514
scrollable = True
1615

1716
def init(self, parent):
17+
"""Create and initialize the underlying toolkit widget.
18+
"""
1819
self.set_tooltip()
19-
self.control = self._create_mpl_canvas(parent)
20+
self.control = QtGui.QWidget()
21+
self.control.setLayout(QtGui.QVBoxLayout())
22+
self._do_layout()
2023

2124
def update_editor(self):
22-
pass
23-
24-
def _create_mpl_canvas(self, parent):
25-
control = QtGui.QWidget()
26-
canvas = FigureCanvas(figure=self.value)
27-
toolbar = NavigationToolbar(canvas, control)
28-
layout = QtGui.QVBoxLayout()
25+
"""Updates the editor when the value changes externally to the editor.
26+
"""
27+
self.clear_layout()
28+
self._do_layout()
29+
30+
def _do_layout(self):
31+
"""Creates sub-widgets and does layout.
32+
"""
33+
canvas = FigureCanvasQTAgg(figure=self.value)
34+
# Allow the figure canvas to expand and shrink with the main widget.
35+
canvas.setSizePolicy(
36+
QtGui.QSizePolicy.Policy.Expanding,
37+
QtGui.QSizePolicy.Policy.Expanding,
38+
)
39+
toolbar = NavigationToolbar2QT(canvas, self.control)
40+
layout = self.control.layout()
2941
layout.addWidget(toolbar)
3042
layout.addWidget(canvas)
31-
control.setLayout(layout)
32-
return control
3343

3444

3545
class MplFigureEditor(BasicEditorFactory):

ets_tutorial/util/tests/test_mpl_figure_editor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class Plot(HasTraits):
1414

1515
view = View(
1616
Item("figure", editor=MplFigureEditor(), show_label=False),
17+
resizable=True
1718
)
1819

1920
def _figure_default(self):

sample_images/20210802_191429.jpg

5.94 MB
Loading

sample_images/owls.jpg

-3.07 MB
Binary file not shown.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
""" Script analyzing an image, detecting human faces inside it, and printing
2+
EXIF data about it.
3+
"""
4+
from os.path import join
5+
6+
import PIL.Image
7+
from PIL.ExifTags import TAGS
8+
from skimage import data
9+
from skimage.feature import Cascade
10+
import matplotlib.pyplot as plt
11+
import numpy as np
12+
from matplotlib import patches
13+
14+
# Select image file -----------------------------------------------------------
15+
16+
image_paths = [
17+
join("..", "sample_images", "IMG-0311_xmas_2020.JPG"),
18+
join("..", "sample_images", "owls.jpg")
19+
]
20+
21+
# Load the trained file from the module root.
22+
trained_file = data.lbp_frontal_face_cascade_filename()
23+
24+
# Initialize the detector cascade.
25+
detector = Cascade(trained_file)
26+
27+
for path in image_paths:
28+
img = PIL.Image.open(path)
29+
30+
img_metadata = {TAGS[k]: v for k, v in img._getexif().items() if k in TAGS}
31+
32+
# Detect faces ------------------------------------------------------------
33+
34+
detected = detector.detect_multi_scale(img=np.asarray(img),
35+
scale_factor=1.2,
36+
step_ratio=1,
37+
min_size=(60, 60),
38+
max_size=(600, 600))
39+
40+
img_metadata["Number of faces detected"] = len(detected)
41+
print(img_metadata)
42+
43+
# Visualize results -------------------------------------------------------
44+
45+
plt.imshow(img)
46+
img_desc = plt.gca()
47+
48+
for patch in detected:
49+
50+
img_desc.add_patch(
51+
patches.Rectangle(
52+
(patch['c'], patch['r']),
53+
patch['width'],
54+
patch['height'],
55+
fill=False,
56+
color='r',
57+
linewidth=2
58+
)
59+
)
60+
61+
plt.show()

stage0_starting_script/face_detect_skimage.py

Lines changed: 0 additions & 57 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Second real version of the pycasa ETS pyface application!
2+
Building on the application state 4.2, this version simply adds an editor and a
3+
view for a folder to be visualized.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
__version__ = "0.0.1"

stage5.1_fuller_application/pycasa/app/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)