diff --git a/.coveragerc b/.coveragerc
index ed969e545113d5a8f3eef30dc29c76d2b01bd553..279dc114a21c191e546cf8db098c7c6eb7e2d563 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -77,6 +77,9 @@ omit =
     homeassistant/components/octoprint.py
     homeassistant/components/*/octoprint.py
 
+    homeassistant/components/opencv.py
+    homeassistant/components/*/opencv.py
+
     homeassistant/components/qwikswitch.py
     homeassistant/components/*/qwikswitch.py
 
diff --git a/homeassistant/components/image_processing/opencv.py b/homeassistant/components/image_processing/opencv.py
new file mode 100644
index 0000000000000000000000000000000000000000..e48c14aeea517a14b0dc1c5b68a77ddc9f0bf7f3
--- /dev/null
+++ b/homeassistant/components/image_processing/opencv.py
@@ -0,0 +1,120 @@
+"""
+Component that performs OpenCV classification on images.
+
+For more details about this component, please refer to the documentation at
+https://home-assistant.io/components/image_processing.opencv/
+"""
+from datetime import timedelta
+import logging
+
+from homeassistant.core import split_entity_id
+from homeassistant.components.image_processing import (
+    ImageProcessingEntity,
+    PLATFORM_SCHEMA,
+)
+from homeassistant.components.opencv import (
+    ATTR_MATCHES,
+    CLASSIFIER_GROUP_CONFIG,
+    CONF_CLASSIFIER,
+    CONF_ENTITY_ID,
+    CONF_NAME,
+    process_image,
+)
+
+DEPENDENCIES = ['opencv']
+
+_LOGGER = logging.getLogger(__name__)
+
+DEFAULT_TIMEOUT = 10
+
+SCAN_INTERVAL = timedelta(seconds=2)
+
+PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(CLASSIFIER_GROUP_CONFIG)
+
+
+def _create_processor_from_config(hass, camera_entity, config):
+    """Create an OpenCV processor from configurtaion."""
+    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 setup_platform(hass, config, add_devices, discovery_info=None):
+    """Set up the OpenCV image processing platform."""
+    if discovery_info is None:
+        return
+
+    devices = []
+    for camera_entity in discovery_info[CONF_ENTITY_ID]:
+        devices.append(
+            _create_processor_from_config(
+                hass,
+                camera_entity,
+                discovery_info))
+
+    add_devices(devices)
+
+
+class OpenCVImageProcessor(ImageProcessingEntity):
+    """Representation of an OpenCV image processor."""
+
+    def __init__(self, hass, camera_entity, name, classifier_configs):
+        """Initialize the OpenCV entity."""
+        self.hass = hass
+        self._camera_entity = camera_entity
+        self._name = name
+        self._classifier_configs = classifier_configs
+        self._matches = {}
+        self._last_image = None
+
+    @property
+    def last_image(self):
+        """Return the last image."""
+        return self._last_image
+
+    @property
+    def matches(self):
+        """Return the matches it found."""
+        return self._matches
+
+    @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."""
+        total_matches = 0
+        for group in self._matches.values():
+            total_matches += len(group)
+        return total_matches
+
+    @property
+    def state_attributes(self):
+        """Return device specific state attributes."""
+        return {
+            ATTR_MATCHES: self._matches
+        }
+
+    def process_image(self, image):
+        """Process the image."""
+        self._last_image = image
+        self._matches = process_image(image,
+                                      self._classifier_configs,
+                                      False)
diff --git a/homeassistant/components/opencv.py b/homeassistant/components/opencv.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f53f0841a12c6246c370617058bd779988357ed
--- /dev/null
+++ b/homeassistant/components/opencv.py
@@ -0,0 +1,182 @@
+"""
+Support for OpenCV image/video processing.
+
+For more details about this component, please refer to the documentation at
+https://home-assistant.io/components/opencv/
+"""
+import asyncio
+import logging
+import os
+import voluptuous as vol
+
+from homeassistant.const import (
+    CONF_NAME,
+    CONF_ENTITY_ID,
+    CONF_FILE_PATH
+)
+from homeassistant.helpers import (
+    discovery,
+    config_validation as cv,
+)
+
+REQUIREMENTS = ['opencv-python==3.2.0.6', 'numpy==1.12.0', 'urllib3==1.21']
+
+_LOGGER = logging.getLogger(__name__)
+
+ATTR_MATCHES = 'matches'
+
+BASE_PATH = os.path.realpath(__file__)
+
+CASCADE_URL = \
+    'https://raw.githubusercontent.com/opencv/opencv/master/data/' +\
+    'lbpcascades/lbpcascade_frontalface.xml'
+
+CONF_CLASSIFIER = 'classifier'
+CONF_COLOR = 'color'
+CONF_GROUPS = 'classifier_group'
+CONF_MIN_SIZE = 'min_size'
+CONF_NEIGHBORS = 'neighbors'
+CONF_SCALE = 'scale'
+
+DATA_CLASSIFIER_GROUPS = 'classifier_groups'
+
+DEFAULT_COLOR = (255, 255, 0)
+DEFAULT_CLASSIFIER_PATH = os.path.join(
+    os.path.dirname(BASE_PATH),
+    'lbp_frontalface.xml')
+DEFAULT_NAME = 'OpenCV'
+DEFAULT_MIN_SIZE = (30, 30)
+DEFAULT_NEIGHBORS = 4
+DEFAULT_SCALE = 1.1
+
+DOMAIN = 'opencv'
+
+CLASSIFIER_GROUP_CONFIG = {
+    vol.Required(CONF_CLASSIFIER): vol.All(
+        cv.ensure_list,
+        [vol.Schema({
+            vol.Optional(CONF_COLOR, default=DEFAULT_COLOR):
+                vol.Schema((int, int, int)),
+            vol.Optional(CONF_FILE_PATH, default=DEFAULT_CLASSIFIER_PATH):
+                cv.isfile,
+            vol.Optional(CONF_NAME, default=DEFAULT_NAME):
+                cv.string,
+            vol.Optional(CONF_MIN_SIZE, default=DEFAULT_MIN_SIZE):
+                vol.Schema((int, int)),
+            vol.Optional(CONF_NEIGHBORS, default=DEFAULT_NEIGHBORS):
+                cv.positive_int,
+            vol.Optional(CONF_SCALE, default=DEFAULT_SCALE):
+                float
+        })]),
+    vol.Required(CONF_ENTITY_ID): cv.entity_ids,
+    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
+}
+CLASSIFIER_GROUP_SCHEMA = vol.Schema(CLASSIFIER_GROUP_CONFIG)
+
+CONFIG_SCHEMA = vol.Schema({
+    DOMAIN: vol.Schema({
+        vol.Required(CONF_GROUPS): vol.All(
+            cv.ensure_list,
+            [CLASSIFIER_GROUP_SCHEMA]
+        ),
+    })
+}, extra=vol.ALLOW_EXTRA)
+
+
+# NOTE:
+# pylint cannot find any of the members of cv2, using disable=no-member
+# to pass linting
+
+
+def cv_image_to_bytes(cv_image):
+    """Convert OpenCV image to bytes."""
+    import cv2
+
+    # pylint: disable=no-member
+    encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
+    # pylint: disable=no-member
+    success, data = cv2.imencode('.jpg', cv_image, encode_param)
+
+    if success:
+        return data.tobytes()
+
+    return None
+
+
+def cv_image_from_bytes(image):
+    """Convert image bytes to OpenCV image."""
+    import cv2
+    import numpy
+
+    # pylint: disable=no-member
+    return cv2.imdecode(numpy.asarray(bytearray(image)), cv2.IMREAD_UNCHANGED)
+
+
+def process_image(image, classifier_group, is_camera):
+    """Process the image given a classifier group."""
+    import cv2
+    import numpy
+
+    # pylint: disable=no-member
+    cv_image = cv2.imdecode(numpy.asarray(bytearray(image)),
+                            cv2.IMREAD_UNCHANGED)
+    group_matches = {}
+    for classifier_config in classifier_group:
+        classifier_path = classifier_config[CONF_FILE_PATH]
+        classifier_name = classifier_config[CONF_NAME]
+        color = classifier_config[CONF_COLOR]
+        scale = classifier_config[CONF_SCALE]
+        neighbors = classifier_config[CONF_NEIGHBORS]
+        min_size = classifier_config[CONF_MIN_SIZE]
+
+        # pylint: disable=no-member
+        classifier = cv2.CascadeClassifier(classifier_path)
+
+        detections = classifier.detectMultiScale(cv_image,
+                                                 scaleFactor=scale,
+                                                 minNeighbors=neighbors,
+                                                 minSize=min_size)
+        regions = []
+        # pylint: disable=invalid-name
+        for (x, y, w, h) in detections:
+            if is_camera:
+                # pylint: disable=no-member
+                cv2.rectangle(cv_image,
+                              (x, y),
+                              (x + w, y + h),
+                              color,
+                              2)
+            else:
+                regions.append((int(x), int(y), int(w), int(h)))
+        group_matches[classifier_name] = regions
+
+    if is_camera:
+        return cv_image_to_bytes(cv_image)
+    else:
+        return group_matches
+
+
+@asyncio.coroutine
+def async_setup(hass, config):
+    """Set up the OpenCV platform entities."""
+    _LOGGER.info('Async setup for opencv')
+    if not os.path.isfile(DEFAULT_CLASSIFIER_PATH):
+        _LOGGER.info('Downloading default classifier')
+        import urllib3
+
+        http = urllib3.PoolManager()
+        request = http.request('GET', CASCADE_URL, preload_content=False)
+
+        with open(DEFAULT_CLASSIFIER_PATH, 'wb') as out:
+            while True:
+                data = request.read(1028)
+                if not data:
+                    break
+                out.write(data)
+
+        request.release_conn()
+
+    for group in config[DOMAIN][CONF_GROUPS]:
+        discovery.load_platform(hass, 'image_processing', DOMAIN, group)
+
+    return True
diff --git a/requirements_all.txt b/requirements_all.txt
index 64f6500638ea371ffb25a9ab2632518ae0ed2207..2208fde8f182888c3f70ff13c894d5f4b4b6a9c6 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -408,12 +408,18 @@ netdisco==1.0.0rc3
 # homeassistant.components.sensor.neurio_energy
 neurio==0.3.1
 
+# homeassistant.components.opencv
+numpy==1.12.0
+
 # homeassistant.components.google
 oauth2client==4.0.0
 
 # homeassistant.components.climate.oem
 oemthermostat==1.1
 
+# homeassistant.components.opencv
+opencv-python==3.2.0.6
+
 # homeassistant.components.sensor.openevse
 openevsewifi==0.4
 
@@ -802,6 +808,9 @@ uber_rides==0.4.1
 # homeassistant.components.sensor.ups
 upsmychoice==1.0.2
 
+# homeassistant.components.opencv
+urllib3==1.21
+
 # homeassistant.components.camera.uvc
 uvcclient==0.10.0