Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ are able to reach the end goal.
- add widgets to filter images
- step 6: pyface application: adding menu and branding
- step 7: pyface application: advanced features [OPTIONAL]
- step 8: 1-click installer
- step 8: Packaging and sharing


## Contributing
Expand Down
2 changes: 0 additions & 2 deletions stage5.1_fuller_application/pycasa/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@

__version__ = "0.0.1"
21 changes: 4 additions & 17 deletions stage5.1_fuller_application/setup.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
from os.path import abspath, dirname, join
from setuptools import setup, find_packages

HERE = dirname(abspath(__file__))

PKG_NAME = "pycasa"

info = {}
init_file = join(HERE, PKG_NAME, "__init__.py")
exec(open(init_file).read(), globals(), info)


setup(
name=PKG_NAME,
version=info["__version__"],
description='Hello world in pyface task',
name="pycasa",
version="0.0.1",
description='ETS based GUI application for image exploration and face '
'detection',
ext_modules=[],
packages=find_packages(),
data_files=[
(".", ["README.md"]),
],
entry_points={
'console_scripts': [
'pycasa = {}.app.main:main'.format(PKG_NAME),
],
},
)
2 changes: 0 additions & 2 deletions stage5.2_fuller_application/pycasa/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@

__version__ = "0.0.1"
21 changes: 4 additions & 17 deletions stage5.2_fuller_application/setup.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
from os.path import abspath, dirname, join
from setuptools import setup, find_packages

HERE = dirname(abspath(__file__))

PKG_NAME = "pycasa"

info = {}
init_file = join(HERE, PKG_NAME, "__init__.py")
exec(open(init_file).read(), globals(), info)


setup(
name=PKG_NAME,
version=info["__version__"],
description='Hello world in pyface task',
name="pycasa",
version="0.0.1",
description='ETS based GUI application for image exploration and face '
'detection',
ext_modules=[],
packages=find_packages(),
data_files=[
(".", ["README.md"]),
],
entry_points={
'console_scripts': [
'pycasa = {}.app.main:main'.format(PKG_NAME),
],
},
)
2 changes: 0 additions & 2 deletions stage5.3_fuller_application/pycasa/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@

__version__ = "0.0.1"
21 changes: 4 additions & 17 deletions stage5.3_fuller_application/setup.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
from os.path import abspath, dirname, join
from setuptools import setup, find_packages

HERE = dirname(abspath(__file__))

PKG_NAME = "pycasa"

info = {}
init_file = join(HERE, PKG_NAME, "__init__.py")
exec(open(init_file).read(), globals(), info)


setup(
name=PKG_NAME,
version=info["__version__"],
description='Hello world in pyface task',
name="pycasa",
version="0.0.1",
description='ETS based GUI application for image exploration and face '
'detection',
ext_modules=[],
packages=find_packages(),
data_files=[
(".", ["README.md"]),
],
entry_points={
'console_scripts': [
'pycasa = {}.app.main:main'.format(PKG_NAME),
],
},
)
2 changes: 0 additions & 2 deletions stage6_branded_application/pycasa/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@

__version__ = "0.0.1"
21 changes: 4 additions & 17 deletions stage6_branded_application/setup.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
from os.path import abspath, dirname, join
from setuptools import setup, find_packages

HERE = dirname(abspath(__file__))

PKG_NAME = "pycasa"

info = {}
init_file = join(HERE, PKG_NAME, "__init__.py")
exec(open(init_file).read(), globals(), info)


setup(
name=PKG_NAME,
version=info["__version__"],
description='Hello world in pyface task',
name="pycasa",
version="0.0.1",
description='ETS based GUI application for image exploration and face '
'detection',
ext_modules=[],
packages=find_packages(),
data_files=[
(".", ["README.md"]),
],
entry_points={
'console_scripts': [
'pycasa = {}.app.main:main'.format(PKG_NAME),
],
},
)
3 changes: 3 additions & 0 deletions stage8.1_packaging_setuptools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Final stage of the tutorial: packaging pycasa ETS pyface application
This stage finalizes the application `setup.py` file for easy packaging and
distribution.
2 changes: 2 additions & 0 deletions stage8.1_packaging_setuptools/pycasa/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

__version__ = "0.0.1"
Empty file.
68 changes: 68 additions & 0 deletions stage8.1_packaging_setuptools/pycasa/app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# coding=utf-8
""" TaskApplication object for the Pycasa app.
"""
import logging

from pyface.tasks.api import TasksApplication, TaskFactory
from pyface.api import SplashScreen
from pyface.action.api import Action
from pyface.action.schema.api import SchemaAddition, SGroup

from ..ui.tasks.pycasa_task import PycasaTask
from ..ui.image_resources import app_icon, new_icon

logger = logging.getLogger(__name__)


class PycasaApplication(TasksApplication):
""" An application to explore image files and detect faces.
"""
id = "pycasa_application"

name = "Pycasa"

description = "An example Tasks application that explores image files."

def _task_factories_default(self):
return [
TaskFactory(
id='pycasa.pycasa_task_factory',
name="Main Pycasa Task Factory",
factory=PycasaTask
)
]

