Source code for ovl.detectors.threshold_detector
from functools import reduce
from typing import List
import cv2
import numpy as np
from .detector import Detector
from ..thresholds.threshold import Threshold
from ..partials.filter_applier import filter_applier
[docs]class ThresholdDetector(Detector):
"""
ThresholdDetector is a detector used to find contours in a binary image.
The binary image is created using a Threshold object.
Examples of this are binary threshold, color, multicolor thresholds.
For more information on binary thresholding and color thresholding refer to
the documentation of the relevant Threshold object and:
Binary Thresholding - https://docs.opencv.org/3.4/d7/d4d/tutorial_py_thresholding.html
Color Thresholding - https://docs.opencv.org/master/da/d97/tutorial_threshold_inRange.html
Threshold also allows the usage of morphological functions
which are functions that are applied on the binary image created by the threshold.
.. note::
Morphological functions are functions decorated with @image_filter that act on binary images.
Examples for morphological functions are erosion or dilation.
For more information on morphological functions:
https://docs.opencv.org/3.4/d9/d61/tutorial_py_morphological_ops.html
"""
def __init__(self, threshold: Threshold, morphological_functions):
"""
:param threshold: a Threshold object used to create binary images
:param morphological_functions: a list of morphological functions
"""
self.morphological_functions = morphological_functions
self.threshold = threshold
[docs] def apply_threshold(self, image: np.ndarray, threshold=None) -> np.ndarray:
"""
Gets a mask (binary image) for a given image and Threshold object
(uses self.threshold if given threshold was none)
:param image: the numpy array of the image
:param threshold: the Threshold object used to create the binary mask
:return: the binary mask
"""
threshold = threshold or self.threshold
return threshold.convert(image)
[docs] def find_contours_in_mask(self, mask: np.ndarray, return_hierarchy=False, apply_morphs=True
) -> List[np.ndarray]:
"""
This function is used to find and extract contours (object shapes) from a binary image
(image passed through a threshold)
:param mask: binary image (mask), a numpy array
:param return_hierarchy: if the hierarchy should be returned
:param apply_morphs: if the morphological functions should be applied.
:return: the list of contours
"""
mask = self.apply_morphological_functions(mask) if apply_morphs else mask
result = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if len(result) == 3:
_, contours, hierarchy = result
elif len(result) == 2:
contours, hierarchy = result
else:
raise ValueError("Invalid output from cv2.findContours, check that your cv2 (OpenCV) version is supported")
return (contours, hierarchy) if return_hierarchy else contours
[docs] def detect(self, image: np.ndarray, return_hierarchy=False, *args, **kwargs) -> List[np.ndarray]:
"""
Gets a list of all the contours within the threshold that was given
:param image: image from which to get the contours
:param return_hierarchy: if the hierarchy should be returned
:return: list of all contours matching the range of hsv colours
"""
image_mask = self.apply_threshold(image)
return self.find_contours_in_mask(image_mask, return_hierarchy=return_hierarchy)
[docs] def apply_morphological_functions(self, mask, morphological_functions=None):
"""
Applies all morphological functions on the mask (binary images) created using the threshold,
Morphological functions are functions that are applied
to binary images to alter the shape of "detected" regions
:param mask: the mask on which the functions should be applied
:param morphological_functions: list of morphological_functions to be
applied instead of self.morphological_functions
:return: the applied mask
"""
if type(self.morphological_functions) not in (tuple, list, set):
return mask
morphological_functions = morphological_functions or self.morphological_functions
return reduce(filter_applier, morphological_functions, mask)