Skip to content

Commit ed645c0

Browse files
Add support for folder visualization
1 parent eb4ddfe commit ed645c0

21 files changed

+444
-0
lines changed
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_first_application/pycasa/app/__init__.py

Whitespace-only changes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# coding=utf-8
2+
""" TaskApplication object for the Pycasa app.
3+
"""
4+
import logging
5+
6+
from pyface.tasks.api import TasksApplication, TaskFactory
7+
from ..ui.tasks.pycasa_task import PycasaTask
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
class PycasaApplication(TasksApplication):
13+
""" An application to say hello.
14+
"""
15+
id = "pycasa_application"
16+
17+
name = "Pycasa"
18+
19+
description = "An example Tasks application that explores image files."
20+
21+
def _task_factories_default(self):
22+
return [
23+
TaskFactory(
24+
id='pycasa.pycasa_task_factory',
25+
name="Main Pycasa Task Factory",
26+
factory=PycasaTask
27+
)
28+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
from pycasa.app.app import PycasaApplication
3+
4+
5+
def main():
6+
app = PycasaApplication()
7+
app.run()
8+
9+
10+
if __name__ == '__main__':
11+
main()

stage5.1_first_application/pycasa/model/__init__.py

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from os.path import expanduser
2+
from traits.api import Directory, Event, HasStrictTraits
3+
4+
5+
class FileBrowser(HasStrictTraits):
6+
root = Directory(expanduser("~"))
7+
8+
#: Item last double-clicked on in the tree view
9+
requested_item = Event
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# General imports
2+
import os
3+
import PIL.Image
4+
from PIL.ExifTags import TAGS
5+
import numpy as np
6+
7+
# ETS imports
8+
from traits.api import cached_property, Dict, File, HasStrictTraits, Property
9+
10+
SUPPORTED_FORMATS = [".png", ".jpg", ".jpeg"]
11+
12+
13+
class ImageFile(HasStrictTraits):
14+
""" Model to hold an image file.
15+
"""
16+
filepath = File
17+
18+
metadata = Property(Dict, depends_on="filepath")
19+
20+
def to_array(self):
21+
file_ext = os.path.splitext(self.filepath)[1].lower()
22+
if not self.filepath or file_ext not in SUPPORTED_FORMATS:
23+
return np.array([])
24+
25+
with PIL.Image.open(self.filepath) as img:
26+
return np.asarray(img)
27+
28+
@cached_property
29+
def _get_metadata(self):
30+
file_ext = os.path.splitext(self.filepath)[1].lower()
31+
if not self.filepath or file_ext not in SUPPORTED_FORMATS:
32+
return {}
33+
34+
with PIL.Image.open(self.filepath) as img:
35+
exif = img._getexif()
36+
37+
if exif:
38+
return {TAGS[k]: v for k, v in exif.items()
39+
if k in TAGS}
40+
else:
41+
return {}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# General imports
2+
import os
3+
4+
import pandas as pd
5+
import numpy as np
6+
7+
# ETS imports
8+
from traits.api import Directory, HasStrictTraits, Instance
9+
10+
# Local imports
11+
from .image_file import ImageFile, SUPPORTED_FORMATS
12+
13+
14+
class ImageFolder(HasStrictTraits):
15+
""" Model to hold an image folder.
16+
"""
17+
path = Directory
18+
19+
data = Instance(pd.DataFrame)
20+
21+
def __init__(self, **traits):
22+
# Don't forget this!
23+
super(ImageFolder, self).__init__(**traits)
24+
if not os.path.isdir(self.path):
25+
msg = f"Unable to create an ImageFolder from {self.path} since" \
26+
f" it is not a valid directory."
27+
raise ValueError(msg)
28+
29+
self.data = self.to_dataframe()
30+
31+
def to_dataframe(self):
32+
if not self.path:
33+
return pd.DataFrame({"filename": [], "Num. faces": []})
34+
35+
data = []
36+
for filename in os.listdir(self.path):
37+
file_ext = os.path.splitext(filename)[1].lower()
38+
if file_ext in SUPPORTED_FORMATS:
39+
filepath = os.path.join(self.path, filename)
40+
img_file = ImageFile(filepath=filepath)
41+
file_data = {"filename": filename, "Num. faces": np.nan}
42+
try:
43+
file_data.update(img_file.metadata)
44+
except Exception as e:
45+
pass
46+
data.append(file_data)
47+
48+
return pd.DataFrame(data)

stage5.1_first_application/pycasa/model/tests/__init__.py

Whitespace-only changes.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from os.path import dirname, join
2+
from unittest import TestCase
3+
4+
import numpy as np
5+
6+
from pycasa.model.image_file import ImageFile
7+
8+
import ets_tutorial
9+
10+
TUTORIAL_DIR = dirname(ets_tutorial.__file__)
11+
12+
SAMPLE_IMG_DIR = join(TUTORIAL_DIR, "..", "sample_images")
13+
14+
SAMPLE_IMG1 = join(SAMPLE_IMG_DIR, "IMG-0311_xmas_2020.JPG")
15+
16+
17+
class TestImageFile(TestCase):
18+
def test_no_image_file(self):
19+
img = ImageFile()
20+
self.assertEqual(img.metadata, {})
21+
data = img.to_array()
22+
self.assertIsInstance(data, np.ndarray)
23+
self.assertEqual(data.shape, (0,))
24+
25+
def test_bad_type_image_file(self):
26+
img = ImageFile(filepath=__file__)
27+
self.assertEqual(img.metadata, {})
28+
data = img.to_array()
29+
self.assertIsInstance(data, np.ndarray)
30+
self.assertEqual(data.shape, (0,))
31+
32+
def test_image_metadata(self):
33+
img = ImageFile(filepath=SAMPLE_IMG1)
34+
self.assertNotEqual(img.metadata, {})
35+
for key in ['ExifVersion', 'ExifImageWidth', 'ExifImageHeight']:
36+
self.assertIn(key, img.metadata.keys())
37+
data = img.to_array()
38+
expected_shape = (img.metadata['ExifImageHeight'],
39+
img.metadata['ExifImageWidth'], 3)
40+
self.assertEqual(data.shape, expected_shape)

0 commit comments

Comments
 (0)