From 233da9c188953efb45e28e07fe6ac8fa5d8e5e0b Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:22:41 +0100 Subject: [PATCH 01/10] Remove blank line --- tests/basic.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/basic.py b/tests/basic.py index 8a8f5ee..c241339 100644 --- a/tests/basic.py +++ b/tests/basic.py @@ -1,4 +1,3 @@ - import keras_video import unittest import os From 7cad240afb0ed543f90d3c3c5a18cd1e74db886b Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:23:23 +0100 Subject: [PATCH 02/10] Avoid use of on_epoch_end from children class Issue #17 - because the mother class is called with super(), the on_epoch_end is call twice in SlidingFrameGenerator and it fails if transformation should be applied. Because vid_info is not initialized. We now can use a special on_epoch_at_init argument to avoid the call. --- src/keras_video/generator.py | 3 ++- src/keras_video/sliding.py | 2 +- tests/slinding.py | 46 ++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/slinding.py diff --git a/src/keras_video/generator.py b/src/keras_video/generator.py index 8bd86e4..52c1e47 100644 --- a/src/keras_video/generator.py +++ b/src/keras_video/generator.py @@ -199,7 +199,8 @@ def __init__( self.classes_count = len(classes) # to initialize transformations and shuffle indices - self.on_epoch_end() + if 'no_epoch_at_init' not in kwargs: + self.on_epoch_end() kind = "train" if _validation_data is not None: diff --git a/src/keras_video/sliding.py b/src/keras_video/sliding.py index 7be7d61..a78aaaf 100644 --- a/src/keras_video/sliding.py +++ b/src/keras_video/sliding.py @@ -53,7 +53,7 @@ class SlidingFrameGenerator(VideoFrameGenerator): """ def __init__(self, *args, sequence_time: int = None, **kwargs): - super().__init__(*args, **kwargs) + super().__init__(no_epoch_at_init=True, *args, **kwargs) self.sequence_time = sequence_time self.sample_count = 0 diff --git a/tests/slinding.py b/tests/slinding.py new file mode 100644 index 0000000..c6c3049 --- /dev/null +++ b/tests/slinding.py @@ -0,0 +1,46 @@ +import keras_video +import keras +import unittest +import os +import sys +import shutil +sys.path.insert(0, './src') + + +class TestSlinding(unittest.TestCase): + + testdir = 'test_vids' + + def setUp(self): + dirname = self.testdir + os.makedirs(dirname) + + def _write_zero(cl, i): + shutil.copy( + 'tests/vidtest.ogv', + os.path.join(self.testdir, '%s_%d.ogv' % (cl, i)) + ) + + for i in range(10): + for cl in ['A', 'B', 'C']: + _write_zero(cl, i) + + def tearDown(self): + shutil.rmtree(self.testdir) + + def test_init(self): + """ Check if slinding generator init """ + g = keras_video.SlidingFrameGenerator( + glob_pattern=os.path.join(self.testdir, '{classname}_*.ogv')) + assert 'A' in g.classes + assert 'B' in g.classes + assert 'C' in g.classes + + assert g.files_count == 30 + + def test_with_transformation(self): + """ Check if transformation works with slinding frame generator """ + tr = keras.preprocessing.image.ImageDataGenerator(rotation_range=10) + keras_video.SlidingFrameGenerator( + transformation=tr, + glob_pattern=os.path.join(self.testdir, '{classname}_*.ogv')) From 44d78e57a6826c26b92b73b3e9cb66463bcf5191 Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:29:28 +0100 Subject: [PATCH 03/10] Set verison to 1.0.12 --- setup.py | 2 +- src/keras_video/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index dcdd427..b7ad838 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name='keras-video-generators', - version='1.0.11', + version='1.0.12', description='Keras sequence generators for video data', long_description=long_description, long_description_content_type="text/markdown", diff --git a/src/keras_video/__init__.py b/src/keras_video/__init__.py index 67e5969..446fa70 100644 --- a/src/keras_video/__init__.py +++ b/src/keras_video/__init__.py @@ -28,7 +28,7 @@ """ -__version__ = "1.0.11" +__version__ = "1.0.12" from . import flow from . import generator From f579660e809f760716d7fafb7c2065848346b7ca Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:40:18 +0100 Subject: [PATCH 04/10] Add coverage in tests --- Makefile | 9 +++++++++ requirements-tests.txt | 1 + 2 files changed, 10 insertions(+) diff --git a/Makefile b/Makefile index 4f55f9e..5fe50c9 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +.PHONY: tests build: python3 setup.py sdist @@ -10,3 +11,11 @@ doc: clean: rm -rf *.egg-info build dist src/keras_video_generators.egg-info + +tests: + nosetests -v tests/*.py --with-coverage --cover-package keras_video + +tests-html: + nosetests -v tests/*.py --with-coverage --cover-package keras_video \ + --cover-html --cover-html-dir=coverage + xdg-open coverage diff --git a/requirements-tests.txt b/requirements-tests.txt index fc0e9f6..08ec0c7 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -1,2 +1,3 @@ nose +coverage tensorflow From ce76f1801bc45afe60f1475a24d6a5238a2903aa Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:40:35 +0100 Subject: [PATCH 05/10] Use makefile to launch tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fcf1574..b7f476e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ install: - pip install -r requirements-tests.txt # command to run tests script: - - nosetests -v tests/*.py + - make tests From 8ba7462b181c8e572b82b149d6f7cf9597aeff3f Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:40:57 +0100 Subject: [PATCH 06/10] Enhance coverage by trying to get frames --- tests/slinding.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/slinding.py b/tests/slinding.py index c6c3049..ec944e0 100644 --- a/tests/slinding.py +++ b/tests/slinding.py @@ -38,9 +38,19 @@ def test_init(self): assert g.files_count == 30 + # check get item + seq, labels = next(g) + assert seq.shape == (16, 5, 224, 224, 3) + assert labels.shape == (16, 3) + def test_with_transformation(self): """ Check if transformation works with slinding frame generator """ tr = keras.preprocessing.image.ImageDataGenerator(rotation_range=10) - keras_video.SlidingFrameGenerator( + g = keras_video.SlidingFrameGenerator( transformation=tr, glob_pattern=os.path.join(self.testdir, '{classname}_*.ogv')) + + # check get item + seq, labels = next(g) + assert seq.shape == (16, 5, 224, 224, 3) + assert labels.shape == (16, 3) From d66cd822592b2f78dd02b1ecca1cfe621d237159 Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:41:24 +0100 Subject: [PATCH 07/10] Add changelog --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 10c2478..d366b95 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,8 @@ Each of these generators accepts parameters: # Changelog +## v1.0.12 +- fix transformation error with SlidingFrameGenerator ## v1.0.11 - set generator to be Iterable From 8d65bb28113b19af0bf748efc4038c68ce3c1486 Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sat, 7 Mar 2020 10:41:53 +0100 Subject: [PATCH 08/10] Add experimental note --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d366b95..2c1ca2e 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ The package contains 3 generators that inherits `Sequence` interface. So they ma - `VideoFrameGenerator` that will take the choosen number of frames from the entire video - `SlidingFrameGenerator` that takes frames with decay for the entire video or with a sequence time -- `OpticalFlowGenerator` that gives optical flow sequence from frames with different methods +- `OpticalFlowGenerator` that gives optical flow sequence from frames with different methods (experimental) Each of these generators accepts parameters: From 34c34459964ca53f765d407f0dbf48d33ee1630b Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sun, 8 Mar 2020 09:12:30 +0100 Subject: [PATCH 09/10] Open html file with tests-html --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5fe50c9..134268a 100644 --- a/Makefile +++ b/Makefile @@ -18,4 +18,4 @@ tests: tests-html: nosetests -v tests/*.py --with-coverage --cover-package keras_video \ --cover-html --cover-html-dir=coverage - xdg-open coverage + xdg-open coverage/index.html From ce2fc6a069555f43957655c33cca0c431a612689 Mon Sep 17 00:00:00 2001 From: Patrice Ferlet Date: Sun, 8 Mar 2020 09:12:40 +0100 Subject: [PATCH 10/10] Add more tests to cover code - Add init opticalflow checks - Add spliting tests, to check if all classes can split test and validation subset --- tests/opticalflow.py | 66 ++++++++++++++++++++++++++++++++++++++++++++ tests/split.py | 55 ++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 tests/opticalflow.py create mode 100644 tests/split.py diff --git a/tests/opticalflow.py b/tests/opticalflow.py new file mode 100644 index 0000000..8166c84 --- /dev/null +++ b/tests/opticalflow.py @@ -0,0 +1,66 @@ +import keras_video +import keras +import unittest +import os +import sys +import shutil +sys.path.insert(0, './src') + + +class TestOpticalFlow(unittest.TestCase): + + testdir = 'test_vids' + + def setUp(self): + dirname = self.testdir + os.makedirs(dirname) + + def _write_zero(cl, i): + shutil.copy( + 'tests/vidtest.ogv', + os.path.join(self.testdir, '%s_%d.ogv' % (cl, i)) + ) + + for i in range(10): + for cl in ['A', 'B', 'C']: + _write_zero(cl, i) + + def tearDown(self): + shutil.rmtree(self.testdir) + + def test_init(self): + """ Check opticalflow init """ + gen = keras_video.OpticalFlowGenerator( + glob_pattern=os.path.join(self.testdir, '{classname}_*.ogv') + ) + assert len(gen.classes) == 3 + assert gen.files_count == 30 + + def __get_with_method(self, method=keras_video.METHOD_ABS_DIFF): + tr = keras.preprocessing.image.ImageDataGenerator(rotation_range=10) + + gen = keras_video.OpticalFlowGenerator( + method=method, + glob_pattern=os.path.join(self.testdir, '{classname}_*.ogv'), + transformation=tr + ) + + seq, labels = next(gen) + assert seq.shape == (16, 5, 224, 224, 3) + assert labels.shape == (16, 3) + + def test_absdiff(self): + """ Check absdiff """ + self.__get_with_method(keras_video.METHOD_ABS_DIFF) + + def test_absdiffmask(self): + """ Check absdiff masked """ + self.__get_with_method(keras_video.METHOD_DIFF_MASK) + + def test_opticalflow(self): + """ Check opticalflow""" + self.__get_with_method(keras_video.METHOD_OPTICAL_FLOW) + + def test_opticalflowmask(self): + """ Check opticalflow masked """ + self.__get_with_method(keras_video.METHOD_FLOW_MASK) diff --git a/tests/split.py b/tests/split.py new file mode 100644 index 0000000..9e03c10 --- /dev/null +++ b/tests/split.py @@ -0,0 +1,55 @@ +import keras_video +import unittest +import os +import sys +import shutil +sys.path.insert(0, './src') + + +class TestSplit(unittest.TestCase): + + testdir = 'test_vids' + + def setUp(self): + dirname = self.testdir + os.makedirs(dirname) + + def _write_zero(cl, i): + shutil.copy( + 'tests/vidtest.ogv', + os.path.join(self.testdir, '%s_%d.ogv' % (cl, i)) + ) + + for i in range(10): + for cl in ['A', 'B', 'C']: + _write_zero(cl, i) + + def tearDown(self): + shutil.rmtree(self.testdir) + + def __split(self, + kind=keras_video.VideoFrameGenerator, + vc=0, + tc=0): + pattern = os.path.join(self.testdir, '{classname}_*.ogv') + gen = kind( + glob_pattern=pattern, + split_test=.2, + split_val=.3) + valid = gen.get_validation_generator() + test = gen.get_test_generator() + + assert valid.files_count == vc + assert test.files_count == tc + + def test_videoframegenerator_split(self): + """ Check spliting VideoFrameGenerator """ + self.__split(keras_video.VideoFrameGenerator, 9, 3) + + def test_slidinggenerator_split(self): + """ Check splitint SlidingFrameGenerator """ + self.__split(keras_video.SlidingFrameGenerator, 9, 3) + + def test_flowgenerator_split(self): + """ Check splitint OpticalFlowGenerator """ + self.__split(keras_video.OpticalFlowGenerator, 9, 3)