Initial commit of skeleton.
authorBenjamin Braatz <benjamin.braatz@graph-it.com>
Wed, 11 Aug 2021 09:17:56 +0000 (11:17 +0200)
committerBenjamin Braatz <benjamin.braatz@graph-it.com>
Wed, 11 Aug 2021 09:17:56 +0000 (11:17 +0200)
.gitignore [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README.md [new file with mode: 0644]
controlpi_plugins/imageproc.py [new file with mode: 0644]
setup.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..f7e2588
--- /dev/null
@@ -0,0 +1,4 @@
+__pycache__/
+dist/
+controlpi_imageproc.egg-info/
+venv/
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..ebb8ac1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2021 Graph-IT GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..ba64656
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+# ControlPi Plugin for AI Image Processing
+This distribution package contains a plugin for the
+[ControlPi system](https://docs.graph-it.com/graphit/controlpi), that
+processes images from the controlpi-camera plugin with an AI model.
diff --git a/controlpi_plugins/imageproc.py b/controlpi_plugins/imageproc.py
new file mode 100644 (file)
index 0000000..273f4b5
--- /dev/null
@@ -0,0 +1,78 @@
+import asyncio
+import concurrent.futures
+import urllib.request
+import PIL
+
+from controlpi import BasePlugin, Message, MessageTemplate
+
+from typing import Deque, Tuple
+
+
+class ImageProc(BasePlugin):
+    # The configuration schema contains the properties that can and
+    # should be set in the configuration JSON file.
+    CONF_SCHEMA = {'properties':
+                   {'camera': {'type': 'string'},
+                    'url': {'type': 'string'}},
+                   'required': ['camera', 'url']}
+
+    def process_conf(self) -> None:
+        """Register plugin as bus client."""
+        # The latest available image:
+        self._current_image = None
+        # We want to send events with the analysis results:
+        sends = [MessageTemplate({'event': {'const': 'image analysed'},
+                                  'image': {'type': 'string'},
+                                  'category': {'type': 'string'}})]
+        # We want to receive new image events from the configured camera:
+        receives = [MessageTemplate({'original sender':
+                                     {'const': self.conf['camera']},
+                                     'event':
+                                     {'const': 'new image'},
+                                     'image': {'type': 'string'}})]
+        # We register ourselves at the message bus:
+        self.bus.register(self.name, 'ImageProc',
+                          sends, receives, self._receive)
+
+    async def _receive(self, message: Message) -> None:
+        # Since the only messages we receive are new image events,
+        # we can immediately process them by just setting
+        # self._current_image
+        self._current_image = message['image']
+
+    async def run(self) -> None:
+        """Run image processing."""
+        loop = asyncio.get_running_loop()
+        executor = concurrent.futures.ProcessPoolExecutor()
+        # Initialise the model:
+        model = await loop.run_in_executor(executor, Model())
+        print("Model initialised.")
+        while True:
+            # Wait until an image is there:
+            while not self._current_image:
+                await asyncio.sleep(1)
+            image = self._current_image
+            url = self.conf['url'] + image
+            # Give it to the model:
+            category = await loop.run_in_executor(executor,
+                                                  model.analyse(url))
+            # Send the result on the message bus:
+            await self.bus.send(Message(self.name,
+                                        {'event': 'image analysed',
+                                         'image': image,
+                                         'category': category}))
+
+
+class Model:
+    def __init__(self):
+        # Dummy model just sleeps for 10 seconds to simulate heavy work:
+        time.sleep(10)
+
+    def analyse(self, url):
+        # Load image from given URL into PIL:
+        image = PIL.Image.open(urllib.request.urlopen(url))
+        # Dummy model just sleeps for 5 seconds to simulate heavy work:
+        time.sleep(5)
+        # Return image size as "category":
+        width, height = image.size
+        return f"{width}x{height}"
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..886691b
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,25 @@
+import setuptools
+
+with open("README.md", "r") as readme_file:
+    long_description = readme_file.read()
+
+setuptools.setup(
+    name="controlpi-imageproc",
+    version="0.1.0",
+    author="Graph-IT GmbH",
+    author_email="info@graph-it.com",
+    description="ControlPi Plugin for AI Image Processing",
+    long_description=long_description,
+    long_description_content_type="text/markdown",
+    url="http://docs.graph-it.com/graphit/controlpi-imageproc",
+    packages=["controlpi_plugins"],
+    install_requires=[
+        "Pillow",
+        "controlpi @ git+git://git.graph-it.com/graphit/controlpi.git@master",
+    ],
+    classifiers=[
+        "Programming Language :: Python",
+        "License :: OSI Approved :: MIT License",
+        "Operating System :: OS Independent",
+    ],
+)