import cv2
|
import numpy as np
|
import pandas as pd
|
import math
|
from screeninfo import get_monitors
|
|
def detect_a_card(img, thresh_val=80, blur_radius=None, dilate_radius=None, min_hyst=80, max_hyst=200,
|
min_line_length=None, max_line_gap=None, debug=False):
|
dim_img = (len(img[0]), len(img)) # (width, height)
|
# Intermediate variables
|
|
# Default values
|
if blur_radius is None:
|
blur_radius = math.floor(min(dim_img) / 100 + 0.5) // 2 * 2 + 1 # Rounded to the nearest odd
|
if dilate_radius is None:
|
dilate_radius = math.floor(min(dim_img) / 100)
|
if min_line_length is None:
|
min_line_length = min(dim_img) / 10
|
if max_line_gap is None:
|
max_line_gap = min(dim_img) / 10
|
|
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
# Median blur better removes background textures than Gaussian blur
|
img_blur = cv2.medianBlur(img_gray, blur_radius)
|
# Truncate the bright area while detecting the border
|
_, img_thresh = cv2.threshold(img_blur, thresh_val, 255, cv2.THRESH_TRUNC)
|
|
# Dilate the image to emphasize thick borders around the card
|
kernel_dilate = np.ones((dilate_radius, dilate_radius), np.uint8)
|
img_dilate = cv2.dilate(img_thresh, kernel_dilate, iterations=1)
|
|
# Canny edge - low minimum hysteresis to detect glowed area,
|
# and high maximum hysteresis to compensate for high false positives.
|
img_canny = cv2.Canny(img_dilate, min_hyst, max_hyst)
|
|
# Apply Hough transformation to detect the edges
|
'''
|
detected_lines = cv2.HoughLines(img_canny, 1, np.pi / 180, 200)
|
if detected_lines is not None:
|
img_hough = cv2.cvtColor(img_dilate.copy(), cv2.COLOR_GRAY2BGR)
|
for line in detected_lines:
|
rho, theta = line[0]
|
a = np.cos(theta)
|
b = np.sin(theta)
|
x0 = a * rho
|
y0 = b * rho
|
x1 = int(x0 + 1000 * (-b))
|
y1 = int(y0 + 1000 * (a))
|
x2 = int(x0 - 1000 * (-b))
|
y2 = int(y0 - 1000 * (a))
|
cv2.line(img_hough, (x1, y1), (x2, y2), (0, 0, 255), 2)
|
else:
|
print('Hough couldn\'t find any lines')
|
return False
|
'''
|
detected_lines = cv2.HoughLinesP(img_canny, 1, np.pi / 180, threshold=60,
|
minLineLength=min_line_length,
|
maxLineGap=max_line_gap)
|
card_found = detected_lines is not None
|
|
if card_found:
|
if debug:
|
img_hough = cv2.cvtColor(img_dilate.copy(), cv2.COLOR_GRAY2BGR)
|
for line in detected_lines:
|
x1, y1, x2, y2 = line[0]
|
cv2.line(img_hough, (x1, y1), (x2, y2), (0, 0, 255), 3)
|
elif not debug:
|
print('Hough couldn\'t find any lines')
|
|
# Debug: display intermediate results from various steps
|
if debug:
|
'''
|
cv2.imshow('Original', img)
|
cv2.imshow('Thresholded', img_thresh)
|
cv2.imshow('Dilated', img_dilate)
|
cv2.imshow('Canny Edge', img_canny)
|
if card_found:
|
cv2.imshow('Detected Lines', img_hough)
|
'''
|
img_blank = np.zeros((len(img), len(img[0]), 3), np.uint8)
|
img_thresh = cv2.cvtColor(img_thresh, cv2.COLOR_GRAY2BGR)
|
#img_dilate = cv2.cvtColor(img_dilate, cv2.COLOR_GRAY2BGR)
|
img_canny = cv2.cvtColor(img_canny, cv2.COLOR_GRAY2BGR)
|
if not card_found:
|
img_hough = img_blank
|
|
# Append all images together
|
img_row_1 = np.concatenate((img, img_thresh), axis=1)
|
img_row_2 = np.concatenate((img_canny, img_hough), axis=1)
|
img_result = np.concatenate((img_row_1, img_row_2), axis=0)
|
|
# Resize the final image to fit into the main monitor's resolution
|
screen_size = get_monitors()[0]
|
resize_ratio = max(len(img_result[0]) / screen_size.width, len(img_result) / screen_size.height, 1)
|
img_result = cv2.resize(img_result, (int(len(img_result[0]) // resize_ratio),
|
int(len(img_result) // resize_ratio)))
|
cv2.imshow('Result', img_result)
|
cv2.waitKey(0)
|
|
# TODO: output meaningful data
|
return card_found
|
|
|
def main():
|
img_test = cv2.imread('data/tilted_card_2.jpg')
|
card_found = detect_a_card(img_test,
|
dilate_radius=2,
|
min_hyst=30,
|
max_hyst=80,
|
min_line_length=10,
|
max_line_gap=50,
|
debug=True)
|
if card_found:
|
return
|
|
for dilate_radius in range(1, 6):
|
for min_hyst in range(50, 91, 10):
|
for max_hyst in range(180, 119, -20):
|
print('dilate_radius=%d, min_hyst=%d, max_hyst=%d: ' % (dilate_radius, min_hyst, max_hyst),
|
end='', flush=True)
|
card_found = detect_a_card(img_test, dilate_radius=dilate_radius,
|
min_hyst=min_hyst, max_hyst=max_hyst, debug=True)
|
if card_found:
|
print('Card found')
|
else:
|
print('Not found')
|
|
if __name__ == '__main__':
|
main()
|