mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 01:07:10 +00:00
Remove OpenCV integration (#113455)
This commit is contained in:
parent
7bcfa94b12
commit
e0b1531afa
@ -926,7 +926,6 @@ omit =
|
|||||||
homeassistant/components/onvif/sensor.py
|
homeassistant/components/onvif/sensor.py
|
||||||
homeassistant/components/onvif/util.py
|
homeassistant/components/onvif/util.py
|
||||||
homeassistant/components/open_meteo/weather.py
|
homeassistant/components/open_meteo/weather.py
|
||||||
homeassistant/components/opencv/*
|
|
||||||
homeassistant/components/openevse/sensor.py
|
homeassistant/components/openevse/sensor.py
|
||||||
homeassistant/components/openexchangerates/__init__.py
|
homeassistant/components/openexchangerates/__init__.py
|
||||||
homeassistant/components/openexchangerates/coordinator.py
|
homeassistant/components/openexchangerates/coordinator.py
|
||||||
|
@ -1 +0,0 @@
|
|||||||
"""The opencv component."""
|
|
@ -1,196 +0,0 @@
|
|||||||
"""Support for OpenCV classification on images."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
import requests
|
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.image_processing import (
|
|
||||||
PLATFORM_SCHEMA,
|
|
||||||
ImageProcessingEntity,
|
|
||||||
)
|
|
||||||
from homeassistant.const import CONF_ENTITY_ID, CONF_NAME, CONF_SOURCE
|
|
||||||
from homeassistant.core import HomeAssistant, split_entity_id
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Verify that the OpenCV python package is pre-installed
|
|
||||||
import cv2
|
|
||||||
|
|
||||||
CV2_IMPORTED = True
|
|
||||||
except ImportError:
|
|
||||||
CV2_IMPORTED = False
|
|
||||||
|
|
||||||
|
|
||||||
_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): {
|
|
||||||
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(
|
|
||||||
vol.All(vol.Coerce(tuple), vol.ExactSequence([int, int]))
|
|
||||||
),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _create_processor_from_config(hass, camera_entity, config):
|
|
||||||
"""Create an OpenCV processor from configuration."""
|
|
||||||
classifier_config = config.get(CONF_CLASSIFIER)
|
|
||||||
name = f"{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, timeout=10)
|
|
||||||
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: HomeAssistant,
|
|
||||||
config: ConfigType,
|
|
||||||
add_entities: AddEntitiesCallback,
|
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
|
||||||
) -> None:
|
|
||||||
"""Set up the OpenCV image processing platform."""
|
|
||||||
if not CV2_IMPORTED:
|
|
||||||
_LOGGER.error(
|
|
||||||
"No OpenCV library found! Install or compile for your system "
|
|
||||||
"following instructions here: https://opencv.org/?s=releases"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
if CONF_CLASSIFIER not in config:
|
|
||||||
dest_path = hass.config.path(DEFAULT_CLASSIFIER_PATH)
|
|
||||||
_get_default_classifier(dest_path)
|
|
||||||
config[CONF_CLASSIFIER] = {"Face": dest_path}
|
|
||||||
|
|
||||||
add_entities(
|
|
||||||
OpenCVImageProcessor(
|
|
||||||
hass,
|
|
||||||
camera[CONF_ENTITY_ID],
|
|
||||||
camera.get(CONF_NAME),
|
|
||||||
config[CONF_CLASSIFIER],
|
|
||||||
)
|
|
||||||
for camera in config[CONF_SOURCE]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
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 = f"OpenCV {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 extra_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."""
|
|
||||||
cv_image = cv2.imdecode(np.asarray(bytearray(image)), cv2.IMREAD_UNCHANGED)
|
|
||||||
|
|
||||||
matches = {}
|
|
||||||
total_matches = 0
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
cascade = cv2.CascadeClassifier(path)
|
|
||||||
|
|
||||||
detections = cascade.detectMultiScale(
|
|
||||||
cv_image, scaleFactor=scale, minNeighbors=neighbors, minSize=min_size
|
|
||||||
)
|
|
||||||
regions = []
|
|
||||||
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
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"domain": "opencv",
|
|
||||||
"name": "OpenCV",
|
|
||||||
"codeowners": [],
|
|
||||||
"documentation": "https://www.home-assistant.io/integrations/opencv",
|
|
||||||
"iot_class": "local_push",
|
|
||||||
"requirements": ["numpy==1.26.0", "opencv-python-headless==4.6.0.66"]
|
|
||||||
}
|
|
@ -4183,12 +4183,6 @@
|
|||||||
"config_flow": false,
|
"config_flow": false,
|
||||||
"iot_class": "cloud_push"
|
"iot_class": "cloud_push"
|
||||||
},
|
},
|
||||||
"opencv": {
|
|
||||||
"name": "OpenCV",
|
|
||||||
"integration_type": "hub",
|
|
||||||
"config_flow": false,
|
|
||||||
"iot_class": "local_push"
|
|
||||||
},
|
|
||||||
"openerz": {
|
"openerz": {
|
||||||
"name": "Open ERZ",
|
"name": "Open ERZ",
|
||||||
"integration_type": "hub",
|
"integration_type": "hub",
|
||||||
|
@ -1407,7 +1407,6 @@ numato-gpio==0.12.0
|
|||||||
|
|
||||||
# homeassistant.components.compensation
|
# homeassistant.components.compensation
|
||||||
# homeassistant.components.iqvia
|
# homeassistant.components.iqvia
|
||||||
# homeassistant.components.opencv
|
|
||||||
# homeassistant.components.stream
|
# homeassistant.components.stream
|
||||||
# homeassistant.components.tensorflow
|
# homeassistant.components.tensorflow
|
||||||
# homeassistant.components.trend
|
# homeassistant.components.trend
|
||||||
@ -1449,9 +1448,6 @@ open-meteo==0.3.1
|
|||||||
# homeassistant.components.openai_conversation
|
# homeassistant.components.openai_conversation
|
||||||
openai==1.3.8
|
openai==1.3.8
|
||||||
|
|
||||||
# homeassistant.components.opencv
|
|
||||||
# opencv-python-headless==4.6.0.66
|
|
||||||
|
|
||||||
# homeassistant.components.openerz
|
# homeassistant.components.openerz
|
||||||
openerz-api==0.3.0
|
openerz-api==0.3.0
|
||||||
|
|
||||||
|
@ -1125,7 +1125,6 @@ numato-gpio==0.12.0
|
|||||||
|
|
||||||
# homeassistant.components.compensation
|
# homeassistant.components.compensation
|
||||||
# homeassistant.components.iqvia
|
# homeassistant.components.iqvia
|
||||||
# homeassistant.components.opencv
|
|
||||||
# homeassistant.components.stream
|
# homeassistant.components.stream
|
||||||
# homeassistant.components.tensorflow
|
# homeassistant.components.tensorflow
|
||||||
# homeassistant.components.trend
|
# homeassistant.components.trend
|
||||||
|
@ -29,7 +29,6 @@ COMMENT_REQUIREMENTS = (
|
|||||||
"decora-wifi",
|
"decora-wifi",
|
||||||
"evdev",
|
"evdev",
|
||||||
"face-recognition",
|
"face-recognition",
|
||||||
"opencv-python-headless",
|
|
||||||
"pybluez",
|
"pybluez",
|
||||||
"pycocotools",
|
"pycocotools",
|
||||||
"pycups",
|
"pycups",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user