diff --git a/presentation/ball_tracking.xml b/presentation/ball_tracking.xml
new file mode 100644
index 0000000..3f44dd1
--- /dev/null
+++ b/presentation/ball_tracking.xml
@@ -0,0 +1 @@
+7V1bc6M2GP01nj4lA0hc/Bg78e5D29lpOtPuowyyzS5GHsBJvL++EkgYIfkubLreZCYDQtx0dI6+i1AGYLz8+JSh1eIPEuFk4FjRxwA8Dxxn6Fr0LyvYVAU+8KuCeRZHVZG9LXiNf2BeyM+br+MI51LFgpCkiFdyYUjSFIeFVIayjLzL1WYkke+6QnOsFLyGKFFL/4mjYlGVBo6/Lf+M4/lC3Nn2htWRKQq/zzOyTvn9Bg6YlT/V4SUS1+Ivmi9QRN4bReBlAMYZIUW1tfwY44Q1rWi26rzJjqP1c2c4LY45wefP/YaSNRaPXD5YsRGNUb4OZidYAzB6X8QFfl2hkB19p+jTskWxTOieTTcjlC/KumwnQVOcjOomGZOEZPRQSlJ68igvMvK9bl/66qNZnCSiEm25Z/hiT1xWTtJigpZxwrrTUxajhBfynmN7fL9xsmXB8XBY36ZxxAsDPJ3RI2pj8fZ7w1mBPxpFvPE+YbLERbahVfhRgSPv5xDw/fdtr/FE2aLRY4a8DPGOOq+vvAWLbnC8dmAX9Bg7bEcu9o1jN/R8gDxD2AEZPHpbBTzoaMCzHRPo+T1GjwqWE4bG0Yu8qed2hJ6ngucONeDV510Enttj8F489mteNsufTmRTg51jabADngHs6qF3CxWO6OjPd0lWLMicpCh52ZaOZDAbwOGPuPi3sf2VVXlkgxZtnWzzLz+j3Nke+4aLYsNRQOuC0KLtfX8nZMWvqMH6EKZQhyn72YdcTtZZyBuD9+QCZXMsavHuztppL7wZTlARv8lW1CVgAZVofxKT+F0XifGYI9HW2yDEpd4qrJsGLnSt3aLQ5Hvn8HL2PliP/CpH411e6ynL0KZRYUXitMgbt/rCChoqYcsyIaR7cl59ulE9Qets8ThkNstpk7R7Z/3+R3VYz+9CXbiicH2xJXXZis3Xpth8wVlMnxtnvPDakjMc6jo6NQqDCOo6euBMwf7h5UAvhjcTKU81xL/iXOkHdGwsZHgznMc/0LSswBqLE4LWdkcD95mWoCSep7QgpI3BoByxMTamjuoTP7CMo6jsQ0fogw4zLbA6IFVYRFdXhv3aL+evNmj6trsEJZCo656jL4ogPLjSRR/sR1e+hBHKOwr6FLayQkr/MKPN8RKG/DSjW3O2RWas8y40R0K0xBl7vIlqUC7IcrrODxuTF9kIKv8N2Hu+LMx2oBp8ttbTskwYfKpt/tMbfN2qr6+xIeCt1BdavVbfyWTijMfm1beWHRPqa7sguExxzSoq6N6IuoVNxCW2FgpbFQqt7Xa6t3AujR3jNNaPzNCTh2a7HZWpHoqfdVFnAqp1pnEh/5fyULuTGnkABuUBWi5sWVI9Ugs1kPp3FlMhYDmjEmS8GlSZmYusqmvFYo63qiAEjy0aXdewGl5Hpk/WyxvpekcyLUwrSae9m5lbopvel5yKPKkRX7dF2su0VH4acU1PPt+I0IJOzLJ9jpQc27L7wvduvSsd34FzM76r4Y17cK+AMfvJerR8MT1EmE9nhc87Mp9Ed9PYT2UYqx2hWpE8j9m7M4sCldXSeYIvC1n1z7jyhITexrSylbb8FbO6TFVdVVX9W4kqUH2WexDVnSw8y4ry7JaqAiOG1IOtvapRzYU/aYBLT+EjHKGTXbyzOW8bJ72+G9WzyXg/as/4MxfgguoAfgceGTQZ4KJt2ApwXWihiUs7shHhdKAltjpFRthvS5JpUozFAqVqKW1Oa5ah5YWGXP9yj3WC6CaGnH2FGJk40tbIfXNE+jwDzdYlJm5lqtmqqfZX5fZwtrANsmSyw1P3bbzVJmw6Pgu0YvWWH3P2JcXjLCHv4QJlxeMqIyHOd1HOaKCy+kJBMz6bdKiCFg1tDQ11kz6hARaK7FLnkeoTWdiLaNZJk0M1sSnzFtXRXrJq+bwWhGV7wnVWvgcbA9/wstpEaTSQ80H9p6oB4gHnCOZ5XTGvk0DGcczrNZGMJ3B2pAXADvAP+CGnztV1Xa27s2uqbvux5OryTN1zJpB4GpuYvU7KvCA5cHkfIuDu6gdXGX7hr+HXiGqINFA/hl/xNE3TmBSoYKmBKYk298Es374hs2An7qUmT7CXWUfG7PrMLKgJFcLgVsyCakxnjJJwnXByVfPLN+h9O4hVs83LOeXcExUu6n3QsGV/AHhFI9e91sSIn56FgcpCAewNWKjOHK3Ht4po3I6cbhrU4zSNWjy9Bw46QXtC4nVp2ImZeRwNz2PV3jzIGZE8U8ly85zTu4Ft20n5wNtclsxVXcI+pdzrGKzhlLvghJk0mRPwVrwQ96F8gplp4FeINB3MtNznDGUhF81hW0x5u/6w7atuaY/y4dKiRgbz4f6u0focogNoO5IwP4hZghcnxFsGgtOBEoju2OgAnytDrbTE2pnv97hYxJqM+JQhp82Gn2m8RTiM85ikPbXe3FaeAOgCGZ0lyl3V5RWfUbMca0LC78ymNoMEZe8yTlHBmvE8LLRL55g3ys4PQwHNUmR1aKqJnok1dcQ1DI+9pznAPR97jxtJdQ7wzUZSd48DXAV4m67voqGxd+HtQnlyF9T5umLcNO3rek4PGPczhJwEu64wR/TUnGorZQe9/TnVdoZv3+pH51hV6lKhtRhw6tPHYV/c/sAZuSchaK1uotWBrhJA/q+R14wOeBodcG+WAPJUsu2Z2XQPJINAdhx1LNOt92mCZIHqUI5R+hsD4RVvswGVv3IwziC7AXxVz6bPwIuOjzbo8JI5fsL6ogeBDlSgh0M4rmZw04eI0/mg+ZGGJiKh9ITdRtbhZV61+QQTq7wG6qfuqtim0RNbcJzhlKA8j0MZ7COWZTsjJbBv4dbGhBerJcyWf+B7mpbQaSmrGkoqeM1FeDXgiLILg0ntxbdbkFfqruQO1CSEfBm3fR1zOYhAjUzyGMczhSIsWGzoLvVj+wWIaf0IDssH7Eo+gII2D0M+Rd/WeaEdu+8Cbs+zrDLu1flwoVvT3dZJkhHA1enooypKcu+Ab1cVNw54awwYdoc33d3+Y45K/bf//AS8/Ac=
\ No newline at end of file
diff --git a/presentation/milestones.xml b/presentation/milestones.xml
new file mode 100644
index 0000000..4805f77
--- /dev/null
+++ b/presentation/milestones.xml
@@ -0,0 +1 @@
+7Zpdb9owFIZ/DbdVPkgIlwXaTtoqVeqkrZcmOSRenThynAL79bOJHZIaNqQGwtRwgeLj44+c18/hEGXkztPNA0N58kgjICPHijYjdzFynKlniW9p2FYGPwgqQ8xwVJnsveEZ/wZlVOPiEkdQtBw5pYTjvG0MaZZByFs2xBhdt91WlLRXzVEMhuE5RMS0/sART5TV9qf7ji+A40QtHTiTqmOJwteY0TJT640cd7X7VN0p0nOpGy0SFNF1w+Tejdw5o5RXV+lmDkSGVoetGnd/pLfeN4OMnzJgXA14Q6QEvePdvvhWxwIiERrVpIwnNKYZInd762x3vyBntEQr4SkRl7a4JGgJZFaHZE4JZaIro5kc9gs43yrtUcmpMO3n/0ZprmYpOKOvtQ4iRLMVzfg9SjGRx+uWYUSUUc3maCe9opDB2n3kdDkKcRYL61h6YUIaXqsghDCsF230LANv7MnxZohV1AtaslAFTYWRIxaD8nIrkwxnY5iS5QFoCpxthQMDgjh+a59EpA50XPvtRRUXStfDGjuGxjO0c1gAF/Bgmhmat0Nut1UVZzaXfukmlvDfrAhdhwli/CZnNIRCbHW2TjCHZxFp6bgWbv88DceE+JjWR1Vsn4Kjmr4B47D5q16qVxOtMp7OgOtG+tC2pJE5JtbHBfYHiM8CsWtC7PUFsWto/EDRAHHXEPdIcTBQ3D48K/APUxxNpkvrZIo9k+JJXxR7hsb3GERtOmDcKcbjHjGuj2An2MIG85/SfOOp1kuj5wkYFhsEpgaKiLFtw102X5p97wd83qwwMbOC3VuFPjHSwveSZTIG8n+v+KoK9utLDFqMbhNDrWTnicHvMTHYQ5l+HpTtA3W63VuhbpuV+gIXHGViu471CKgoGaTyfgaeO+fZsS4J9FCxvz8+K+cI0P7S9/yTgT5Qstu91ey2WbTf5gI6FCbC+kRQVv1SDzR3XbZflGa99kBz1zQfKrWnvdFs1trqafge6iskWUnRMclax7M/R7ssyWYFNpDcCclTk2Qd2x5Inhoyq0fitwTH2dWW2P8byn2SbJZen5vkyIMgGh86AIGzdP2TSdZxbJE87otkvZsDv8kDyWcj2b3oU3HzRZOvOHy9QllrxLqVtebz7LXWOXUVzf27Sbu+xvtf7t0f
\ No newline at end of file
diff --git a/presentation/striker_flowchart.xml b/presentation/striker_flowchart.xml
new file mode 100644
index 0000000..083a803
--- /dev/null
+++ b/presentation/striker_flowchart.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/pykick/colorpicker.py b/pykick/colorpicker.py
index 7b40da6..3626abe 100644
--- a/pykick/colorpicker.py
+++ b/pykick/colorpicker.py
@@ -5,6 +5,7 @@ import json
import argparse
import cv2
+import numpy as np
from .imagereaders import VideoReader, NaoImageReader, PictureReader
from .finders import GoalFinder, BallFinder, FieldFinder
@@ -99,9 +100,13 @@ class Colorpicker(object):
tuple(map(self.settings.get, ('high_h', 'high_s', 'high_v')))
)
- cv2.imshow(self.WINDOW_CAPTURE_NAME, frame)
- cv2.imshow(self.WINDOW_DETECTION_NAME, thr)
- return cv2.waitKey(0 if manual else 1)
+ thr = cv2.cvtColor(thr, cv2.COLOR_GRAY2BGR)
+ thr = self.marker.draw_last_contours(thr)
+ resulting = np.concatenate((frame, thr), axis=1)
+
+ cv2.imshow(self.WINDOW_CAPTURE_NAME, resulting)
+ # cv2.imshow(self.WINDOW_DETECTION_NAME, thr)
+ return cv2.waitKey(0 if manual else 50)
def save(self, filename, color):
try:
diff --git a/pykick/detection_demo.py b/pykick/detection_demo.py
index e68ba38..28844ae 100644
--- a/pykick/detection_demo.py
+++ b/pykick/detection_demo.py
@@ -4,6 +4,7 @@ from __future__ import division
import argparse
import cv2
+import numpy as np
from .utils import read_config, imresize
from .imagereaders import NaoImageReader, VideoReader, PictureReader
@@ -118,9 +119,10 @@ if __name__ == '__main__':
ball_frame = ball_finder.draw(ball_frame, ball)
goal_frame = goal_finder.draw(goal_frame, goal)
+ combined = np.concatenate((ball_frame, goal_frame), axis=1)
- cv2.imshow(ball_window, ball_frame)
- cv2.imshow(goal_window, goal_frame)
+ cv2.imshow(ball_window, combined)
+ # cv2.imshow(goal_window, goal_frame)
key = cv2.waitKey(0 if args.manual else 1)
if key == ord('q') or key == 27:
diff --git a/pykick/finders.py b/pykick/finders.py
index 36fe4e4..3b29718 100644
--- a/pykick/finders.py
+++ b/pykick/finders.py
@@ -6,7 +6,7 @@ from collections import deque
import cv2
import numpy as np
-from .utils import hsv_mask
+from .utils import hsv_mask, contour_center
class FieldFinder(object):
@@ -51,9 +51,12 @@ class FieldFinder(object):
class GoalFinder(object):
- def __init__(self, hsv_lower, hsv_upper):
+ def __init__(self, hsv_lower, hsv_upper, goal_thr=0.45):
self.hsv_lower = tuple(hsv_lower)
self.hsv_upper = tuple(hsv_upper)
+ self.goal_thr = goal_thr
+ self.last_detection = []
+ self.last_contours = []
def primary_mask(self, frame):
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
@@ -86,9 +89,11 @@ class GoalFinder(object):
return final_score
def find(self, frame):
+ self.last_detection = []
thr = self.primary_mask(frame)
cnts, _ = cv2.findContours(thr, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
+ self.last_contours = cnts
cnts.sort(key=cv2.contourArea, reverse=True)
top_x = 6
cnts = cnts[:top_x]
@@ -108,15 +113,22 @@ class GoalFinder(object):
return None
similarities = [self.goal_similarity(cnt) for cnt in good_cnts]
+ self.last_detection = list(zip(good_cnts, similarities))
best = min(similarities)
print('Final goal score:', best)
print()
- if best > 0.45:
+ if best > self.goal_thr:
return None
# Find the contour with the shape closest to that of the goal
goal = good_cnts[similarities.index(best)]
return goal
+ def draw_last_contours(self, frame):
+ frame = frame.copy()
+ for cnt in self.last_contours:
+ cv2.drawContours(frame, (cnt,), -1, (255, 0, 0), 2)
+ return frame
+
def left_right_post(self, contour):
return contour[...,0].min(), contour[...,0].max()
@@ -127,9 +139,27 @@ class GoalFinder(object):
return (l + r) / 2
def draw(self, frame, goal):
+ frame = frame.copy()
+ cv2.putText(frame,
+ 'Upper threshold: ' + '%.2f' % self.goal_thr, (10, 50),
+ cv2.FONT_HERSHEY_DUPLEX, 1, (0, 255, 0))
+ if self.last_detection:
+ cnts = sorted(self.last_detection,
+ key=lambda x: x[1])
+ if cnts[0][1] < self.goal_thr:
+ goal, score = cnts[0]
+ cnts = cnts[1:]
+ for cnt, sim in cnts[1:]:
+ print(sim)
+ cv2.drawContours(frame, (cnt,), -1, (0, 0, 255), 1)
+ cv2.putText(frame, '%.2f' % sim, contour_center(cnt),
+ cv2.FONT_HERSHEY_DUPLEX, 1, (0, 0, 255))
+
if goal is not None:
- frame = frame.copy()
+ print(goal)
cv2.drawContours(frame, (goal,), -1, (0, 255, 0), 2)
+ cv2.putText(frame, '%.2f' % score, contour_center(goal),
+ cv2.FONT_HERSHEY_DUPLEX, 1, (0, 255, 0))
return frame
@@ -179,8 +209,15 @@ class BallFinder(object):
return center, int(radius)
def draw(self, frame, ball):
+ frame = frame.copy()
if ball is not None:
- frame = frame.copy()
center, radius = ball
- cv2.circle(frame, center, radius, (255, 255, 0), 1)
+ cv2.circle(frame, center, radius, (255, 255, 0), 2)
+ # for i in range(1, len(self.history)):
+ # if self.history[i - 1] is None or self.history[i] is None:
+ # continue
+ # center_now = self.history[i - 1][0]
+ # center_prev = self.history[i][0]
+ # thickness = int((64 / (i + 1))**0.5 * 1.25)
+ # cv2.line(frame, center_now, center_prev, (0, 0, 255), thickness)
return frame
diff --git a/pykick/nao_defaults.json b/pykick/nao_defaults.json
index d0a12f6..cb077e3 100644
--- a/pykick/nao_defaults.json
+++ b/pykick/nao_defaults.json
@@ -15,11 +15,11 @@
[
0,
0,
- 89
+ 159
],
[
180,
- 73,
+ 62,
255
]
],
@@ -28,8 +28,8 @@
"ball_min_radius": 0.01,
"field": [
[
- 31,
- 60,
+ 17,
+ 57,
60
],
[
diff --git a/pykick/utils.py b/pykick/utils.py
index 5dee47e..73ceb54 100644
--- a/pykick/utils.py
+++ b/pykick/utils.py
@@ -41,6 +41,11 @@ def hsv_mask(hsv, hsv_lower, hsv_upper):
else:
return cv2.inRange(hsv, tuple(hsv_lower), tuple(hsv_upper))
+
+def contour_center(contour):
+ M = cv2.moments(contour)
+ return int(M['m10'] / M['m00']) - 30, int(M['m01'] / M['m00']) + 30
+
class InterruptDelayed(object):
def __enter__(self):