2018-03-04 21:23:11 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# vim:fenc=utf-8
|
|
|
|
#
|
|
|
|
# Copyright © 2018 pavle <pavle.portic@tilda.center>
|
|
|
|
#
|
|
|
|
# Distributed under terms of the MIT license.
|
|
|
|
|
2018-03-05 12:05:22 +01:00
|
|
|
|
|
|
|
# cpy = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
|
|
|
|
# cv.drawContours(cpy, [np.int0(rect)], 0, (0, 0, 255), 2)
|
|
|
|
# cv.imshow('arst', cpy)
|
|
|
|
# cv.waitKey()
|
|
|
|
|
2018-03-05 00:31:38 +01:00
|
|
|
import copy
|
2018-03-04 21:23:11 +01:00
|
|
|
import cv2 as cv
|
2018-03-05 16:33:18 +01:00
|
|
|
import itertools as it
|
2018-03-04 21:23:11 +01:00
|
|
|
import numpy as np
|
|
|
|
|
2018-03-15 21:25:14 +01:00
|
|
|
|
2018-03-04 21:23:11 +01:00
|
|
|
def main():
|
2018-03-06 12:06:10 +01:00
|
|
|
# for k in range(10, 11):
|
2018-03-05 16:33:18 +01:00
|
|
|
# filename = 'set/A' + str(k) + '.png'
|
2018-03-15 21:25:14 +01:00
|
|
|
# filename = raw_input()
|
|
|
|
# src = cv.imread(filename)
|
|
|
|
# wrapper(src)
|
2018-03-04 21:23:11 +01:00
|
|
|
|
2018-03-15 21:25:14 +01:00
|
|
|
# i = 9
|
|
|
|
for i in range(2, 11):
|
|
|
|
filename = 'private/set/B' + str(i) + '.png'
|
|
|
|
src = cv.imread(filename)
|
|
|
|
wrapper(src)
|
|
|
|
cv.waitKey()
|
|
|
|
print_solution(i)
|
2018-03-06 15:58:34 +01:00
|
|
|
|
2018-03-04 21:23:11 +01:00
|
|
|
|
2018-03-06 12:06:10 +01:00
|
|
|
def wrapper(src):
|
2018-03-06 15:58:34 +01:00
|
|
|
src = filter_pink(src)
|
2018-03-06 12:06:10 +01:00
|
|
|
box = find_resistor(src)
|
2018-03-05 16:33:18 +01:00
|
|
|
if box is None:
|
|
|
|
print '221G'
|
|
|
|
return
|
2018-03-05 00:31:38 +01:00
|
|
|
|
2018-03-05 16:33:18 +01:00
|
|
|
src = crop_resistor(src, box)
|
|
|
|
if len(src) is 0:
|
|
|
|
print '221G'
|
|
|
|
return
|
2018-03-05 00:31:38 +01:00
|
|
|
|
2018-03-05 16:33:18 +01:00
|
|
|
simple = simplify_image(src)
|
|
|
|
code = find_bands(simple)
|
2018-03-06 12:06:10 +01:00
|
|
|
if code is '':
|
|
|
|
print '221G'
|
|
|
|
return
|
|
|
|
|
2018-03-05 16:33:18 +01:00
|
|
|
if code[0] is 'G':
|
|
|
|
code = code[::-1]
|
2018-03-05 00:31:38 +01:00
|
|
|
|
2018-03-06 12:06:10 +01:00
|
|
|
code = code.replace('G', '') + '222'
|
2018-03-05 16:33:18 +01:00
|
|
|
code = code[:3] + 'G'
|
|
|
|
print code
|
2018-03-04 21:23:11 +01:00
|
|
|
|
2018-03-05 00:31:38 +01:00
|
|
|
|
2018-03-06 15:58:34 +01:00
|
|
|
def print_solution(i):
|
2018-03-15 21:25:14 +01:00
|
|
|
with open('private/outputs/B' + str(i) + '.txt', 'r') as f:
|
2018-03-06 15:58:34 +01:00
|
|
|
print f.read()
|
|
|
|
print
|
|
|
|
|
|
|
|
|
|
|
|
def filter_pink(img):
|
|
|
|
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
|
|
|
|
low = np.array([165, 0, 160])
|
|
|
|
high = np.array([180, 170, 255])
|
|
|
|
mask = cv.inRange(hsv, low, high)
|
|
|
|
mask = cv.bitwise_not(mask)
|
|
|
|
return cv.bitwise_and(img, img, mask=mask)
|
|
|
|
|
|
|
|
|
2018-03-05 00:31:38 +01:00
|
|
|
def rotate_pt(box, off, phi):
|
|
|
|
sin = np.sin(phi)
|
|
|
|
cos = np.cos(phi)
|
|
|
|
for i in range(len(box)):
|
|
|
|
pt = list(box[i])
|
|
|
|
pt[0] -= off[0]
|
|
|
|
pt[1] -= off[1]
|
|
|
|
pt = [pt[0]*cos - pt[1]*sin, pt[1]*cos + pt[0]*sin]
|
|
|
|
pt[0] += off[0]
|
|
|
|
pt[1] += off[1]
|
|
|
|
box[i] = pt
|
|
|
|
|
|
|
|
|
|
|
|
def sort_coords(box):
|
|
|
|
for i in range(0, len(box)):
|
|
|
|
for j in range(i + 1, len(box)):
|
|
|
|
if box[j][0] < box [i][0] or (box[j][0] == box[i][0] and box[j][1] < box[i][1]):
|
|
|
|
box[i], box[j] = list(box[j]), list(box[i])
|
|
|
|
|
|
|
|
return box
|
2018-03-04 21:23:11 +01:00
|
|
|
|
|
|
|
|
2018-03-05 01:47:24 +01:00
|
|
|
def contrast(img, clipLimit):
|
|
|
|
img = cv.cvtColor(img, cv.COLOR_BGR2LAB)
|
|
|
|
l, a, b = cv.split(img)
|
|
|
|
clahe = cv.createCLAHE(clipLimit, tileGridSize=(8,8))
|
|
|
|
cl = clahe.apply(l)
|
|
|
|
img = cv.merge((cl, a, b))
|
|
|
|
return cv.cvtColor(img, cv.COLOR_LAB2BGR)
|
|
|
|
|
|
|
|
|
2018-03-04 21:23:11 +01:00
|
|
|
def find_resistor(img):
|
2018-03-06 15:58:34 +01:00
|
|
|
src = img.copy()
|
2018-03-05 00:31:38 +01:00
|
|
|
img = contrast(img, 1.6)
|
2018-03-04 21:23:11 +01:00
|
|
|
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
|
2018-03-05 00:31:38 +01:00
|
|
|
img = cv.medianBlur(img, 21)
|
|
|
|
img = cv.Canny(img, 60, 100)
|
2018-03-06 15:58:34 +01:00
|
|
|
|
2018-03-04 21:23:11 +01:00
|
|
|
kernel = np.ones((9, 9), np.uint8)
|
|
|
|
img = cv.dilate(img, kernel, 2)
|
|
|
|
img = cv.erode(img, kernel, 2)
|
2018-03-05 16:33:18 +01:00
|
|
|
img, contours, _ = cv.findContours(img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
|
2018-03-05 12:05:22 +01:00
|
|
|
rect = None
|
2018-03-04 21:23:11 +01:00
|
|
|
|
|
|
|
if len(contours) is not 0:
|
2018-03-05 16:33:18 +01:00
|
|
|
ind, _ = max(enumerate([cv.contourArea(x) for x in contours]), key = lambda x: x[1])
|
|
|
|
max_contour = contours[ind]
|
2018-03-04 21:23:11 +01:00
|
|
|
rect = cv.minAreaRect(max_contour)
|
2018-03-05 12:05:22 +01:00
|
|
|
rect = cv.boxPoints(rect)
|
2018-03-06 15:58:34 +01:00
|
|
|
# cv.drawContours(src, [np.int0(rect)], 0, (0, 0, 255), 2)
|
|
|
|
# cv.imshow('src', src)
|
2018-03-05 00:31:38 +01:00
|
|
|
|
2018-03-05 12:05:22 +01:00
|
|
|
return rect
|
2018-03-04 21:23:11 +01:00
|
|
|
|
|
|
|
|
2018-03-05 01:47:24 +01:00
|
|
|
def crop_resistor(img, box):
|
|
|
|
M = cv.moments(box)
|
|
|
|
center = (int(M['m10']/M['m00']), int(M['m01']/M['m00']))
|
|
|
|
box = sort_coords(box)
|
|
|
|
|
|
|
|
x = abs(box[0][0] - box[2][0])
|
|
|
|
y = abs(box[0][1] - box[2][1])
|
|
|
|
phi = np.arctan2(y, x)
|
|
|
|
|
|
|
|
if box[0][1] > box[2][1]:
|
|
|
|
phi = -phi
|
|
|
|
|
|
|
|
rotate_pt(box, center, -phi)
|
2018-03-05 12:05:22 +01:00
|
|
|
box = np.int0(box)
|
2018-03-05 01:47:24 +01:00
|
|
|
box = sort_coords(box)
|
|
|
|
|
|
|
|
w, h, c = img.shape
|
|
|
|
rotM = cv.getRotationMatrix2D(center, np.degrees(phi), 1.0)
|
2018-03-05 12:05:22 +01:00
|
|
|
img = cv.warpAffine(img, rotM, (int(h*1.4), int(w*1.4)))
|
2018-03-05 01:47:24 +01:00
|
|
|
|
|
|
|
x = box[0][0]
|
|
|
|
y = box[0][1]
|
|
|
|
w = box[2][0] - box[0][0]
|
|
|
|
h = box[1][1] - box[0][1]
|
|
|
|
y += int(0.2 * h)
|
|
|
|
h = int(0.6 * h)
|
2018-03-06 15:58:34 +01:00
|
|
|
x += int(0.1 * w)
|
|
|
|
w = int(0.8 * w)
|
2018-03-05 01:47:24 +01:00
|
|
|
img = img[y:(y+h), x:(x+w)]
|
2018-03-15 21:25:14 +01:00
|
|
|
# cv.imshow('img', img)
|
2018-03-05 01:47:24 +01:00
|
|
|
|
|
|
|
return img
|
2018-03-05 12:05:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
def simplify_image(img):
|
|
|
|
# kernel = np.array([[0,-1,0], [-1,5,-1], [0,-1,0]])
|
|
|
|
# img = cv.filter2D(img, -1, kernel)
|
|
|
|
|
|
|
|
h, w, c = img.shape
|
2018-03-06 15:58:34 +01:00
|
|
|
simple_height = 5
|
|
|
|
simple = np.zeros((simple_height, w, 3), np.uint8)
|
2018-03-05 12:05:22 +01:00
|
|
|
for i in range(w):
|
|
|
|
sumB = 0
|
|
|
|
sumR = 0
|
|
|
|
sumG = 0
|
|
|
|
for j in range(h):
|
|
|
|
sumB += img[j, i, 0]
|
|
|
|
sumR += img[j, i, 1]
|
|
|
|
sumG += img[j, i, 2]
|
|
|
|
|
2018-03-06 15:58:34 +01:00
|
|
|
for k in range(simple_height):
|
|
|
|
simple[k, i] = [ sumB/h, sumR/h, sumG/h ]
|
2018-03-05 12:05:22 +01:00
|
|
|
|
|
|
|
return simple
|
|
|
|
|
|
|
|
|
|
|
|
def find_bands(img):
|
|
|
|
i = 0
|
|
|
|
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV);
|
|
|
|
h, w, c = img.shape
|
|
|
|
|
2018-03-05 16:33:18 +01:00
|
|
|
# check_color(hsv[0, 0])
|
2018-03-05 12:05:22 +01:00
|
|
|
# while hsv[0, i][0] >= 0 and i < w:
|
2018-03-05 16:33:18 +01:00
|
|
|
band_colors = []
|
|
|
|
for i in range(w):
|
2018-03-15 21:25:14 +01:00
|
|
|
# print i, hsv[0, i]
|
2018-03-05 16:33:18 +01:00
|
|
|
band_colors.append(check_color(hsv[0, i]))
|
2018-03-05 12:05:22 +01:00
|
|
|
|
2018-03-05 16:33:18 +01:00
|
|
|
band_colors = [k for k, g in it.groupby(band_colors) if sum(1 for _ in g) > 2]
|
|
|
|
band_colors = filter(None, band_colors)
|
|
|
|
return ''.join(band_colors)
|
2018-03-05 12:05:22 +01:00
|
|
|
|
|
|
|
|
2018-03-05 16:33:18 +01:00
|
|
|
def check_color(px):
|
|
|
|
pColors = {}
|
|
|
|
pColors['0'] = np.mean(check_color_range(px[0], px[1], px[2], 'black') or[ 0 ])
|
|
|
|
pColors['1'] = np.mean(check_color_range(px[0], px[1], px[2], 'brown') or[ 0 ])
|
|
|
|
pColors['2'] = np.mean(check_color_range(px[0], px[1], px[2], 'red') or[ 0 ])
|
|
|
|
pColors['3'] = np.mean(check_color_range(px[0], px[1], px[2], 'orange') or[ 0 ])
|
|
|
|
pColors['4'] = np.mean(check_color_range(px[0], px[1], px[2], 'yellow') or[ 0 ])
|
|
|
|
pColors['5'] = np.mean(check_color_range(px[0], px[1], px[2], 'green') or[ 0 ])
|
|
|
|
pColors['6'] = np.mean(check_color_range(px[0], px[1], px[2], 'blue') or[ 0 ])
|
|
|
|
pColors['7'] = np.mean(check_color_range(px[0], px[1], px[2], 'purple') or[ 0 ])
|
|
|
|
pColors['8'] = np.mean(check_color_range(px[0], px[1], px[2], 'gray') or[ 0 ])
|
|
|
|
pColors['9'] = np.mean(check_color_range(px[0], px[1], px[2], 'white') or[ 0 ])
|
|
|
|
pColors['G'] = np.mean(check_color_range(px[0], px[1], px[2], 'gold') or[ 0 ])
|
|
|
|
best = max(pColors, key=pColors.get)
|
2018-03-06 12:06:10 +01:00
|
|
|
best = None if pColors[best] < 0.05 else best
|
2018-03-05 16:33:18 +01:00
|
|
|
return best
|
|
|
|
|
|
|
|
|
|
|
|
def check_color_range(h, s, v, color_str):
|
|
|
|
col = colors[color_str]
|
2018-03-06 12:06:10 +01:00
|
|
|
if color_str == 'red':
|
|
|
|
if ((h >= col['lowH'] and h <= 0) or (h >= 0 and h <= col['highH'])) and s >= col['lowS'] and s <= col['highS'] and v >= col['lowV'] and v <= col['highV']:
|
2018-03-05 16:33:18 +01:00
|
|
|
diff = 180 - col['lowH']
|
|
|
|
h = calculate_offset(h + diff, col['highH'] + diff, 0)
|
2018-03-06 12:06:10 +01:00
|
|
|
s = calculate_offset(s, col['highS'], col['lowS'])
|
|
|
|
v = calculate_offset(v, col['highV'], col['lowV'])
|
|
|
|
return [h, s, v]
|
|
|
|
else:
|
|
|
|
if h >= col['lowH'] and h <= col['highH'] and s >= col['lowS'] and s <= col['highS'] and v >= col['lowV'] and v <= col['highV']:
|
2018-03-05 16:33:18 +01:00
|
|
|
h = calculate_offset(h, col['highH'], col['lowH'])
|
2018-03-06 12:06:10 +01:00
|
|
|
s = calculate_offset(s, col['highS'], col['lowS'])
|
|
|
|
v = calculate_offset(v, col['highV'], col['lowV'])
|
|
|
|
return [h, s, v]
|
2018-03-05 16:33:18 +01:00
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def calculate_offset(x, high, low):
|
|
|
|
m = (high - low) / 2.0
|
|
|
|
return 1 - abs((x - m) / (high - m))
|
2018-03-05 01:47:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
colors = {
|
|
|
|
'black': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 0,
|
|
|
|
'highH': 179,
|
|
|
|
'lowS': 0,
|
2018-03-05 16:33:18 +01:00
|
|
|
'highS': 10,
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowV': 0,
|
2018-03-05 16:33:18 +01:00
|
|
|
'highV': 40,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'brown': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 3,
|
|
|
|
'highH': 20,
|
|
|
|
'lowS': 200,
|
|
|
|
'highS': 255,
|
|
|
|
'lowV': 80,
|
|
|
|
'highV': 140,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'red': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 170,
|
|
|
|
'highH': 5,
|
|
|
|
'lowS': 124,
|
|
|
|
'highS': 255,
|
|
|
|
'lowV': 74,
|
|
|
|
'highV': 255,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'orange': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 3,
|
|
|
|
'highH': 20,
|
|
|
|
'lowS': 200,
|
|
|
|
'highS': 255,
|
|
|
|
'lowV': 141,
|
|
|
|
'highV': 255,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'yellow': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 20,
|
2018-03-05 16:33:18 +01:00
|
|
|
'highH': 32,
|
2018-03-06 15:58:34 +01:00
|
|
|
'lowS': 180,
|
2018-03-05 12:05:22 +01:00
|
|
|
'highS': 255,
|
|
|
|
'lowV': 100,
|
2018-03-06 15:58:34 +01:00
|
|
|
'highV': 230,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'green': {
|
2018-03-06 15:58:34 +01:00
|
|
|
'lowH': 40,
|
2018-03-05 12:05:22 +01:00
|
|
|
'highH': 80,
|
2018-03-06 15:58:34 +01:00
|
|
|
'lowS': 60,
|
2018-03-05 12:05:22 +01:00
|
|
|
'highS': 255,
|
|
|
|
'lowV': 30,
|
2018-03-06 12:06:10 +01:00
|
|
|
'highV': 255,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'blue': {
|
2018-03-06 12:06:10 +01:00
|
|
|
'lowH': 81,
|
2018-03-06 15:58:34 +01:00
|
|
|
'highH': 125,
|
|
|
|
'lowS': 40,
|
2018-03-05 12:05:22 +01:00
|
|
|
'highS': 255,
|
2018-03-06 12:06:10 +01:00
|
|
|
'lowV': 30,
|
2018-03-05 12:05:22 +01:00
|
|
|
'highV': 255,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'purple': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 140,
|
2018-03-15 21:25:14 +01:00
|
|
|
'highH': 175,
|
|
|
|
'lowS': 170,
|
|
|
|
'highS': 255,
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowV': 10,
|
2018-03-15 21:25:14 +01:00
|
|
|
'highV': 210,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'gray': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 0,
|
2018-03-06 12:06:10 +01:00
|
|
|
'highH': 40,
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowS': 0,
|
2018-03-06 15:58:34 +01:00
|
|
|
'highS': 83,
|
|
|
|
'lowV': 100,
|
2018-03-05 16:33:18 +01:00
|
|
|
'highV': 220,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'white': {
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowH': 0,
|
2018-03-06 12:06:10 +01:00
|
|
|
'highH': 40,
|
2018-03-05 12:05:22 +01:00
|
|
|
'lowS': 0,
|
2018-03-06 12:06:10 +01:00
|
|
|
'highS': 15,
|
|
|
|
'lowV': 221,
|
2018-03-05 12:05:22 +01:00
|
|
|
'highV': 255,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
'gold': {
|
2018-03-05 16:33:18 +01:00
|
|
|
'lowH': 10,
|
|
|
|
'highH': 20,
|
2018-03-06 15:58:34 +01:00
|
|
|
'lowS': 150,
|
2018-03-05 12:05:22 +01:00
|
|
|
'highS': 230,
|
|
|
|
'lowV': 100,
|
2018-03-06 15:58:34 +01:00
|
|
|
'highV': 175,
|
2018-03-05 01:47:24 +01:00
|
|
|
},
|
|
|
|
}
|
2018-03-04 21:23:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|