def _icon_default(self):
return app_icon

def _splash_screen_default(self):
splash_screen = SplashScreen(image=app_icon)
return splash_screen

def create_new_task_window(self):
from pyface.tasks.task_window_layout import TaskWindowLayout

layout = TaskWindowLayout()
layout.items = [self.task_factories[0].id]
window = self.create_window(layout=layout)
self.add_window(window)
window.title += " {}".format(len(self.windows))
return window

def create_new_task_menu(self):
return SGroup(
Action(name="New",
accelerator='Ctrl+N',
on_perform=self.create_new_task_window,
image=new_icon),
id='NewGroup', name='NewGroup',
)

def _extra_actions_default(self):
extra_actions = [
SchemaAddition(id='pycasa.custom_new',
factory=self.create_new_task_menu,
path="MenuBar/File/OpenGroup",
absolute_position="first")
]
return extra_actions
11 changes: 11 additions & 0 deletions stage8.1_packaging_setuptools/pycasa/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

from pycasa.app.app import PycasaApplication


def main():
app = PycasaApplication()
app.run()


if __name__ == '__main__':
main()
Empty file.
9 changes: 9 additions & 0 deletions stage8.1_packaging_setuptools/pycasa/model/file_browser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from os.path import expanduser
from traits.api import Directory, Event, HasStrictTraits


class FileBrowser(HasStrictTraits):
root = Directory(expanduser("~"))

#: Item last double-clicked on in the tree view
requested_item = Event
64 changes: 64 additions & 0 deletions stage8.1_packaging_setuptools/pycasa/model/image_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# General imports
from os.path import splitext
import PIL.Image
from PIL.ExifTags import TAGS
from skimage import data
from skimage.feature import Cascade
import numpy as np

# ETS imports
from traits.api import (
Array, cached_property, Dict, File, HasStrictTraits, List, Property
)

SUPPORTED_FORMATS = [".png", ".jpg", ".jpeg", ".PNG", ".JPG", ".JPEG"]


class ImageFile(HasStrictTraits):
""" Model to hold an image file.
"""
filepath = File

metadata = Property(Dict, depends_on="filepath")

data = Property(Array, depends_on="filepath")

faces = List

def _is_valid_file(self):
return (
bool(self.filepath) and
splitext(self.filepath)[1].lower() in SUPPORTED_FORMATS
)

@cached_property
def _get_data(self):
if not self._is_valid_file():
return np.array([])
with PIL.Image.open(self.filepath) as img:
return np.asarray(img)

@cached_property
def _get_metadata(self):
if not self._is_valid_file():
return {}
with PIL.Image.open(self.filepath) as img:
exif = img._getexif()
if not exif:
return {}
return {TAGS[k]: v for k, v in exif.items() if k in TAGS}

def detect_faces(self):
# Load the trained file from the module root.
trained_file = data.lbp_frontal_face_cascade_filename()

# Initialize the detector cascade.
detector = Cascade(trained_file)

detected = detector.detect_multi_scale(img=self.data,
scale_factor=1.2,
step_ratio=1,
min_size=(60, 60),
max_size=(600, 600))
self.faces = detected
return self.faces
69 changes: 69 additions & 0 deletions stage8.1_packaging_setuptools/pycasa/model/image_folder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# General imports
import glob
from os.path import basename, expanduser, isdir

import numpy as np
import pandas as pd

# ETS imports
from traits.api import (
Directory, Event, HasStrictTraits, Instance, List, observe,
)

# Local imports
from pycasa.model.image_file import ImageFile, SUPPORTED_FORMATS

FILENAME_COL = "filename"
NUM_FACE_COL = "Num. faces"


class ImageFolder(HasStrictTraits):
""" Model for a folder of images.
"""
directory = Directory(expanduser("~"))

images = List(Instance(ImageFile))

data = Instance(pd.DataFrame)

data_updated = Event

def __init__(self, **traits):
# Don't forget this!
super(ImageFolder, self).__init__(**traits)
if not isdir(self.directory):
msg = f"The provided directory isn't a real directory: " \
f"{self.directory}"
raise ValueError(msg)
self.data = self._create_metadata_df()

@observe("directory")
def _update_images(self, event):
self.images = [
ImageFile(filepath=file)
for fmt in SUPPORTED_FORMATS
for file in glob.glob(f"{self.directory}/*{fmt}")
]

@observe("images.items")
def _update_metadata(self, event):
self.data = self._create_metadata_df()

def _create_metadata_df(self):
if not self.images:
return pd.DataFrame({FILENAME_COL: [], NUM_FACE_COL: []})
return pd.DataFrame([
{
FILENAME_COL: basename(img.filepath),
NUM_FACE_COL: np.nan,
**img.metadata

}
for img in self.images
])

def compute_num_faces(self, **kwargs):
for i, image in enumerate(self.images):
faces = image.detect_faces(**kwargs)
self.data[NUM_FACE_COL].iat[i] = len(faces)
self.data_updated = True
Empty file.
Loading