From 9bad84fff9ff73da36571ef29420250552d5ceb1 Mon Sep 17 00:00:00 2001 From: Quentin Bolsee <quentinbolsee@hotmail.com> Date: Thu, 14 Dec 2023 15:56:27 -0500 Subject: [PATCH] machine code --- host/config.json | 4 +- host/filtering.py | 75 ++++++++++++++++++++++---- host/img/plotting.png | Bin 0 -> 8801 bytes host/img/processing.png | Bin 0 -> 8379 bytes host/machine.py | 77 ++++++++++++++++---------- host/main.py | 54 +++++++++++++++++-- host/test/polys.obj | Bin 0 -> 53544 bytes host/test/polys_np_keep.obj | Bin 0 -> 32070 bytes host/{ => test}/test.png | Bin host/test/test_prune.py | 104 ++++++++++++++++++++++++++++++++++++ 10 files changed, 269 insertions(+), 45 deletions(-) create mode 100644 host/img/plotting.png create mode 100644 host/img/processing.png create mode 100644 host/test/polys.obj create mode 100644 host/test/polys_np_keep.obj rename host/{ => test}/test.png (100%) create mode 100644 host/test/test_prune.py diff --git a/host/config.json b/host/config.json index 565ee1f..bd635ae 100644 --- a/host/config.json +++ b/host/config.json @@ -6,7 +6,9 @@ "yes_no": "img/yes_no.png", "3": "img/3.png", "2": "img/2.png", - "1": "img/1.png" + "1": "img/1.png", + "processing": "img/processing.png", + "plotting": "img/plotting.png" }, "ports": { "solenoid": "4150325537323119", diff --git a/host/filtering.py b/host/filtering.py index 5c7ce0b..ae58e3b 100644 --- a/host/filtering.py +++ b/host/filtering.py @@ -26,8 +26,7 @@ def bf(img): return edges -def stroke(img): - img_copy = np.ones_like(img)*255 +def get_polylines(img, min_length=5.0, n_max=200): img2 = bf(img) img_float = img2.astype(np.float32) / 255.0 img_binary = img_float > 0.5 @@ -40,13 +39,49 @@ def stroke(img): rects = [] polys = trace_skeleton_old.traceSkeleton(im, 0, 0, im.shape[1], im.shape[0], 10, 999, rects) + polys = [np.array(x, dtype=np.float32) for x in polys] + + polys_length_keep = [] + for line in polys: + deltas = line[1:] - line[:-1] + length = np.sum(np.linalg.norm(deltas, axis=1)) + if length >= min_length: + polys_length_keep.append([line, length]) + + polys_length_keep = sorted(polys_length_keep, key=lambda x: x[1])[::-1] + polys_length_keep = polys_length_keep[:n_max] + + polys_keep = [x[0] for x in polys_length_keep] + return polys_keep + + +def draw_polylines(img, polys): for l in polys: - # c = (200 * random.random(), 200 * random.random(), 200 * random.random()) for i in range(0, len(l) - 1): - # cv2.line(img_copy, (l[i][0], l[i][1]), (l[i + 1][0], l[i + 1][1]), c) - cv2.line(img_copy, (l[i][0], l[i][1]), (l[i + 1][0], l[i + 1][1]), (0, 0, 0)) + cv2.line(img, (int(l[i][0]), int(l[i][1])), (int(l[i + 1][0]), int(l[i + 1][1])), (0, 0, 0), 2) + + +def scale_offset_polylines(polys, img_w, img_h, mm_w, offset): + scale = mm_w / img_w + + polys_new = [np.copy(x) for x in polys] - return img_copy, polys + polys_new = sorted(polys_new, key=lambda x: -x[0, 1]) + + for i in range(len(polys)): + # flip + polys_new[i][:, 1] = img_h - polys_new[i][:, 1] + # zero center + polys_new[i][:, 0] -= img_w/2 + polys_new[i][:, 1] -= img_h/2 + # scale to mm + polys_new[i][:, :] *= scale + + # offset + polys_new[i][:, 0] += offset[0] + polys_new[i][:, 1] += offset[1] + + return polys_new if __name__ == "__main__": @@ -59,10 +94,30 @@ if __name__ == "__main__": # plt.plot(cnt[:, 0], cnt[:, 1]) # plt.show() # # print(contours[0]) - img = cv2.imread("test.png", cv2.IMREAD_UNCHANGED) + img = cv2.imread("test/test.png", cv2.IMREAD_UNCHANGED) img = img[:, :, :3] + h, w, _ = img.shape # img_copy = np.copy(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))*0 - img_stroke, polys = stroke(img) + polys = get_polylines(img) + img_draw = 255*np.ones((h, w, 3), dtype=np.uint8) + draw_polylines(img_draw, polys) + + lines = scale_offset_polylines(polys, w, h, 100, (130, 118)) + + import matplotlib.pyplot as plt + + plt.figure() + plt.imshow(img_draw) + + plt.figure() + for xy in lines: + plt.plot(xy[:, 0], xy[:, 1]) + plt.axis("equal") + plt.show() + + # import pickle + # with open("test/polys.obj", "wb") as f: + # pickle.dump(polys, f) - cv2.imshow("test", img_stroke) - cv2.waitKey(0) + # cv2.imshow("test", img_stroke) + # cv2.waitKey(0) diff --git a/host/img/plotting.png b/host/img/plotting.png new file mode 100644 index 0000000000000000000000000000000000000000..5583954622eb3ca7568c7dd379a9add5f29aea5a GIT binary patch literal 8801 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 AI{*Lx literal 0 HcmV?d00001 diff --git a/host/img/processing.png b/host/img/processing.png new file mode 100644 index 0000000000000000000000000000000000000000..cc633c34cfda44a3f52f8e322be2c96e1d8d944f GIT binary patch literal 8379 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 literal 0 HcmV?d00001 diff --git a/host/machine.py b/host/machine.py index b39c3d0..63ca139 100644 --- a/host/machine.py +++ b/host/machine.py @@ -9,7 +9,7 @@ home_rate = 60 home_accel = 2000 home_backoff_time = 0.2 -go_rate = 150 +go_rate = 180 go_accel = 2000 use_current = 0.4 @@ -35,25 +35,6 @@ class Machine: self.x_top_motor.set_current(use_current) def home(self): - # home Y .... - # if we're on the switch, backoff: - if self.y_motor.get_states()['limit'] > 0: - self.y_motor.set_target_velocity(home_rate, home_accel) - time.sleep(home_backoff_time) - self.y_motor.set_target_velocity(0, home_accel) - time.sleep(home_backoff_time) - - # let's home it, - self.y_motor.set_target_velocity(-home_rate, home_accel) - - # then check-wait on states, - while True: - states = self.y_motor.get_states() - if states['limit'] > 0: - break - - self.y_motor.set_target_velocity(0, home_accel) - # home X ... if self.x_bottom_motor.get_states()['limit'] > 0: self.x_bottom_motor.set_target_velocity(home_rate, home_accel) @@ -75,6 +56,25 @@ class Machine: self.x_top_motor.set_target_velocity(0, home_accel) time.sleep(home_backoff_time) + # home Y .... + # if we're on the switch, backoff: + if self.y_motor.get_states()['limit'] > 0: + self.y_motor.set_target_velocity(home_rate, home_accel) + time.sleep(home_backoff_time) + self.y_motor.set_target_velocity(0, home_accel) + time.sleep(home_backoff_time) + + # let's home it, + self.y_motor.set_target_velocity(-home_rate, home_accel) + + # then check-wait on states, + while True: + states = self.y_motor.get_states() + if states['limit'] > 0: + break + + self.y_motor.set_target_velocity(0, home_accel) + # set zeroes, self.x_bottom_motor.set_position(0) self.x_top_motor.set_position(0) @@ -128,15 +128,34 @@ if __name__ == "__main__": m.goto(0, origin[1]) m.goto(origin[0], origin[1]) - w = 25 - h = 25 + # w = 35 + # h = 35 + # + # m.goto(origin[0]+w, origin[1]+h) + # m.pen_action(2, True) + # m.goto(origin[0]-w, origin[1]+h) + # m.goto(origin[0]-w, origin[1]-h) + # m.goto(origin[0]+w, origin[1]-h) + # m.goto(origin[0]+w, origin[1]+h) + # m.pen_action(2, False) + # m.goto(0, origin[1]) + # m.goto(0, 0) + + import pickle + + with open("test/polys_np_keep.obj", "rb") as f: + data = pickle.load(f) + + for line, _ in data: + m.goto(line[0, 0], line[0, 1]) + m.pen_action(2, True) + m.goto_list(line[:, 0], line[:, 1]) + m.pen_action(2, False) + # for x, y in line: + # print(x, y) - m.goto(origin[0]+w, origin[1]+h) - m.pen_action(2, True) - m.goto(origin[0]-w, origin[1]+h) - m.goto(origin[0]-w, origin[1]-h) - m.goto(origin[0]+w, origin[1]-h) - m.goto(origin[0]+w, origin[1]+h) - m.pen_action(2, False) + m.goto(origin[0], origin[1]) m.goto(0, origin[1]) m.goto(0, 0) + + # print(data) diff --git a/host/main.py b/host/main.py index 757d687..f408f2a 100644 --- a/host/main.py +++ b/host/main.py @@ -5,6 +5,7 @@ import json import time import datetime import filtering +import machine STATE_INIT = 0 STATE_STREAM = 1 @@ -30,6 +31,8 @@ class MainApplication: self.rotate = rotate self.t_state = 0 self.dt_state = 0 + self.strokes = None + self.machine = None cv2.imshow("main", self.img) cv2.setMouseCallback("main", self.on_click) @@ -97,11 +100,46 @@ class MainApplication: else: self.state = STATE_STREAM elif self.state == STATE_VECTORIZED: - img_strokes, strokes = filtering.stroke(self.img_captured) - - self.img = img_strokes - self.state = STATE_DRAWING - # self.running = False + if self.dt_state < 0.5: + self.img = np.zeros((self.height, self.width, 3), dtype=np.uint8) + overlay = "processing" + else: + if self.strokes is None: + polys = filtering.get_polylines(self.img_captured) + img_draw = 255 * np.ones((self.height, self.width, 3), dtype=np.uint8) + filtering.draw_polylines(img_draw, polys) + self.strokes = filtering.scale_offset_polylines(polys, + self.width, + self.height, + 100, + machine.origin) + self.img = np.copy(img_draw) + overlay = "yes_no" + if self.click is not None: + x, y = self.click + self.click = None + if x < self.width // 2: + self.state = STATE_DRAWING + else: + self.state = STATE_STREAM + elif self.state == STATE_DRAWING: + if self.dt_state < 0.5: + self.img = np.zeros((self.height, self.width, 3), np.uint8) + overlay = "plotting" + else: + if self.strokes is not None and self.machine is not None: + self.machine.goto(0, machine.origin[1]) + self.machine.goto(machine.origin[0], machine.origin[1]) + for line in self.strokes: + self.machine.goto(line[0, 0], line[0, 1]) + self.machine.pen_action(2, True) + self.machine.goto_list(line[:, 0], line[:, 1]) + self.machine.pen_action(2, False) + self.machine.goto(machine.origin[0], machine.origin[1]) + self.machine.goto(0, machine.origin[1]) + self.machine.goto(0, 0) + self.strokes = None + self.state = STATE_STREAM self.show(overlay=overlay) if self.state != previous_state: @@ -131,7 +169,12 @@ class MainApplication: def main(): with open("config.json", "r") as f: config = json.load(f) + + m = machine.Machine(config["ports"]) + m.pen_action(2, False) + m.home() app = MainApplication(fullscreen=config["fullscreen"], rotate=config["rotate"]) + app.machine = m app.load_overlays(config["overlays"]) app.run() app.video.release() @@ -140,3 +183,4 @@ def main(): if __name__ == "__main__": main() ++ \ No newline at end of file diff --git a/host/test/polys.obj b/host/test/polys.obj new file mode 100644 index 0000000000000000000000000000000000000000..6071ce638da07f83ad167efc0b4be66b6b8ddbcc GIT binary patch literal 53544 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 literal 0 HcmV?d00001 diff --git a/host/test/polys_np_keep.obj b/host/test/polys_np_keep.obj new file mode 100644 index 0000000000000000000000000000000000000000..5b96882813f09081c65cfe2ec4e9b5378595c84f GIT binary patch literal 32070 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 literal 0 HcmV?d00001 diff --git a/host/test.png b/host/test/test.png similarity index 100% rename from host/test.png rename to host/test/test.png diff --git a/host/test/test_prune.py b/host/test/test_prune.py new file mode 100644 index 0000000..2be1e60 --- /dev/null +++ b/host/test/test_prune.py @@ -0,0 +1,104 @@ +import pickle +import cv2 +import numpy as np +import matplotlib.pyplot as plt + + +def process_polylines(polylines, img_w, img_h, mm_w, offset): + polys_np_keep = [] + for line in polylines: + deltas = line[1:] - line[:-1] + length = np.sum(np.linalg.norm(deltas, axis=1)) + if length > 5.0: + polys_np_keep.append([line, length]) + + polys_np_keep = sorted(polys_np_keep, key=lambda x : x[1])[::-1] + + n_max = 200 + + scale = mm_w / img_w + + polys_np_keep = polys_np_keep[:n_max] + + for i in range(len(polys_np_keep)): + # flip + polys_np_keep[i][0][:, 1] = img_h - polys_np_keep[i][0][:, 1] + # zero center + polys_np_keep[i][0][:, 0] -= img_w/2 + polys_np_keep[i][0][:, 1] -= img_h/2 + # scale to mm + polys_np_keep[i][0][:, :] *= scale + polys_np_keep[i][1] *= scale + + # offset + polys_np_keep[i][0][:, 0] += offset[0] + polys_np_keep[i][0][:, 1] += offset[1] + + return polys_np_keep + +""" +def main(): + with open("polys.obj", "rb") as f: + polys = pickle.load(f) + + img = cv2.imread("test.png", cv2.IMREAD_UNCHANGED) + polys_np = [np.array(x, dtype=np.float32) for x in polys] + print(polys_np[0].shape) + polys_np_keep = [] + # lengths = [] + for line in polys_np: + deltas = line[1:] - line[:-1] + length = np.sum(np.linalg.norm(deltas, axis=1)) + if length > 5.0: + polys_np_keep.append([line, length]) + + polys_np_keep = sorted(polys_np_keep, key=lambda x : x[1])[::-1] + + n_max = 200 + + polys_np_keep = polys_np_keep[:n_max] + + h, w, _ = img.shape + # for line in + + print(w, h) + + # mm per px + scale = 100 / w + offset = (130, 118) + # offset = (0, 0) + + for i in range(len(polys_np_keep)): + # flip + polys_np_keep[i][0][:, 1] = h - polys_np_keep[i][0][:, 1] + # zero center + polys_np_keep[i][0][:, 0] -= w/2 + polys_np_keep[i][0][:, 1] -= h/2 + # scale to mm + polys_np_keep[i][0][:, :] *= scale + polys_np_keep[i][1] *= scale + + # offset + polys_np_keep[i][0][:, 0] += offset[0] + polys_np_keep[i][0][:, 1] += offset[1] + + # for line, length in polys_np_keep: + # plt.plot(line[:, 0], -line[:, 1]) + # + # # print(polys_np_keep[:50]) + plt.figure() + for line, _ in polys_np_keep: + plt.plot(line[:, 0], line[:, 1]) + # plt.hist(lengths, bins=np.linspace(0, 160, 64)) + plt.axis("equal") + plt.show() + + polys_np_keep = sorted(polys_np_keep, key=lambda x: x[0][0, 1]) + + with open("polys_np_keep.obj", "wb") as f: + pickle.dump(polys_np_keep, f) +""" + + +# if __name__ == "__main__": +# main() -- GitLab