text: """
  Component that performs OpenCV classification on images.
  
  For more details about this platform, please refer to the documentation at
  https://home-assistant.io/components/image_processing.opencv/
  """
  from datetime import timedelta
  import logging
  
  import requests
  
  import voluptuous as vol
  
  from homeassistant.core import split_entity_id
  from homeassistant.components.image_processing import (
      CONF_SOURCE, CONF_ENTITY_ID, CONF_NAME, PLATFORM_SCHEMA,
      ImageProcessingEntity)
  import homeassistant.helpers.config_validation as cv
  
  REQUIREMENTS = ['numpy==1.13.3']
  
  _LOGGER = logging.getLogger(__name__)
  
  ATTR_MATCHES = 'matches'
  ATTR_TOTAL_MATCHES = 'total_matches'
  
  CASCADE_URL = \
      'https://raw.githubusercontent.com/opencv/opencv/master/data/' + \
      'lbpcascades/lbpcascade_frontalface.xml'
  
  CONF_CLASSIFIER = 'classifier'
  CONF_FILE = 'file'
  CONF_MIN_SIZE = 'min_size'
  CONF_NEIGHBORS = 'neighbors'
  CONF_SCALE = 'scale'
  
  DEFAULT_CLASSIFIER_PATH = 'lbp_frontalface.xml'
  DEFAULT_MIN_SIZE = (30, 30)
  DEFAULT_NEIGHBORS = 4
  DEFAULT_SCALE = 1.1
  DEFAULT_TIMEOUT = 10
  
  SCAN_INTERVAL = timedelta(seconds=2)
  
  PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
      vol.Optional(CONF_CLASSIFIER, default=None): {
          cv.string: vol.Any(
              cv.isfile,
              vol.Schema({
                  vol.Required(CONF_FILE): cv.isfile,
                  vol.Optional(CONF_SCALE, DEFAULT_SCALE): float,
                  vol.Optional(CONF_NEIGHBORS, DEFAULT_NEIGHBORS):
                      cv.positive_int,
                  vol.Optional(CONF_MIN_SIZE, DEFAULT_MIN_SIZE):
                      vol.Schema((int, int))
              })
          )
      }
  })
  
  
  def _create_processor_from_config(hass, camera_entity, config):
      """Create an OpenCV processor from configuration."""
      classifier_config = config[CONF_CLASSIFIER]
      name = '{} {}'.format(
          config[CONF_NAME], split_entity_id(camera_entity)[1].replace('_', ' '))
  
      processor = OpenCVImageProcessor(
          hass, camera_entity, name, classifier_config)
  
      return processor
  
  
  def _get_default_classifier(dest_path):
      """Download the default OpenCV classifier."""
      _LOGGER.info('Downloading default classifier')
      req = requests.get(CASCADE_URL, stream=True)
      with open(dest_path, 'wb') as fil:
          for chunk in req.iter_content(chunk_size=1024):
              if chunk:  # filter out keep-alive new chunks
                  fil.write(chunk)
  
  
  def setup_platform(hass, config, add_devices, discovery_info=None):
      """Set up the OpenCV image processing platform."""
      try:
          # Verify opencv python package is preinstalled
          # pylint: disable=unused-import,unused-variable
          import cv2  # noqa
      except ImportError:
          _LOGGER.error("No opencv library found! " +
                        "Install or compile for your system " +
                        "following instructions here: " +
                        "http://opencv.org/releases.html")
          return
  
      entities = []
      if config[CONF_CLASSIFIER] is None:
          dest_path = hass.config.path(DEFAULT_CLASSIFIER_PATH)
          _get_default_classifier(dest_path)
          config[CONF_CLASSIFIER] = {
              'Face': dest_path
          }
  
      for camera in config[CONF_SOURCE]:
          entities.append(OpenCVImageProcessor(
              hass, camera[CONF_ENTITY_ID], camera.get(CONF_NAME),
              config[CONF_CLASSIFIER]
          ))
  
      add_devices(entities)
  
  
  class OpenCVImageProcessor(ImageProcessingEntity):
      """Representation of an OpenCV image processor."""
  
      def __init__(self, hass, camera_entity, name, classifiers):
          """Initialize the OpenCV entity."""
          self.hass = hass
          self._camera_entity = camera_entity
          if name:
              self._name = name
          else:
              self._name = "OpenCV {0}".format(
                  split_entity_id(camera_entity)[1])
          self._classifiers = classifiers
          self._matches = {}
          self._total_matches = 0
          self._last_image = None
  
      @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._total_matches
  
      @property
      def state_attributes(self):
          """Return device specific state attributes."""
          return {
              ATTR_MATCHES: self._matches,
              ATTR_TOTAL_MATCHES: self._total_matches
          }
  
      def process_image(self, image):
          """Process the image."""
          import cv2  # pylint: disable=import-error
          import numpy
  
          # pylint: disable=no-member
          cv_image = cv2.imdecode(numpy.asarray(bytearray(image)),
                                  cv2.IMREAD_UNCHANGED)
  
          for name, classifier in self._classifiers.items():
              scale = DEFAULT_SCALE
              neighbors = DEFAULT_NEIGHBORS
              min_size = DEFAULT_MIN_SIZE
              if isinstance(classifier, dict):
                  path = classifier[CONF_FILE]
                  scale = classifier.get(CONF_SCALE, scale)
                  neighbors = classifier.get(CONF_NEIGHBORS, neighbors)
                  min_size = classifier.get(CONF_MIN_SIZE, min_size)
              else:
                  path = classifier
  
              # pylint: disable=no-member
              cascade = cv2.CascadeClassifier(path)
  
              detections = cascade.detectMultiScale(
                  cv_image,
                  scaleFactor=scale,
                  minNeighbors=neighbors,
                  minSize=min_size)
              matches = {}
              total_matches = 0
              regions = []
              # pylint: disable=invalid-name
              for (x, y, w, h) in detections:
                  regions.append((int(x), int(y), int(w), int(h)))
                  total_matches += 1
  
              matches[name] = regions
  
          self._matches = matches
          self._total_matches = total_matches
  