Skip to content
Snippets Groups Projects
Commit 61ca9d8a authored by Rui Jie Li's avatar Rui Jie Li
Browse files

separated the files in black white, edges, and color detection

parent b372bf3f
No related branches found
No related tags found
No related merge requests found
import cv2 as cv
import numpy as np
def debug(image):
cv.imshow("debug", image)
cv.waitKey(0)
def debug_contours(contours, image):
mask = np.zeros((image.shape[0], image.shape[1]))
cv.drawContours(mask, contours, -1, (255), 1)
cv.imshow("debug", mask)
cv.waitKey(0)
class BlackWhiteTransform:
# For iterations with kmeans
def __init__(self, percentage_led_area = 0.01, nb_color = 4, max_iter = 1, accuracy = 1):
self.percetage_led_area = percentage_led_area
self.nb_color = nb_color
self.max_iter = max_iter
self.accuracy = accuracy
def convert_to_black_white(self, image, already_grayscale = False):
# Transform the image into grascale, then use kmeans to group the different shades of
# Grey
min_area = image.shape[0] * image.shape[1] * self.percetage_led_area
grey = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
shape = grey.shape
grey = grey.reshape(grey.shape[0] * grey.shape[1], 1)
grey = np.float32(grey)
# Criteria is the number of iterations
# Format : (type, max_iteration, accuracy)
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER,\
self.max_iter, self.accuracy)
ret,label,center=cv.kmeans(grey,self.nb_color,None,\
criteria,1,cv.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
kmeans = res.reshape(shape)
black_white = cv.threshold(kmeans, np.average(grey), 255, cv.THRESH_BINARY)[1]
return black_white
\ No newline at end of file
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from math import pi as PI
# for debugging purposes
gsize = None
ginertia = None
ls = []
class Colors:
RED = "RED"
BLUE = "BLUE"
GREY = "GREY"
def debug(image):
cv.imshow("debug", image)
cv.waitKey(0)
def debug_contours(contours, image):
mask = np.zeros((image.shape[0], image.shape[1]))
cv.drawContours(mask, contours, -1, (255), 1)
cv.imshow("debug", mask)
cv.waitKey(0)
class EdgeDetector:
# threshold for circularity (circle = 1); TBD
# circularity = 4 * PI * AREA / (PERIMETER ^ 2)
# TODO: change this according to the size of the image
# in general, decrease this more bigger images
CIRCLE_THRESHOLD = 0.4 # based on test values of 0.72, 0.8, 0.68
# threshold for concavity; the formula is area_of_blob / area_convexity_hull, TBD
CONVEX_THRESHOLD = 0.85 # based on values around 0.95 and 0.98
# threshold for how elongated it is (called intertia in opencv), TBD (circle = 1)
# TODO : change this according to the size of the image
# in general, inertia is bigger
MIN_INERTIA = 3 # 1.1 1.3 pour les petits images
MAX_INERTIA = 5.5
MIN_AREA = None # to be initialized to 0.02 * area of image
# for iterations with kmeans
NB_COLOR = 4 # allows for : black, white, blue, red
MAX_ITER = 1 # maximum of 1 iterations
ACCURACY = 1 # not sure what this does ...
def __init__(self):
pass
def calculate_inertia(self, image, shape) -> int:
pass
# finds the contours of the LEDs and returns them
def find_contours(self, image, area = False, distance = False, already_grayscale = False):
# transform the image into black and white
# first go to grayscale then goto black white with a threshold
EdgeDetector.MIN_AREA = image.shape[0] * image.shape[1] * 0.01
grey = image
if not already_grayscale:
grey = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
shape = grey.shape
debug(grey)
# O(N) --> loop over every pixel
grey = grey.reshape(grey.shape[0] * grey.shape[1], 1)
# O(N) --> loop over every pixel
grey = np.float32(grey)
# criteria is the number of iterations
# format : (type, max_iteration, accuracy)
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER,\
EdgeDetector.MAX_ITER, EdgeDetector.ACCURACY)
ret,label,center=cv.kmeans(grey,EdgeDetector.NB_COLOR,None,\
criteria,1,cv.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
kmeans = res.reshape(shape)
# O(N) --> iterate over every pixels
black_white = cv.threshold(kmeans, np.average(grey), 255, cv.THRESH_BINARY)[1]
contours, hierarchy = cv.findContours(black_white, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# note : other versions of OpenCV will require image, contours, hierarchy
# now for the characteristics of the contours
retained_contours = []
for contour in contours:
# TODO : something wrong here, probably with area
area = cv.contourArea(contour)
if area >= EdgeDetector.MIN_AREA:
# circularity < threshold : is the contour NOT circular?
circularity = 4*PI*area / (cv.arcLength(contour, True) * cv.arcLength(contour, True))
# convexity > threashold : we want the shape to be convex
convexity = area / cv.contourArea(cv.convexHull(contour))
# opencv docs aren't very helpful on this but looks like inertia is aspect ratio
(x,y),(width,height),theta = cv.minAreaRect(contour)
# this is basically aspect ratio
inertia = width / height
if inertia < 1:
inertia = 1/inertia
# note : the angle is pretty much useless
print("calculated circularity : ", circularity)
print("threshold circularity : ", EdgeDetector.CIRCLE_THRESHOLD)
print()
print("calculated converxity : ", convexity)
print("threshold converxity : ", EdgeDetector.CONVEX_THRESHOLD)
print()
print("calculated inertia : ", inertia)
print("threshold inertia : ", EdgeDetector.MIN_INERTIA, EdgeDetector.MAX_INERTIA)
print()
print("image area : ", image.shape[0] * image.shape[1])
print("calculated area : ", area)
print()
print("detected angle : ", theta)
print("displaying contour, press any key to continue ... ")
debug_contours([contour], image)
if circularity > EdgeDetector.CIRCLE_THRESHOLD and \
convexity > EdgeDetector.CONVEX_THRESHOLD and \
inertia > EdgeDetector.MIN_INERTIA and \
inertia < EdgeDetector.MAX_INERTIA:
retained_contours.append(contour)
print("retained !")
else:
print("rejected !")
print("----------------------------------")
# use HSV instead
# 1. color = red or blue
# use the other 2 to see if its gray
return retained_contours
if __name__ == '__main__':
import os
image = cv.imread("test9.PNG")
gbd = EdgeDetector()
print(len(gbd.find_contours(image)))
\ No newline at end of file
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from math import pi as PI
from black_and_white import BlackWhiteTransform
import logging
logger = logging.getLogger(__name__)
# For debugging purposes
gsize = None
ginertia = None
ls = []
class Colors:
RED = "RED"
BLUE = "BLUE"
GREY = "GREY"
def debug(image):
cv.imshow("debug", image)
cv.waitKey(0)
def debug_contours(contours, image):
mask = np.zeros((image.shape[0], image.shape[1]))
cv.drawContours(mask, contours, -1, (255), 1)
cv.imshow("debug", mask)
cv.waitKey(0)
class EdgeDetector:
# Threshold for circularity (circle = 1); to be determined
# Circularity = 4 * PI * AREA / (PERIMETER ^ 2)
# In general, decrease this more bigger images
# Based on test values of 0.72, 0.8, 0.68 seems like 0.4 is a good value
# Threshold for concavity; the formula is area_of_blob / area_convexity_hull
# Based on values around 0.95 and 0.98
def __init__(self, circle_threshold = 0.4, convex_threshold = 0.85, min_inertia = 3, max_intertia = 5.5, percentage_led_area = 0.01):
self.circle_threshold = circle_threshold
self.convex_threshold = convex_threshold
self.min_inertia = min_inertia
self.max_inertia = max_intertia
self.percentage_led_area = percentage_led_area
# Finds the contours of the LEDs and returns them
def get_edges(self, black_white_image, area = False, distance = False, already_grayscale = False):
contours, hierarchy = cv.findContours(black_white_image, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
min_area = black_white_image.shape[0] * black_white_image.shape[1] * self.percentage_led_area
# Note : other versions of OpenCV will require image, contours, hierarchy
# Now for the characteristics of the contours
retained_contours = []
for contour in contours:
# TODO : something wrong here, probably with area
area = cv.contourArea(contour)
if area >= min_area:
# Circularity < threshold : is the contour NOT circular?
circularity = 4*PI*area / (cv.arcLength(contour, True) * cv.arcLength(contour, True))
# Convexity > threashold : we want the shape to be convex
convexity = area / cv.contourArea(cv.convexHull(contour))
# Opencv docs aren't very helpful on this but looks like inertia is aspect ratio
(x,y),(width,height),theta = cv.minAreaRect(contour)
# This is basically aspect ratio
inertia = width / height
if inertia < 1:
inertia = 1/inertia
# Note : the angle is pretty much useless
logger.debug("calculated circularity : ", circularity)
logger.debug("threshold circularity : ", self.circle_threshold)
logger.debug("\n")
logger.debug("calculated converxity : ", convexity)
logger.debug("threshold converxity : ", self.convex_threshold)
logger.debug("\n")
logger.debug("calculated inertia : ", inertia)
logger.debug("threshold inertia : ", self.min_inertia, self.max_inertia)
logger.debug("\n")
logger.debug("image area : ", black_white_image.shape[0] * black_white_image.shape[1])
logger.debug("calculated area : ", area)
logger.debug("\n")
logger.debug("detected angle : ", theta)
logger.debug("displaying contour, press any key to continue ... ")
debug_contours([contour], black_white_image)
# Make it able to switch on and off (ex. do not consider circularity)
if circularity > self.circle_threshold and \
convexity > self.convex_threshold and \
inertia > self.min_inertia and \
inertia < self.max_inertia:
retained_contours.append(contour)
logger.debug("retained !")
else:
logger.debug("rejected !")
logger.debug("----------------------------------")
# Use HSV instead
# 1. color = red or blue
# Use the other 2 to see if its gray
return retained_contours
if __name__ == '__main__':
import os
logger.setLevel("DEBUG") # Debug, info, warning, erreur
image = cv.imread("test11.PNG")
gbd = EdgeDetector()
logger.debug(len(gbd.find_contours(image)))
\ No newline at end of file
import cv2 as cv
import numpy as np
import edgeDetector
from edge_detector import EdgeDetector
from black_and_white import BlackWhiteTransform
import logging
logger = logging.getLogger(__name__)
def debug(image):
cv.imshow("debug", image)
......@@ -8,15 +12,12 @@ def debug(image):
class HSVColorDetector:
RED = 180
BLUE = 45
MIN_GRAY = 60 # not enough testing, but around 100 for normal, 40 for gray
def __init__(self, red = 180, blue = 45, min_gray = 60):
self.red = red
self.blue = blue
self.min_gray = min_gray
def __init__(self):
pass
def detect_color(self, image, is_hsv = False):
def detect_color(self, image, contours, shape, is_hsv = False):
# WARNING: greyscale is NOT the same as the value in HSV
# the formula for BGR to grayscale is
# Gray = 0.299*Red + 0.587*Green + 0.114*Blue
......@@ -32,10 +33,7 @@ class HSVColorDetector:
# note : do not use sine or cosine for this, its like 10x slower than
# just doing adding or substracting
hue = np.abs(180 - hue) # due to angles looping back
edge = edgeDetector.EdgeDetector()
contours = edge.find_contours(greyscale, already_grayscale=True)
mask = np.zeros(greyscale.shape)
mask = np.zeros(shape)
mask = cv.drawContours(mask, contours, -1, (255), 1)
hue_mask = np.ma.array(data=hue, mask=mask)
sat_mask = np.ma.array(data=saturation, mask=mask)
......@@ -44,19 +42,24 @@ class HSVColorDetector:
satvalue = sat_mask.mean()
print(huevalue)
print(satvalue)
if (abs(huevalue - HSVColorDetector.BLUE) < abs(huevalue - HSVColorDetector.RED)):
if (abs(huevalue - self.blue) < abs(huevalue - self.red)):
print("this is probably blue")
else:
print("this is probably red")
if satvalue < HSVColorDetector.MIN_GRAY:
if satvalue < self.min_gray:
print("this is probably gray")
else:
print("this is probably not gray")
if __name__ == '__main__':
image = cv.imread("test8.PNG")
logger.setLevel("DEBUG")
image = cv.imread("test11.PNG")
bwt = BlackWhiteTransform()
black_white_image = bwt.convert_to_black_white(image)
ed = EdgeDetector()
edges = ed.get_edges(black_white_image)
hsv = HSVColorDetector()
hsv.detect_color(image)
hsv.detect_color(image, edges, black_white_image.shape)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment