Skip to content

Instantly share code, notes, and snippets.

@dzil123
Created May 4, 2019 04:03
Show Gist options
  • Save dzil123/3afdad8d12a02b7bb1c334b22d0e21fc to your computer and use it in GitHub Desktop.
Save dzil123/3afdad8d12a02b7bb1c334b22d0e21fc to your computer and use it in GitHub Desktop.
import cv2
import numpy
import math
from enum import Enum
class GripPipeline:
"""
An OpenCV pipeline generated by GRIP.
"""
def __init__(self):
"""initializes all values to presets or None if need to be set
"""
self.__blur_type = BlurType.Box_Blur
self.__blur_radius = 4.504504504504505
self.blur_output = None
self.__hsl_threshold_input = self.blur_output
self.__hsl_threshold_hue = [74.46043165467626, 88.31918505942276]
self.__hsl_threshold_saturation = [18.195477451822065, 66.6509592463525]
self.__hsl_threshold_luminance = [64.20863309352518, 155.4244482173175]
self.hsl_threshold_output = None
self.__cv_erode_src = self.hsl_threshold_output
self.__cv_erode_kernel = None
self.__cv_erode_anchor = (-1, -1)
self.__cv_erode_iterations = 7.0
self.__cv_erode_bordertype = cv2.BORDER_CONSTANT
self.__cv_erode_bordervalue = (-1)
self.cv_erode_output = None
self.__cv_dilate_src = self.cv_erode_output
self.__cv_dilate_kernel = None
self.__cv_dilate_anchor = (-1, -1)
self.__cv_dilate_iterations = 16.0
self.__cv_dilate_bordertype = cv2.BORDER_CONSTANT
self.__cv_dilate_bordervalue = (-1)
self.cv_dilate_output = None
self.__find_contours_input = self.cv_dilate_output
self.__find_contours_external_only = False
self.find_contours_output = None
self.__convex_hulls_contours = self.find_contours_output
self.convex_hulls_output = None
self.__filter_contours_contours = self.convex_hulls_output
self.__filter_contours_min_area = 0
self.__filter_contours_min_perimeter = 0
self.__filter_contours_min_width = 0
self.__filter_contours_max_width = 1000
self.__filter_contours_min_height = 0
self.__filter_contours_max_height = 1000
self.__filter_contours_solidity = [0, 100]
self.__filter_contours_max_vertices = 1000000
self.__filter_contours_min_vertices = 0
self.__filter_contours_min_ratio = 0
self.__filter_contours_max_ratio = 1000
self.filter_contours_output = None
def process(self, source0):
"""
Runs the pipeline and sets all outputs to new values.
"""
# Step Blur0:
self.__blur_input = source0
(self.blur_output) = self.__blur(self.__blur_input, self.__blur_type, self.__blur_radius)
# Step HSL_Threshold0:
self.__hsl_threshold_input = self.blur_output
(self.hsl_threshold_output) = self.__hsl_threshold(self.__hsl_threshold_input, self.__hsl_threshold_hue, self.__hsl_threshold_saturation, self.__hsl_threshold_luminance)
# Step CV_erode0:
self.__cv_erode_src = self.hsl_threshold_output
(self.cv_erode_output) = self.__cv_erode(self.__cv_erode_src, self.__cv_erode_kernel, self.__cv_erode_anchor, self.__cv_erode_iterations, self.__cv_erode_bordertype, self.__cv_erode_bordervalue)
# Step CV_dilate0:
self.__cv_dilate_src = self.cv_erode_output
(self.cv_dilate_output) = self.__cv_dilate(self.__cv_dilate_src, self.__cv_dilate_kernel, self.__cv_dilate_anchor, self.__cv_dilate_iterations, self.__cv_dilate_bordertype, self.__cv_dilate_bordervalue)
# Step Find_Contours0:
self.__find_contours_input = self.cv_dilate_output
(self.find_contours_output) = self.__find_contours(self.__find_contours_input, self.__find_contours_external_only)
# Step Convex_Hulls0:
self.__convex_hulls_contours = self.find_contours_output
(self.convex_hulls_output) = self.__convex_hulls(self.__convex_hulls_contours)
# Step Filter_Contours0:
self.__filter_contours_contours = self.convex_hulls_output
(self.filter_contours_output) = self.__filter_contours(self.__filter_contours_contours, self.__filter_contours_min_area, self.__filter_contours_min_perimeter, self.__filter_contours_min_width, self.__filter_contours_max_width, self.__filter_contours_min_height, self.__filter_contours_max_height, self.__filter_contours_solidity, self.__filter_contours_max_vertices, self.__filter_contours_min_vertices, self.__filter_contours_min_ratio, self.__filter_contours_max_ratio)
@staticmethod
def __blur(src, type, radius):
"""Softens an image using one of several filters.
Args:
src: The source mat (numpy.ndarray).
type: The blurType to perform represented as an int.
radius: The radius for the blur as a float.
Returns:
A numpy.ndarray that has been blurred.
"""
if(type is BlurType.Box_Blur):
ksize = int(2 * round(radius) + 1)
return cv2.blur(src, (ksize, ksize))
elif(type is BlurType.Gaussian_Blur):
ksize = int(6 * round(radius) + 1)
return cv2.GaussianBlur(src, (ksize, ksize), round(radius))
elif(type is BlurType.Median_Filter):
ksize = int(2 * round(radius) + 1)
return cv2.medianBlur(src, ksize)
else:
return cv2.bilateralFilter(src, -1, round(radius), round(radius))
@staticmethod
def __hsl_threshold(input, hue, sat, lum):
"""Segment an image based on hue, saturation, and luminance ranges.
Args:
input: A BGR numpy.ndarray.
hue: A list of two numbers the are the min and max hue.
sat: A list of two numbers the are the min and max saturation.
lum: A list of two numbers the are the min and max luminance.
Returns:
A black and white numpy.ndarray.
"""
out = cv2.cvtColor(input, cv2.COLOR_BGR2HLS)
return cv2.inRange(out, (hue[0], lum[0], sat[0]), (hue[1], lum[1], sat[1]))
@staticmethod
def __cv_erode(src, kernel, anchor, iterations, border_type, border_value):
"""Expands area of lower value in an image.
Args:
src: A numpy.ndarray.
kernel: The kernel for erosion. A numpy.ndarray.
iterations: the number of times to erode.
border_type: Opencv enum that represents a border type.
border_value: value to be used for a constant border.
Returns:
A numpy.ndarray after erosion.
"""
return cv2.erode(src, kernel, anchor, iterations = (int) (iterations +0.5),
borderType = border_type, borderValue = border_value)
@staticmethod
def __cv_dilate(src, kernel, anchor, iterations, border_type, border_value):
"""Expands area of higher value in an image.
Args:
src: A numpy.ndarray.
kernel: The kernel for dilation. A numpy.ndarray.
iterations: the number of times to dilate.
border_type: Opencv enum that represents a border type.
border_value: value to be used for a constant border.
Returns:
A numpy.ndarray after dilation.
"""
return cv2.dilate(src, kernel, anchor, iterations = (int) (iterations +0.5),
borderType = border_type, borderValue = border_value)
@staticmethod
def __find_contours(input, external_only):
"""Sets the values of pixels in a binary image to their distance to the nearest black pixel.
Args:
input: A numpy.ndarray.
external_only: A boolean. If true only external contours are found.
Return:
A list of numpy.ndarray where each one represents a contour.
"""
if(external_only):
mode = cv2.RETR_EXTERNAL
else:
mode = cv2.RETR_LIST
method = cv2.CHAIN_APPROX_SIMPLE
im2, contours, hierarchy =cv2.findContours(input, mode=mode, method=method)
return contours
@staticmethod
def __convex_hulls(input_contours):
"""Computes the convex hulls of contours.
Args:
input_contours: A list of numpy.ndarray that each represent a contour.
Returns:
A list of numpy.ndarray that each represent a contour.
"""
output = []
for contour in input_contours:
output.append(cv2.convexHull(contour))
return output
@staticmethod
def __filter_contours(input_contours, min_area, min_perimeter, min_width, max_width,
min_height, max_height, solidity, max_vertex_count, min_vertex_count,
min_ratio, max_ratio):
"""Filters out contours that do not meet certain criteria.
Args:
input_contours: Contours as a list of numpy.ndarray.
min_area: The minimum area of a contour that will be kept.
min_perimeter: The minimum perimeter of a contour that will be kept.
min_width: Minimum width of a contour.
max_width: MaxWidth maximum width.
min_height: Minimum height.
max_height: Maximimum height.
solidity: The minimum and maximum solidity of a contour.
min_vertex_count: Minimum vertex Count of the contours.
max_vertex_count: Maximum vertex Count.
min_ratio: Minimum ratio of width to height.
max_ratio: Maximum ratio of width to height.
Returns:
Contours as a list of numpy.ndarray.
"""
output = []
for contour in input_contours:
x,y,w,h = cv2.boundingRect(contour)
if (w < min_width or w > max_width):
continue
if (h < min_height or h > max_height):
continue
area = cv2.contourArea(contour)
if (area < min_area):
continue
if (cv2.arcLength(contour, True) < min_perimeter):
continue
hull = cv2.convexHull(contour)
solid = 100 * area / cv2.contourArea(hull)
if (solid < solidity[0] or solid > solidity[1]):
continue
if (len(contour) < min_vertex_count or len(contour) > max_vertex_count):
continue
ratio = (float)(w) / h
if (ratio < min_ratio or ratio > max_ratio):
continue
output.append(contour)
return output
BlurType = Enum('BlurType', 'Box_Blur Gaussian_Blur Median_Filter Bilateral_Filter')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment