diff --git a/launch/tic_tac_toe.launch b/launch/tic_tac_toe.launch index 222220348d26c664eedca919dc0c66d360101d1d..6479fdb133162af2e9e186e772a107b660a9e88b 100644 --- a/launch/tic_tac_toe.launch +++ b/launch/tic_tac_toe.launch @@ -58,6 +58,7 @@ <node name="node_coords_to_board" pkg="socrates_workshop" type="node_coords_to_board.py" /> <node name="node_soundplay" pkg="sound_play" type="soundplay_node.py" /> <node name="node_coords" pkg="socrates_workshop" type="obj_recogkinect.py" /> + <node name="node_kineckt" pkg="freenect_camera" type="freenect_node" /> </launch> diff --git a/scripts/node_coords_to_board.py b/scripts/node_coords_to_board.py index 7154e765e254f45e2c0f08579270a2af38c1d395..518d1ebea1b8182cf47d9eb9b15e501d5d719132 100755 --- a/scripts/node_coords_to_board.py +++ b/scripts/node_coords_to_board.py @@ -27,11 +27,18 @@ int32 id_ai int32[] board """ def closest_point(node, nodes): - nodes = np.asarray(node) + node = np.asarray(node) nodes = np.asarray(nodes) - dist_2 = np.sum((nodes - node)**2) + dist_2 = np.sum((nodes - node)**2, axis=1) return np.argmin(dist_2) + +def dists(node, nodes): + node = np.asarray(node) + nodes = np.asarray(nodes) + dist_2 = np.sum((nodes - node)**2, axis=1) + return dist_2 + """ Returns the cell number (in 0-8) given its point """ @@ -64,8 +71,10 @@ def handleCoordsMessage(msg): cells_points = [[cells[i].x, cells[i].y] for i in range(n_cells)] - pieces_dict = [[getCellNo(closest_point(pieces_points[i], cells_points), cells_points, i), getPlayerId(pieces_labels[i])] for i in range(n_pieces)] + pieces_dict = [[closest_point(pieces_points[i], cells_points), getPlayerId(pieces_labels[i])] for i in range(n_pieces)] + + rospy.loginfo(str(pieces_dict)) this.current_board = [0, 0, 0, 0, 0, 0, 0, 0, 0] diff --git a/scripts/obj_recogkinect.py b/scripts/obj_recogkinect.py index 46275aa0e35c23eaaf0aa02ec8858226fd76caf6..849cfbb8450f7c51f72cd780f187d1f566eb07bc 100755 --- a/scripts/obj_recogkinect.py +++ b/scripts/obj_recogkinect.py @@ -12,36 +12,32 @@ import sys import numpy as np from socrates_workshop.msg import PiecesCoords, LabeledPoint +def common_filtering(c): + area = cv2.contourArea(c) + return area > 500 and area < 20000 +def in_bound(var, v1, v2): + return var >= v1 and var <= v2 -def filter_cell(c): +def filter_square(c): perimeter = cv2.arcLength(c, True) area = cv2.contourArea(c) - approx = cv2.approxPolyDP(c, 0.04 * perimeter, True) - if len(approx) == 4 and area < 10000: - return True - else: - return False + approx = cv2.approxPolyDP(c, 0.02 * perimeter, True) + return common_filtering(c) and in_bound(len(approx), 4, 4) and in_bound(area, 3000, 20000) -def filter_circle(contour): - perimeter = cv2.arcLength(contour, True) - area = cv2.contourArea(contour) - approx = cv2.approxPolyDP(contour, 0.04 * perimeter, True) - if len(approx) > 2 and len(approx) <= 8 and area < 5000: - return True - else: - return False +def filter_circle(c): + perimeter = cv2.arcLength(c, True) + area = cv2.contourArea(c) + approx = cv2.approxPolyDP(c, 0.02 * perimeter, True) + return common_filtering(c) and in_bound(len(approx), 7, 9) and in_bound(area, 1500, 1800) -def filter_cross(contour): - perimeter = cv2.arcLength(contour, True) - area = cv2.contourArea(contour) - approx = cv2.approxPolyDP(contour, 0.03 * perimeter, True) - if len(approx) > 6 and area > 2000: - return True - else: - return False +def filter_cross(c): + perimeter = cv2.arcLength(c, True) + area = cv2.contourArea(c) + approx = cv2.approxPolyDP(c, 0.03 * perimeter, True) + return common_filtering(c) and in_bound(area, 0, 1000) and in_bound(len(approx), 7, 12) def filter_contours(contours, filter_function): @@ -66,6 +62,54 @@ def find_center_point(c, ratio): +def index(h, c): + return h.index[c] + +def rh(h): + return range(len(h)) + +def has_children(h, i): + return h[i][2] != -1 + + +def find_brothers_next(h, i): + if h[i][0] == -1: + return [i] + else: + return [i] + find_brothers_next(h, h[i][0]) + +def get_children(h, i): + if not has_children(h, i): + return [] + + return find_brothers_next(h, h[i][2]) + + +def filter_hierarchy(h, c, f, i=0): + #[Next, Previous, First_Child, Parent] + + res = [] + + if f(h, c, i): + return [c[i]] + + for j in get_children(h, i): + res = res + filter_hierarchy(h, c, f, i=j) + return res + + +def no_children_and_circle(h, c, i): + return filter_circle(c[i]) and not any([common_filtering(c[j]) for j in get_children(h, i)]) + + +def no_children_and_cross(h, c, i): + return filter_cross(c[i]) and not any([common_filtering(c[j]) for j in get_children(h, i)]) + +def no_square_children_and_square(h, c, i): + return filter_square(c[i]) and not any([filter_square(c[j]) for j in get_children(h, i)]) + + + def print_contour_stats(img, c, color): ratio = img.shape[0] / float(img.shape[0]) c = c.astype("float") @@ -75,13 +119,13 @@ def print_contour_stats(img, c, color): M = cv2.moments(c) cX = int((M["m10"] / max(M["m00"], 0.001)) * ratio) cY = int((M["m01"] / max(M["m00"], 0.001)) * ratio) - cv2.putText(img,str(cv2.contourArea(c)),(cX-20,cY-20),cv2.FONT_HERSHEY_SIMPLEX, 0.5, color,2) + cv2.putText(img,str(cv2.contourArea(c)),(cX-40,cY-25),cv2.FONT_HERSHEY_SIMPLEX, 0.5, color,1) perimeter = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.03 * perimeter, True) - cv2.putText(img, str(len(approx)),(cX-20,cY-10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, color,2) + cv2.putText(img, str(len(approx)),(cX-40,cY-15),cv2.FONT_HERSHEY_SIMPLEX, 0.5, color,1) @@ -90,7 +134,7 @@ class image_converter: def __init__(self): img_tpc = "/rgb/image_raw" - self.image_pub = rospy.Publisher("img_proc/contours_stats", Image, queue_size=10) + self.image_pub = rospy.Publisher("/ttt/img_proc/contours_stats", Image, queue_size=10) self.pub = rospy.Publisher("/ttt/coords",PiecesCoords, queue_size=10) self.image_sub = rospy.Subscriber(img_tpc, Image, self.img_callback) self.bridge = CvBridge() @@ -103,17 +147,33 @@ class image_converter: gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - blur = cv2.GaussianBlur(gray, (5, 5), 0) + blur = cv2.medianBlur(gray,5) + blur = cv2.GaussianBlur(gray,(7,3),0) + blur = cv2.bilateralFilter(gray, 13, 25, 25) - (ret, thresh) = cv2.threshold(blur, 100, 250, cv2.THRESH_BINARY) + thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 5) + thresh1 = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR) ratio = img.shape[0] / float(img.shape[0]) - (im2, contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) + (im2, contours, hierarchy) = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + + #[cells, c1] = filter_contours(contours, filter_square) + #[circles, c2] = filter_contours(c1, filter_circle) + #[crosses, c3] = filter_contours(c2, filter_cross) + + h = hierarchy[0] + + cells = [] + circles = [] + crosses = [] + + roots = [i for i in range(len(h)) if h[i][3] == -1 ] - [cells, c1] = filter_contours(contours, filter_cell) - [circles, c2] = filter_contours(c1, filter_circle) - [crosses, c3] = filter_contours(c2, filter_cross) + for i in roots: + cells = cells + filter_hierarchy(h, contours, no_square_children_and_square, i) + circles = circles + filter_hierarchy(h, contours, no_children_and_circle, i) + crosses = crosses + filter_hierarchy(h, contours, no_children_and_cross, i) self.msg = PiecesCoords() @@ -122,7 +182,7 @@ class image_converter: self.msg.pieces = self.msg.pieces + [LabeledPoint(find_center_point(c, ratio), "X") for c in crosses] - self.msg.cells = sorted(self.msg.cells, key=lambda p: p.x + 100*p.y) + self.msg.cells = sorted(self.msg.cells, key=lambda p: p.x + 1000*p.y) [print_contour_stats(img, c, (255,0,0)) for c in cells] [print_contour_stats(img, c, (0,255,0)) for c in circles]