From abcfb75f72247a0bb6bfcddd89a5b8f87bffe122 Mon Sep 17 00:00:00 2001 From: Askill Date: Sat, 30 Oct 2021 15:16:35 +0200 Subject: [PATCH] added packaging information --- .gitignore | 138 +++++++++++++++++++++++++++++++++++++++ README.md | 43 ------------ README.rst | 45 +++++++++++++ VERSION | 1 + VideoReader.py | 132 ------------------------------------- __init__.py | 0 requirements.txt | 1 + setup.py | 60 +++++++++++++++++ test.py => tests/test.py | 0 9 files changed, 245 insertions(+), 175 deletions(-) create mode 100644 .gitignore delete mode 100644 README.md create mode 100644 README.rst create mode 100644 VERSION delete mode 100644 VideoReader.py create mode 100644 __init__.py create mode 100644 requirements.txt create mode 100644 setup.py rename test.py => tests/test.py (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbf1f6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ + Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +src/ +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 9aa6891..0000000 --- a/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# CV2 Threaded Video Capture - -Not much to say here, it enables you to read an entire video or a number of frames from a video in an extra thread with some nice syntax. - -This project was initially part of my video synopsis project, wich is why the config dict() is required. - -### Full video -```python -from VideoReader import VideoReader -import os - -fileName = "out.mp4" -dirName = os.path.join(os.path.dirname(__file__), "generate test footage") - -config = {} -config["inputPath"] = os.path.join(dirName, fileName) -config["videoBufferLength"] = 100 - -with VideoReader(config) as reader: - while not reader.videoEnded(): - framenumber, frame = reader.pop() - print(framenumber) -``` - -### Selection of Frames -```python -from VideoReader import VideoReader -import os - -fileName = "out.mp4" -dirName = os.path.join(os.path.dirname(__file__), "generate test footage") - -config = {} -config["inputPath"] = os.path.join(dirName, fileName) -config["videoBufferLength"] = 100 - -frameList = list(range(100, 500)) - -with VideoReader(config, frameList) as reader: - while not reader.videoEnded(): - framenumber, frame = reader.pop() - print(framenumber) -``` \ No newline at end of file diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..b754ed1 --- /dev/null +++ b/README.rst @@ -0,0 +1,45 @@ +# CV2 Threaded Video Capture + +Not much to say here, it enables you to read an entire video or a number of frames from a video in an extra thread with some nice syntax. + +This project was initially part of my video synopsis project, wich is why the config dict() is required. + +### Full video + + + from VideoReader import VideoReader + import os + + fileName = "out.mp4" + dirName = os.path.join(os.path.dirname(__file__), "generate test footage") + + config = {} + config["inputPath"] = os.path.join(dirName, fileName) + config["videoBufferLength"] = 100 + + with VideoReader(config) as reader: + while not reader.videoEnded(): + framenumber, frame = reader.pop() + print(framenumber) + + +### Selection of Frames + + + from VideoReader import VideoReader + import os + + fileName = "out.mp4" + dirName = os.path.join(os.path.dirname(__file__), "generate test footage") + + config = {} + config["inputPath"] = os.path.join(dirName, fileName) + config["videoBufferLength"] = 100 + + frameList = list(range(100, 500)) + + with VideoReader(config, frameList) as reader: + while not reader.videoEnded(): + framenumber, frame = reader.pop() + print(framenumber) + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..afaf360 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/VideoReader.py b/VideoReader.py deleted file mode 100644 index ae77f69..0000000 --- a/VideoReader.py +++ /dev/null @@ -1,132 +0,0 @@ -from queue import Queue - -import cv2 -import threading -import os - -class VideoReader: - listOfFrames = None - w = None - h = None - - def __init__(self, config, setOfFrames=None): - videoPath = config["inputPath"] - self.videoPath = videoPath - - if videoPath is None: - raise Exception("VideoReader:: Video reader needs a videoPath!") - if not os.path.exists(videoPath): - raise Exception("VideoReader:: Provided video path does not exist") - - self.lastFrame = 0 - # buffer data struct: - # buffer = Queue([(frameNumber, frame), ]) - self.buffer = Queue(config["videoBufferLength"]) - self.vc = cv2.VideoCapture(videoPath) - self.stopped = False - self.getWH() - self.calcFPS() - self.calcLength() - self.calcStartTime() - if setOfFrames is not None: - self.listOfFrames = sorted(setOfFrames) - - def __enter__(self): - self.fillBuffer() - return self - - def __exit__(self, type, value, traceback): - self.stop() - - def stop(self): - self.thread.join() - self.vc.release() - - def pop(self): - return self.buffer.get(block=True) - - def fillBuffer(self, listOfFrames=None): - self.endFrame = int(self.vc.get(cv2.CAP_PROP_FRAME_COUNT)) - if listOfFrames is not None: - self.listOfFrames = listOfFrames - - if self.listOfFrames is not None: - self.thread = threading.Thread( - target=self.readFramesByList, args=()) - else: - self.thread = threading.Thread(target=self.readFrames, args=()) - self.thread.start() - - def readFrames(self): - '''Reads video from start to finish''' - while self.lastFrame < self.endFrame: - res, frame = self.vc.read() - if res: - self.buffer.put((self.lastFrame, frame)) - self.lastFrame += 1 - - self.stopped = True - - def readFramesByList(self): - '''Reads all frames from a list of frame numbers''' - self.vc.set(1, self.listOfFrames[0]) - self.lastFrame = self.listOfFrames[0] - self.endFrame = self.listOfFrames[-1] - - while self.lastFrame < self.endFrame: - if self.lastFrame in self.listOfFrames: - res, frame = self.vc.read() - if res: - self.buffer.put((self.lastFrame, frame)) - else: - print("READING FRAMES IS FALSE") - # since the list is sorted the first element is always the lowest relevant framenumber - # [0,1,2,3,32,33,34,35,67,68,69] - self.listOfFrames.pop(0) - self.lastFrame += 1 - else: - # if current Frame number is not in list of Frames, we can skip a few frames - self.vc.set(1, self.listOfFrames[0]) - self.lastFrame = self.listOfFrames[0] - - self.stopped = True - - def videoEnded(self): - if self.stopped and self.buffer.empty(): - return True - else: - return False - - def calcFPS(self): - self.fps = self.vc.get(cv2.CAP_PROP_FPS) - - def getFPS(self): - if self.fps is None: - self.calcFPS() - return self.fps - - def calcLength(self): - fc = int(self.vc.get(cv2.CAP_PROP_FRAME_COUNT)) - self.length = fc / self.getFPS() - - def getLength(self): - if self.length is None: - self.calcLength() - return self.length - - def calcStartTime(self): - starttime = os.stat(self.videoPath).st_mtime - length = self.getLength() - starttime = starttime - length - self.starttime = starttime - - def getStartTime(self): - return self.starttime - - def getWH(self): - '''get width and height''' - if self.w is None or self.h is None: - res, image = self.vc.read() - self.w = image.shape[1] - self.h = image.shape[0] - return (self.w, self.h) diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1db7aea --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +opencv-python \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..9f23eef --- /dev/null +++ b/setup.py @@ -0,0 +1,60 @@ +# -*- coding: utf8 -*- +# +# This file were created by Python Boilerplate. Use Python Boilerplate to start +# simple, usable and best-practices compliant Python projects. +# +# Learn more about it at: http://github.com/fabiommendes/python-boilerplate/ +# + +import os + +from setuptools import setup, find_packages + +# Meta information +version = open('VERSION').read().strip() +dirname = os.path.dirname(__file__) + +# Save version and author to __meta__.py +path = os.path.join(dirname, 'src', 'CV2-Threaded-Video-Capture', '__meta__.py') +data = '''# Automatically created. Please do not edit. +__version__ = u'%s' +__author__ = u'Patrice Matz' +''' % version +with open(path, 'wb') as F: + F.write(data.encode()) + +setup( + # Basic info + name='CV2-Threaded-Video-Capture', + version=version, + author='Patrice Matz', + author_email='mail@patricematz.de', + url='https://github.com/Askill/CV2-Threaded-Video-Capture', + description='Reads a video into a buffer in an extra thread with some nice syntax.', + long_description=open('README.rst').read(), + classifiers=[ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Operating System :: POSIX', + 'Programming Language :: Python', + 'Topic :: Software Development :: Libraries', + ], + keywords = ['multi-threaded',"video reader", 'CV2', 'CV'], + # Packages and depencies + package_dir={'': 'src'}, + packages=find_packages('src'), + install_requires=[ + 'opencv-python' + ], + # Data files + package_data={ + }, + # Scripts + entry_points={ + }, + + # Other configurations + zip_safe=False, + platforms='any', +) \ No newline at end of file diff --git a/test.py b/tests/test.py similarity index 100% rename from test.py rename to tests/test.py