From f86edd4f2407554df5c6c3843da79f585094b433 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 18 May 2017 00:07:02 +0200 Subject: [PATCH] Seven segments OCR image processing (#7632) * Add initial seven segments OCR image processing * Fix typo --- .coveragerc | 1 + .../components/image_processing/__init__.py | 11 +- .../image_processing/seven_segments.py | 114 ++++++++++++++++++ 3 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 homeassistant/components/image_processing/seven_segments.py diff --git a/.coveragerc b/.coveragerc index 5b11aea6fd8..4ba57e0f750 100644 --- a/.coveragerc +++ b/.coveragerc @@ -252,6 +252,7 @@ omit = homeassistant/components/ifttt.py homeassistant/components/image_processing/dlib_face_detect.py homeassistant/components/image_processing/dlib_face_identify.py + homeassistant/components/image_processing/seven_segments.py homeassistant/components/joaoapps_join.py homeassistant/components/keyboard.py homeassistant/components/keyboard_remote.py diff --git a/homeassistant/components/image_processing/__init__.py b/homeassistant/components/image_processing/__init__.py index a37f1163b3d..7ca8b48931b 100644 --- a/homeassistant/components/image_processing/__init__.py +++ b/homeassistant/components/image_processing/__init__.py @@ -11,25 +11,26 @@ import os import voluptuous as vol +import homeassistant.helpers.config_validation as cv from homeassistant.config import load_yaml_config_file from homeassistant.const import ( ATTR_ENTITY_ID, CONF_NAME, CONF_ENTITY_ID) from homeassistant.exceptions import HomeAssistantError -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.loader import get_component +_LOGGER = logging.getLogger(__name__) + DOMAIN = 'image_processing' DEPENDENCIES = ['camera'] -_LOGGER = logging.getLogger(__name__) - SCAN_INTERVAL = timedelta(seconds=10) DEVICE_CLASSES = [ - 'alpr', # automatic license plate recognition - 'face', # face + 'alpr', # Automatic license plate recognition + 'face', # Face + 'ocr', # OCR ] SERVICE_SCAN = 'scan' diff --git a/homeassistant/components/image_processing/seven_segments.py b/homeassistant/components/image_processing/seven_segments.py new file mode 100644 index 00000000000..07b9b9d5d80 --- /dev/null +++ b/homeassistant/components/image_processing/seven_segments.py @@ -0,0 +1,114 @@ +""" +Local optical character recognition processing of seven segements displays. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/image_processing.seven_segments/ +""" +import asyncio +import logging +import io +import os + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.core import split_entity_id +from homeassistant.components.image_processing import ( + PLATFORM_SCHEMA, ImageProcessingEntity, CONF_SOURCE, CONF_ENTITY_ID, + CONF_NAME) + +_LOGGER = logging.getLogger(__name__) + +CONF_DIGITS = 'digits' +CONF_HEIGHT = 'height' +CONF_SSOCR_BIN = 'ssocr' +CONF_THRESHOLD = 'threshold' +CONF_WIDTH = 'width' +CONF_X_POS = 'x_position' +CONF_Y_POS = 'y_position' + +DEFAULT_BINARY = 'ssocr' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_DIGITS, default=-1): cv.positive_int, + vol.Optional(CONF_HEIGHT, default=0): cv.positive_int, + vol.Optional(CONF_SSOCR_BIN, default=DEFAULT_BINARY): cv.string, + vol.Optional(CONF_THRESHOLD, default=0): cv.positive_int, + vol.Optional(CONF_WIDTH, default=0): cv.positive_int, + vol.Optional(CONF_X_POS, default=0): cv.string, + vol.Optional(CONF_Y_POS, default=0): cv.positive_int, +}) + + +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + """Set up the Seven segments OCR platform.""" + entities = [] + for camera in config[CONF_SOURCE]: + entities.append(ImageProcessingSsocr( + hass, camera[CONF_ENTITY_ID], config, camera.get(CONF_NAME) + )) + + async_add_devices(entities) + + +class ImageProcessingSsocr(ImageProcessingEntity): + """Representation of the seven segments OCR image processing entity.""" + + def __init__(self, hass, camera_entity, config, name): + """Initialize seven segments processing.""" + self.hass = hass + self._camera_entity = camera_entity + if name: + self._name = name + else: + self._name = "SevenSegement OCR {0}".format( + split_entity_id(camera_entity)[1]) + self._state = None + self.filepath = os.path.join(self.hass.config.config_dir, 'ocr.png') + self._command = [ + config[CONF_SSOCR_BIN], 'erosion', 'make_mono', 'crop', + str(config[CONF_X_POS]), str(config[CONF_Y_POS]), + str(config[CONF_WIDTH]), str(config[CONF_HEIGHT]), '-t', + str(config[CONF_THRESHOLD]), '-d', str(config[CONF_DIGITS]), + self.filepath + ] + + @property + def device_class(self): + """Return the class of this device, from component DEVICE_CLASSES.""" + return 'ocr' + + @property + def camera_entity(self): + """Return camera entity id from process pictures.""" + return self._camera_entity + + @property + def name(self): + """Return the name of the image processor.""" + return self._name + + @property + def state(self): + """Return the state of the entity.""" + return self._state + + def process_image(self, image): + """Process the image.""" + from PIL import Image + import subprocess + + stream = io.BytesIO(image) + img = Image.open(stream) + img.save(self.filepath, 'png') + + ocr = subprocess.Popen( + self._command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out = ocr.communicate() + if out[0] != b'': + self._state = out[0].strip().decode('utf-8') + else: + self._state = None + _LOGGER.warning( + "Unable to detect value: %s", out[1].strip().decode('utf-8'))