From ec9105b690974b0246e36769506e735c4edf069a Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 1 Mar 2023 21:38:09 +0100 Subject: Exif data reader and extractor --- test/extractor/image/test_photometrics.py | 138 ++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 test/extractor/image/test_photometrics.py (limited to 'test/extractor/image') diff --git a/test/extractor/image/test_photometrics.py b/test/extractor/image/test_photometrics.py new file mode 100644 index 0000000..6e3b661 --- /dev/null +++ b/test/extractor/image/test_photometrics.py @@ -0,0 +1,138 @@ +""" + +Part of the bsie test suite. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# standard imports +import unittest + +# bsie imports +from bsie.extractor import base +from bsie.utils import bsfs, node as _node, ns + +# objects to test +from bsie.extractor.image.photometrics import Exif, _gps_to_dec + + +## code ## + +class TestExif(unittest.TestCase): + + def test_gps_to_dec(self): + # deg+min+sec format + self.assertAlmostEqual(_gps_to_dec('29/1 58/1 45/1'.split()), 29.979167, 6) + self.assertAlmostEqual(_gps_to_dec('31 08 03'.split()), 31.134167, 6) + self.assertAlmostEqual(_gps_to_dec('20 40 586/10'.split()), 20.682944, 6) + self.assertAlmostEqual(_gps_to_dec('88/1 34 68/10'.split()), 88.568556, 6) + # deg+min format + self.assertAlmostEqual(_gps_to_dec('13 472167/10000 0/1 '.split()), 13.786945, 6) + self.assertAlmostEqual(_gps_to_dec('104/1 3215/100 0/1'.split()), 104.535833, 6) + + def test_eq(self): + # identical instances are equal + self.assertEqual(Exif(), Exif()) + self.assertEqual(hash(Exif()), hash(Exif())) + # comparison respects type + class Foo(): pass + self.assertNotEqual(Exif(), Foo()) + self.assertNotEqual(hash(Exif()), hash(Foo())) + self.assertNotEqual(Exif(), 1234) + self.assertNotEqual(hash(Exif()), hash(1234)) + self.assertNotEqual(Exif(), None) + self.assertNotEqual(hash(Exif()), hash(None)) + + def test_schema(self): + self.assertSetEqual({pred.uri for pred in Exif().schema.predicates()}, { + ns.bsfs.Predicate, + ns.bse.exposure, + ns.bse.aperture, + ns.bse.iso, + ns.bse.focal_length, + ns.bse.width, + ns.bse.height, + ns.bse.orientation, + ns.bse.orientation_label, + ns.bse.altitude, + ns.bse.latitude, + ns.bse.longitude, + }) + + def test_extract(self): + ext = Exif() + node = _node.Node(ns.bsfs.File, '') # Blank node + content = { + 'Exif.Photo.ExposureTime': '10/600', + 'Exif.Photo.FNumber': '48/10', + 'Exif.Photo.ISOSpeedRatings': '400', + 'Exif.Photo.FocalLength': '460/10', + 'Exif.Photo.PixelXDimension': '4288', + 'Exif.Photo.PixelYDimension': '2848', + 'Exif.Image.Orientation': '1', + 'Exif.GPSInfo.GPSAltitude': '431/1', + 'Exif.GPSInfo.GPSLatitude': '46/1 11397/625 0/1', + 'Exif.GPSInfo.GPSLongitude': '7/1 131250/2500 0/1', + } + + # invalid principals are ignored + self.assertSetEqual(set(ext.extract(node, content, {ns.bse.filename})), set()) + # extract finds all relevant information + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.exposure)})), + {(node, ext.schema.predicate(ns.bse.exposure), 60.0)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.aperture)})), + {(node, ext.schema.predicate(ns.bse.aperture), 4.8)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.iso)})), + {(node, ext.schema.predicate(ns.bse.iso), 400)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.focal_length)})), + {(node, ext.schema.predicate(ns.bse.focal_length), 46.0)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.width)})), + {(node, ext.schema.predicate(ns.bse.width), 4288)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.height)})), + {(node, ext.schema.predicate(ns.bse.height), 2848)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.orientation)})), + {(node, ext.schema.predicate(ns.bse.orientation), 1)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.orientation_label)})), + {(node, ext.schema.predicate(ns.bse.orientation_label), 'landscape')}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.altitude)})), + {(node, ext.schema.predicate(ns.bse.altitude), 431.0)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.latitude)})), + {(node, ext.schema.predicate(ns.bse.latitude), 46.30392)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.longitude)})), + {(node, ext.schema.predicate(ns.bse.longitude), 7.875)}) + + # can pass multiple principals + self.assertSetEqual(set(ext.extract(node, content, { + ext.schema.predicate(ns.bse.exposure), + ext.schema.predicate(ns.bse.iso), + ext.schema.predicate(ns.bse.focal_length), + })), { + (node, ext.schema.predicate(ns.bse.exposure), 60.0), + (node, ext.schema.predicate(ns.bse.iso), 400), + (node, ext.schema.predicate(ns.bse.focal_length), 46.0), + }) + + # principals w/o content are ignored + self.assertSetEqual(set(ext.extract( + node, + content={'Exif.Photo.ExposureTime': '10/600'}, + principals={ + ext.schema.predicate(ns.bse.exposure), + ext.schema.predicate(ns.bse.iso), + ext.schema.predicate(ns.bse.focal_length), + }) + ), { + (node, ext.schema.predicate(ns.bse.exposure), 60.0), + }) + + # empty content is acceptable + self.assertSetEqual(set(ext.extract(node, {}, set(ext.principals))), set()) + # no principals is acceptable + self.assertSetEqual(set(ext.extract(node, content, set())), set()) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## -- cgit v1.2.3 From 4b5c4d486bb4f0f4da2e25ad464e8336a781cdcb Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Wed, 1 Mar 2023 22:31:03 +0100 Subject: removed module header stubs --- test/extractor/image/test_colors_spatial.py | 5 ----- test/extractor/image/test_photometrics.py | 5 ----- 2 files changed, 10 deletions(-) (limited to 'test/extractor/image') diff --git a/test/extractor/image/test_colors_spatial.py b/test/extractor/image/test_colors_spatial.py index ba551f3..967aaf2 100644 --- a/test/extractor/image/test_colors_spatial.py +++ b/test/extractor/image/test_colors_spatial.py @@ -1,9 +1,4 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import os import unittest diff --git a/test/extractor/image/test_photometrics.py b/test/extractor/image/test_photometrics.py index 6e3b661..0e0261b 100644 --- a/test/extractor/image/test_photometrics.py +++ b/test/extractor/image/test_photometrics.py @@ -1,9 +1,4 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" # standard imports import unittest -- cgit v1.2.3 From ba6329bbe14c832d42773dee2fe30bd7669ca255 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Thu, 2 Mar 2023 08:58:29 +0100 Subject: various minor fixes --- test/extractor/image/test_photometrics.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/extractor/image') diff --git a/test/extractor/image/test_photometrics.py b/test/extractor/image/test_photometrics.py index 0e0261b..fb219e2 100644 --- a/test/extractor/image/test_photometrics.py +++ b/test/extractor/image/test_photometrics.py @@ -95,6 +95,16 @@ class TestExif(unittest.TestCase): self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.longitude)})), {(node, ext.schema.predicate(ns.bse.longitude), 7.875)}) + # check orientation label + self.assertSetEqual(set(ext.extract( + node, { + 'Exif.Photo.PixelXDimension': '4288', + 'Exif.Photo.PixelYDimension': '2848', + 'Exif.Image.Orientation': '5', + }, + {ext.schema.predicate(ns.bse.orientation_label)})), + {(node, ext.schema.predicate(ns.bse.orientation_label), 'portrait')}) + # can pass multiple principals self.assertSetEqual(set(ext.extract(node, content, { ext.schema.predicate(ns.bse.exposure), -- cgit v1.2.3 From d2052e77210e0ace2c5f06e48afe2a8acb412965 Mon Sep 17 00:00:00 2001 From: Matthias Baumgartner Date: Sat, 4 Mar 2023 13:41:13 +0100 Subject: namespace refactoring and cleanup --- test/extractor/image/test_colors_spatial.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'test/extractor/image') diff --git a/test/extractor/image/test_colors_spatial.py b/test/extractor/image/test_colors_spatial.py index 967aaf2..902ab6d 100644 --- a/test/extractor/image/test_colors_spatial.py +++ b/test/extractor/image/test_colors_spatial.py @@ -19,8 +19,8 @@ from bsie.extractor.image.colors_spatial import ColorsSpatial class TestColorsSpatial(unittest.TestCase): def setUp(self): # content id with default constructors (width=32, height=32, exp=4) - self.instance_prefix = 'http://ie.bsfs.ai/schema/Feature/ColorsSpatial' - self.predicate_prefix = 'http://bsfs.ai/schema/Entity/colors_spatial' + self.instance_prefix = 'https://schema.bsfs.io/ie/Literal/Array/Feature/ColorsSpatial' + self.predicate_prefix = 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_' self.uuid = 'adee8d6c43687021e1c5bffe56bcfe727f1638d792744137181304ef889dac2a' def test_essentials(self): @@ -50,7 +50,7 @@ class TestColorsSpatial(unittest.TestCase): def test_schema(self): schema = bsfs.schema.from_string(base.SCHEMA_PREAMBLE + f''' - <{self.instance_prefix}> rdfs:subClassOf bsfs:Feature ; + <{self.instance_prefix}> rdfs:subClassOf bsa:Feature ; # annotations rdfs:label "Spatially dominant colors"^^xsd:string ; schema:description "Domiant colors of subregions in an image."^^xsd:string ; @@ -63,8 +63,8 @@ class TestColorsSpatial(unittest.TestCase): <{self.instance_prefix}/args#height> "32"^^xsd:integer ; <{self.instance_prefix}/args#exp> "4"^^xsd:float . - <{self.predicate_prefix}#{self.uuid}> rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + <{self.predicate_prefix}{self.uuid}> rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; rdfs:range <{self.instance_prefix}#{self.uuid}> ; bsfs:unique "true"^^xsd:boolean . ''') @@ -73,7 +73,7 @@ class TestColorsSpatial(unittest.TestCase): def test_extract(self): ext = ColorsSpatial(2,2,2) img = PIL.Image.open(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) - node = _node.Node(ns.bsfs.Entity, bsfs.URI('http://example.com/entity#1234')) + node = _node.Node(ns.bsn.Entity, bsfs.URI('http://example.com/entity#1234')) principals = set(ext.principals) self.assertEqual(len(principals), 1) # valid invocation yields feature -- cgit v1.2.3