advancedskrald/runner.py

318 lines
11 KiB
Python
Raw Normal View History

2019-04-04 10:59:37 +00:00
import glob
import os
2019-05-18 15:12:35 +00:00
import time
2019-04-04 10:59:37 +00:00
from datetime import datetime
2019-04-16 21:29:41 +00:00
from pathlib import Path
from typing import Tuple
2019-05-18 15:12:35 +00:00
import copyreg
2019-04-16 21:29:41 +00:00
import cv2
import numpy as np
2019-04-16 21:29:41 +00:00
from sklearn import cluster, metrics, svm, neural_network
from sklearn.externals import joblib
2019-04-04 16:27:19 +00:00
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
2019-04-10 11:39:50 +00:00
from util import RANK, POSITION, imwrite, PIECE, COLOR, Squares, OUR_PIECES
here: Path = Path(__file__).parent
2019-05-18 15:12:35 +00:00
BASELINE = cv2.imread(str(here.joinpath("new_baseline_board.png")))
BASELINE_GRAY = cv2.cvtColor(BASELINE, cv2.COLOR_BGR2GRAY)
SIFT = cv2.xfeatures2d.SIFT_create()
BASELINE_KEYPOINTS = SIFT.detect(BASELINE_GRAY)
BASELINE_KEYPOINTS, BASELINE_DES = SIFT.compute(BASELINE_GRAY, BASELINE_KEYPOINTS)
def generate_centers(number_of_clusters, sift: cv2.xfeatures2d_SIFT):
2019-04-10 11:39:50 +00:00
features = None
for piece in OUR_PIECES:
for color in COLOR:
2019-04-10 11:39:50 +00:00
for filename in glob.glob(f"training_images/{piece}/{color}_square/*.png"):
2019-04-04 10:59:37 +00:00
image = cv2.imread(filename)
#image = selective_search(image, use_fast=True)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
kp, desc = sift.detectAndCompute(gray, None)
print(f"{piece}, {color}, {filename}")
2019-04-10 11:39:50 +00:00
if features is None:
features = np.array(desc)
else:
print(f"{piece}, {color}, {filename}")
features = np.vstack((features, desc))
features = np.array(features)
2019-04-04 10:59:37 +00:00
k_means = cluster.KMeans(number_of_clusters)
k_means.fit(features)
return k_means.cluster_centers_
def generate_bag_of_words(image, centers, sift: cv2.xfeatures2d_SIFT):
2019-04-04 10:59:37 +00:00
num_centers = centers.shape[0]
histogram = np.zeros((1, num_centers))
2019-04-04 10:59:37 +00:00
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
kp, desc = sift.detectAndCompute(gray_image, None)
2019-04-04 10:59:37 +00:00
if not kp:
return histogram
2019-04-04 10:59:37 +00:00
distances = metrics.pairwise.pairwise_distances(desc, centers)
best_centers = np.argmin(distances, axis=1)
for i in best_centers: # TODO: Could do this way faster in one line with numpy somehow
histogram[0, i] += + 1
return histogram / np.sum(histogram)
def do_pre_processing() -> None:
2019-04-04 10:59:37 +00:00
sift = cv2.xfeatures2d.SIFT_create()
centers = generate_centers(8, sift)
2019-04-04 10:59:37 +00:00
np.save("training_data/centers", centers)
2019-04-10 11:39:50 +00:00
for piece in OUR_PIECES:
for color in COLOR:
2019-04-10 11:39:50 +00:00
for filename in glob.glob(f"training_images/{piece}/{color}_square/*.png"):
2019-04-04 10:59:37 +00:00
image = cv2.imread(filename)
#image = selective_search(image, image_name=filename, use_fast=True)
bow_features = generate_bag_of_words(image, centers, sift)
np.save(f"training_data/{piece}/{color}_square/{os.path.basename(filename)}", bow_features)
def load_training_data(piece: PIECE, color: COLOR) -> Tuple[np.array, np.array]:
X = []
Y = []
2019-04-10 11:39:50 +00:00
for p in OUR_PIECES:
for filename in glob.glob(f"training_data/{piece}/{color}_square/*.npy"):
2019-04-04 10:59:37 +00:00
data = np.load(filename)
2019-04-10 11:39:50 +00:00
X.append(data[0])
Y.append(p == piece)
return np.array(X), np.array(Y)
def train_empty_or_piece_hist() -> None:
for square_color in COLOR:
X = []
Y = []
2019-04-10 11:39:50 +00:00
for piece in OUR_PIECES + (PIECE.EMPTY,):
print(f"training training_images/{piece}/{square_color}_square/*.png")
2019-04-10 11:39:50 +00:00
for filename in glob.glob(f"training_images/{piece}/{square_color}_square/*.png"):
2019-04-04 10:59:37 +00:00
img = cv2.imread(filename)
y, x = np.histogram(img.ravel(), bins=32, range=[0, 256])
X.append(y)
Y.append(piece == PIECE.EMPTY)
2019-04-04 16:27:19 +00:00
classifier = make_pipeline(StandardScaler(),
svm.SVC(C=10.0, gamma=0.01, probability=True))
classifier.fit(np.array(X), np.array(Y))
2019-04-04 16:27:19 +00:00
joblib.dump(classifier, f"classifiers/classifier_empty/white_piece_on_{square_color}_square.pkl")
def train_pieces_svm() -> None:
2019-04-10 11:39:50 +00:00
for piece in OUR_PIECES:
for color in COLOR:
2019-04-10 11:39:50 +00:00
total_weights = len(glob.glob(f"training_images/{piece}/{color}_square/*.png"))
2019-04-10 11:39:50 +00:00
for piece in OUR_PIECES:
for color in COLOR:
current_weight = len(glob.glob(f"training_images/{piece}/{color}_square/*.png"))
print(f"Training for piece: {piece}")
2019-04-04 10:59:37 +00:00
X, Y = load_training_data(piece, color)
2019-05-18 15:12:35 +00:00
classifier = svm.SVC(gamma=0.01, class_weight={0: current_weight, 1: total_weights}, probability=True)
2019-04-04 10:59:37 +00:00
classifier.fit(X, Y)
joblib.dump(classifier, f"classifiers/classifier_{piece}/{color}.pkl")
2019-04-10 20:32:30 +00:00
def train_pieces_svm_canny() -> None:
for square_color in COLOR:
X = []
Y = []
for piece in OUR_PIECES + (PIECE.EMPTY,):
for filename in glob.glob(f"training_images/{piece}/{square_color}_square/*.png"):
img = cv2.imread(filename)
y, x = np.histogram(img.ravel(), bins=32, range=[0, 256])
X.append(y)
Y.append(piece == PIECE.EMPTY)
classifier = make_pipeline(StandardScaler(),
svm.SVC(C=10.0, gamma=0.01, probability=True))
classifier.fit(np.array(X), np.array(Y))
joblib.dump(classifier, f"classifiers/classifier_empty/white_piece_on_{square_color}_square.pkl")
2019-04-17 16:20:37 +00:00
def find_keypoints(camera_image: np.ndarray, baseline: np.ndarray, debug=False) -> Tuple[np.ndarray, np.ndarray]:
2019-04-16 21:29:41 +00:00
"""
Find keypoints in raw camera image of board.
2019-04-04 10:59:37 +00:00
2019-04-16 21:29:41 +00:00
:return: (src points, dest points)
"""
2019-05-18 15:12:35 +00:00
cv2.imwrite("camera_image.png", camera_image)
2019-04-04 10:59:37 +00:00
camera_image_gray = cv2.cvtColor(camera_image, cv2.COLOR_BGR2GRAY)
2019-05-18 15:12:35 +00:00
#sift = cv2.xfeatures2d.SURF_create()
kp_start = time.time()
camera_image_keypoints = SIFT.detect(camera_image_gray, None)
2019-04-04 10:59:37 +00:00
2019-05-18 15:12:35 +00:00
camera_image_keypoints, des = SIFT.compute(camera_image_gray, camera_image_keypoints)
#print("kp:",time.time() - kp_start)
def_flan = time.time()
2019-04-04 10:59:37 +00:00
# FLANN parameters
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=8)
2019-04-16 21:29:41 +00:00
search_params = dict(checks=100) # or pass empty dictionary
2019-04-04 10:59:37 +00:00
2019-05-18 15:12:35 +00:00
flann_start = time.time()
2019-04-16 21:29:41 +00:00
flann = cv2.FlannBasedMatcher(index_params, search_params)
2019-05-18 15:12:35 +00:00
#print("end_def:", time.time() - def_flan)
matches = flann.knnMatch(des, BASELINE_DES, k=2)
#print("flann:",time.time() - flann_start)
2019-04-04 10:59:37 +00:00
# Need to draw only good matches, so create a mask
matchesMask = [[0, 0] for _ in range(len(matches))]
2019-04-04 10:59:37 +00:00
# Ratio test as per Lowe's paper
2019-04-04 10:59:37 +00:00
good_matches = []
for i, (m, n) in enumerate(matches):
2019-04-16 21:29:41 +00:00
if m.distance < 0.55 * n.distance:
matchesMask[i] = [1, 0]
good_matches.append([m, n])
2019-05-18 15:12:35 +00:00
#good_matches = list(filter(lambda x: x[0].distance < 0.55 * x[1].distance, matches))
2019-04-16 21:29:41 +00:00
if debug:
# Save keypoints
keypoints_image = camera_image.copy()
cv2.drawKeypoints(camera_image, keypoints=camera_image_keypoints, outImage=keypoints_image)
cv2.imwrite("keypoints.png", keypoints_image)
# Save matches
matches_image = cv2.drawMatchesKnn(
camera_image,
camera_image_keypoints,
baseline,
2019-05-18 15:12:35 +00:00
BASELINE_KEYPOINTS,
2019-04-16 21:29:41 +00:00
matches,
None,
matchColor=(0, 255, 0),
singlePointColor=(255, 0, 0),
matchesMask=matchesMask,
flags=0
)
cv2.imwrite("matches.png", matches_image)
2019-04-04 10:59:37 +00:00
# Extract location of good matches
2019-04-16 21:29:41 +00:00
src_points = np.zeros((len(good_matches), 2), dtype=np.float32)
dst_points = np.zeros((len(good_matches), 2), dtype=np.float32)
2019-04-04 10:59:37 +00:00
2019-05-18 15:12:35 +00:00
2019-04-04 10:59:37 +00:00
for i, (m, n) in enumerate(good_matches):
2019-04-16 21:29:41 +00:00
src_points[i, :] = camera_image_keypoints[m.queryIdx].pt
2019-05-18 15:12:35 +00:00
dst_points[i, :] = BASELINE_KEYPOINTS[m.trainIdx].pt
2019-04-04 10:59:37 +00:00
2019-04-16 21:29:41 +00:00
return src_points, dst_points
2019-04-11 11:39:19 +00:00
2019-04-17 16:20:37 +00:00
def find_homography(camera_image: np.ndarray,
2019-05-18 15:12:35 +00:00
baseline: np.ndarray = BASELINE,
2019-04-17 16:20:37 +00:00
debug=False) -> np.ndarray:
2019-04-16 21:29:41 +00:00
src_points, dst_points = find_keypoints(camera_image, baseline, debug=debug)
h, mask = cv2.findHomography(src_points, dst_points, cv2.RANSAC)
2019-04-17 16:20:37 +00:00
return h
def warp_board(camera_image: np.ndarray, homography: np.ndarray = None, debug=False) -> np.ndarray:
if homography is None:
2019-05-18 15:12:35 +00:00
homography = find_homography(camera_image, BASELINE, debug=debug)
2019-04-17 16:20:37 +00:00
2019-05-18 15:12:35 +00:00
height, width, channels = BASELINE.shape
2019-04-17 16:20:37 +00:00
return cv2.warpPerspective(camera_image, homography, (width, height))
2019-04-04 10:59:37 +00:00
def get_square(warped_board: np.ndarray, position: POSITION) -> np.ndarray:
2019-04-04 10:59:37 +00:00
width, _, _ = warped_board.shape # board is square anyway
2019-04-04 16:27:19 +00:00
side = int(width * 0.045)
2019-04-04 10:59:37 +00:00
size = width - 2 * side
square_size = size // 8
2019-04-10 20:32:30 +00:00
padding = 2
2019-04-04 10:59:37 +00:00
x1 = side + (square_size * (position.file - 1))
2019-04-10 20:32:30 +00:00
x2 = x1 + square_size + padding
y1 = max(0, side + (square_size * (8 - position.rank)) - padding) # 8 - rank because chessboard is from 8 to 1
2019-04-04 10:59:37 +00:00
y2 = min(width, y1 + square_size + padding)
square = warped_board[y1:y2, x1:x2]
return square
def get_squares(warped_board: np.ndarray) -> Squares:
# cv2.imwrite(f"warped_square_{square}.png", square)
return {position: get_square(warped_board, position)
for position in POSITION}
2019-04-04 16:27:19 +00:00
2019-05-18 15:12:35 +00:00
def save_empty_fields(warped_board: np.ndarray, skip_rank: RANK = None, fourk=False) -> None:
for position in POSITION:
if position.rank == skip_rank:
continue
square = get_square(warped_board, position)
2019-05-18 15:12:35 +00:00
if fourk:
imwrite(f"training_images/4k/empty/{position.color}_square/training_{position}_{datetime.utcnow().timestamp()}.png", square)
else:
imwrite(f"training_images/empty/{position.color}_square/training_{position}_{datetime.utcnow().timestamp()}.png", square)
2019-04-04 16:27:19 +00:00
2019-04-10 20:32:30 +00:00
def load_data_nn(spec_piece, color):
X = None
Y = None
for piece in OUR_PIECES:
piece_class = int(spec_piece == piece)
for filename in glob.glob(f"training_images/{piece}/{color}_square/*.png"):
image = cv2.imread(filename)
data = np.reshape(image, (1, np.product(image.shape)))
if X is None:
if piece_class == 1:
for _ in range(10):
X = np.array(data)
Y = np.array([piece_class])
else:
for _ in range(5):
X = np.array(data)
Y = np.array([piece_class])
else:
if piece_class == 1:
for _ in range(10):
X = np.vstack((X, data))
Y = np.vstack((Y, [piece_class]))
else:
for _ in range(5):
X = np.vstack((X, data))
Y = np.vstack((Y, [piece_class]))
return X, Y
def train_nn():
for piece in OUR_PIECES:
for color in COLOR:
X, Y = load_data_nn(piece, color)
classifier = neural_network.MLPClassifier(hidden_layer_sizes=256)
classifier.fit(X, Y)
joblib.dump(classifier, f"classifiers/neural_net_{piece}/{color}.pkl")
if __name__ == '__main__':
#train_nn()
2019-05-18 15:12:35 +00:00
do_pre_processing()
train_pieces_svm()