def test_set_pen_color_1(self):
     drawing = Drawing(1920, 1080)
     color = np.array([120, 150, 150])
     drawing.set_pen_color(color)
     color = cv2.cvtColor(np.array([[color]], dtype="uint8"), cv2.COLOR_BGR2HSV)[0, 0]
     assert np.array_equal(drawing.pen_color_range[0], color - drawing.d_color_range)
     assert np.array_equal(drawing.pen_color_range[1], color + drawing.d_color_range)
 def test_process_frame_action_changed(self):
     drawing = Drawing(1920, 1080)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=5, y=5, area=200, action="Yellow")
     drawing.process_frame(frame=frame, x=10, y=10, area=200, action="Blue")
     assert drawing.ex_action == "Blue"
     assert drawing.ex_pen_pos == (1930, 1090)
class TestDrawingMove:
    def setup(self):
        self.width = 1920
        self.height = 1080
        self.drawing = Drawing(self.width, self.height)

    def test_normal_move(self):
        oldpos = self.drawing.view_corner
        dx = -10
        dy = -10
        speed = 2.5
        self.drawing.move(dx, dy, speed)
        newpos = self.drawing.view_corner
        assert oldpos[0] - speed * dx == newpos[0]
        assert oldpos[1] - speed * dy == newpos[1]

    def test_move_top_left(self):
        self.drawing.view_corner = 0, 0
        oldpos = self.drawing.view_corner
        dx = 10
        dy = 10
        speed = 2.5
        self.drawing.move(dx, dy, speed)
        newpos = self.drawing.view_corner
        assert newpos[0] == oldpos[0]
        assert newpos[1] == oldpos[1]

    def test_move_top_right(self):
        self.drawing.view_corner = 3 * self.drawing.W, 0
        oldpos = self.drawing.view_corner
        dx = -10
        dy = -10
        speed = 2.5
        self.drawing.move(dx, dy, speed)
        newpos = self.drawing.view_corner
        assert newpos[0] == oldpos[0]
        assert newpos[1] == oldpos[1] - speed * dy

    def test_move_bottom_left(self):
        self.drawing.view_corner = 0, 3 * self.drawing.H
        oldpos = self.drawing.view_corner
        dx = -10
        dy = -10
        speed = 2.5
        self.drawing.move(dx, dy, speed)
        newpos = self.drawing.view_corner
        assert newpos[0] == oldpos[0] - speed * dy
        assert newpos[1] == oldpos[1]

    def test_move_bottom_right(self):
        self.drawing.view_corner = 3 * self.drawing.W, 3 * self.drawing.H
        oldpos = self.drawing.view_corner
        dx = -10
        dy = -10
        speed = 2.5
        self.drawing.move(dx, dy, speed)
        newpos = self.drawing.view_corner
        assert newpos[0] == oldpos[0]
        assert newpos[1] == oldpos[1]
 def test_draw_after_color_erase_drawn(self):
     drawing = Drawing(1920, 1080)
     ma = MotionAnalyser(1080, 1920, drawing)
     ma.analyse((0, 0), 5)
     ma.analyse((0, 300), 5)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=300, y=300, area=196, action="Green")
     drawing.process_frame(frame=frame, x=300, y=300, area=196, action="Green")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Green")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Erasing")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Erasing")
     drawing.process_frame(frame=frame, x=300, y=300, area=196, action="Erasing")
     for x in range(300, 400):
         assert (drawing.canvas[x + 330, x + 1920] == np.array([0, 0, 0])).all()
 def test_analyse_gesture_same_in_motion(self):
     # Setup
     width = 1920
     height = 1080
     pos_1 = 0, 0
     pos_2 = 1, 6
     pos_3 = 5, 4
     pos_4 = 2, 4
     pos_5 = 11, 0
     gesture = 1
     drawing = Drawing(width, height)
     ma = MotionAnalyser(width, height, drawing)
     ma.analyse(pos_1, gesture)
     ma.analyse(pos_2, gesture)
     ma.analyse(pos_3, gesture)
     ma.analyse(pos_4, gesture)
     ma.analyse(pos_5, gesture)
     exp_gesture = gesture
     exp_pos = pos_5
     exp_total_dx = 11
     exp_total_dy = 0
     assert exp_gesture == ma.ex_gesture
     assert exp_pos == pytest.approx(ma.ex_pos)
     assert round(abs(exp_total_dx - ma.total_dx), 7) == 0
     assert round(abs(exp_total_dy - ma.total_dy), 7) == 0
 def test_draw_after_color_green_to_blue(self):
     drawing = Drawing(1920, 1080)
     ma = MotionAnalyser(1080, 1920, drawing)
     ma.analyse((0, 0), 5)
     ma.analyse((0, 300), 5)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=300, y=300, area=196, action="Green")
     drawing.process_frame(frame=frame, x=300, y=300, area=196, action="Green")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Green")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Blue")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Blue")
     drawing.process_frame(frame=frame, x=350, y=350, area=196, action="Blue")
     for x in range(300, int(350 - 14 / math.sqrt(2))):
         assert (drawing.canvas[x + 330, x + 1920] == np.array([0, 255, 0])).all()
     for x in range(int(350 - 14 / math.sqrt(2)) + 1, 400):
         assert (drawing.canvas[x + 330, x + 1920] == np.array([255, 0, 0])).all()
 def test_mr_sd(self):
     drawing = Drawing(1920, 1080)
     ma = MotionAnalyser(1080, 1920, drawing)
     ma.analyse((0, 1000), 5)
     ma.analyse((500, 1000), 5)
     ma.analyse((0, 0), 0)
     ma.analyse((0, 216), 0)
     print(drawing.view_corner)
     assert drawing.view_corner == (670, 1080)
 def test_process_frame_no_previous_pen(self):
     drawing = Drawing(1920, 1080)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=None, y=None, area=None, action="Blue")
     drawing.process_frame(frame=frame, x=10, y=10, area=200, action="Blue")
     print(drawing.ex_pen_pos)
     assert drawing.ex_pen_pos == (1930, 1090)
 def test_process_frame_general_blue(self):
     drawing = Drawing(1920, 1080)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=300, y=300, area=200, action="Blue")
     drawing.process_frame(frame=frame, x=300, y=300, area=200, action="Blue")
     drawing.process_frame(frame=frame, x=400, y=400, area=200, action="Blue")
     for x in range(300, 400):
         assert drawing.canvas[x + 1080, x + 1920].all() == np.array([255, 0, 0]).all()
 def test_process_frame_general_yellow(self):
     drawing = Drawing(1920, 1080)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=300, y=300, area=200, action="Yellow")
     drawing.process_frame(frame=frame, x=300, y=300, area=200, action="Yellow")
     drawing.process_frame(frame=frame, x=300, y=400, area=200, action="Yellow")
     for y in range(300, 400):
         assert drawing.canvas[300 + 1080, y + 1920].all() == np.array([0, 255, 255]).all()
 def test_analyse_gesture_change_on_start(self):
     # Setup
     width = 1920
     height = 1080
     pos = 0, 0
     gesture = 1
     drawing = Drawing(width, height)
     ma = MotionAnalyser(width, height, drawing)
     ma.analyse(pos, gesture)
     exp_gesture = gesture
     exp_pos = pos
     exp_total_dx = 0
     exp_total_dy = 0
     assert exp_gesture == ma.ex_gesture
     assert exp_pos == pytest.approx(ma.ex_pos)
     assert round(abs(exp_total_dx - ma.total_dx), 7) == 0
     assert round(abs(exp_total_dy - ma.total_dy), 7) == 0
    def test_same_gesture_brush(self):
        drawing = Drawing(1920, 1080)
        frame = np.zeros((1080, 1920, 3), dtype="uint8")

        # Frame 1
        drawing.process_frame(frame=frame, x=100, y=100, area=2, action="Blue")
        drawing.process_frame(frame=frame, x=100, y=100, area=2, action="Blue")
        # Frame 2
        drawing.process_frame(frame=frame, x=100, y=100, area=2, action="Blue")

        assert (drawing.canvas[1080 + 100, 1920 + 100] == np.array([255, 0,
                                                                    0])).all()
 def test_analyse_gesture_none(self):
     # Setup
     width = 1920
     height = 1080
     pos = 1.23, 3.55
     gesture = None
     drawing = Drawing(width, height)
     ma = MotionAnalyser(width, height, drawing)
     ma.analyse(pos, gesture)
     ma.analyse(pos, gesture)
     exp_gesture = gesture
     exp_pos = 0, 0
     exp_total_dx = 0
     exp_total_dy = 0
     assert exp_gesture == ma.ex_gesture
     assert exp_pos == pytest.approx(ma.ex_pos)
     assert round(abs(exp_total_dx - ma.total_dx), 7) == 0
     assert round(abs(exp_total_dy - ma.total_dy), 7) == 0
    def test_none_gesture_brush(self):
        drawing = Drawing(1920, 1080)
        frame = np.zeros((1080, 1920, 3), dtype="uint8")

        # Frame 1
        drawing.process_frame(frame=frame,
                              x=None,
                              y=None,
                              area=None,
                              action=None)
        drawing.process_frame(frame=frame,
                              x=None,
                              y=None,
                              area=None,
                              action=None)
        # Frame 2
        drawing.process_frame(frame=frame,
                              x=None,
                              y=None,
                              area=None,
                              action=None)

        assert (drawing.canvas == np.array([0, 0, 0])).all()
 def test_analyse_gesture_change(self):
     # Setup
     width = 1920
     height = 1080
     pos = 0, 0
     gesture_1 = 1
     gesture_2 = 2
     gesture_3 = 3
     drawing = Drawing(width, height)
     ma = MotionAnalyser(width, height, drawing)
     ma.analyse(pos, gesture_1)
     ma.analyse(pos, gesture_1)
     ma.analyse(pos, gesture_2)
     ma.analyse(pos, gesture_2)
     ma.analyse(pos, gesture_1)
     ma.analyse(pos, gesture_3)
     exp_gesture = gesture_3
     exp_pos = pos
     exp_total_dx = pos[0]
     exp_total_dy = pos[0]
     assert exp_gesture == ma.ex_gesture
     assert exp_pos == pytest.approx(ma.ex_pos)
     assert round(abs(exp_total_dx - ma.total_dx), 7) == 0
     assert round(abs(exp_total_dy - ma.total_dy), 7) == 0
 def test_draw_after_scaling_down(self):
     drawing = Drawing(1920, 1080)
     ma = MotionAnalyser(1080, 1920, drawing)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     ma.analyse((0, 216), 0)
     drawing.process_frame(frame=frame,
                           x=None,
                           y=None,
                           area=None,
                           action="Green")
     ma.analyse((0, 0), 0)
     drawing.process_frame(frame=frame,
                           x=None,
                           y=None,
                           area=None,
                           action="Green")
     print(drawing.view_corner, drawing.scale_factor)
     drawing.process_frame(frame=frame,
                           x=300,
                           y=300,
                           area=200,
                           action="Blue")
     drawing.process_frame(frame=frame,
                           x=300,
                           y=300,
                           area=200,
                           action="Blue")
     drawing.process_frame(frame=frame,
                           x=400,
                           y=400,
                           area=200,
                           action="Blue")
     print(np.where(drawing.canvas > 0))
     for x in range(300, 400):
         assert (drawing.canvas[int(x * 0.5 + 1080),
                                int(x * 0.5 + 1920)] == np.array(
                                    [255, 0, 0])).all()
 def setup(self):
     self.width = 1920
     self.height = 1080
     self.drawing = Drawing(self.width, self.height)
 def test_scale_out_of_bounds_high(self):
     drawing = Drawing(1920, 1080)
     drawing.scale_factor = 3
     drawing.scale(10)
     assert drawing.scale_factor == 3
 def test_scale_down(self):
     drawing = Drawing(1920, 1080)
     drawing.scale(- 1080 / 10)
     assert drawing.scale_factor == 0.75
 def test_scale_up(self):
     drawing = Drawing(1920, 1080)
     drawing.scale(1080 / 10)
     assert drawing.scale_factor == 1.25
 def test_set_pen_color_edge(self):
     drawing = Drawing(1920, 1080)
     color = np.array([0, 0, 0])
     drawing.set_pen_color(color)
     assert np.array_equal(drawing.pen_color_range[0], np.zeros(3))
     assert np.array_equal(drawing.pen_color_range[1], color + drawing.d_color_range)
 def test_process_frame_no_pen(self):
     drawing = Drawing(1920, 1080)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=None, y=None, area=None, action=None)
     assert drawing.ex_action is None
     assert drawing.ex_pen_pos == (0, 0)
 def test_draw_after_moving_up(self):
     drawing = Drawing(1920, 1080)
     ma = MotionAnalyser(1080, 1920, drawing)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     ma.analyse((0, 300), 5)
     drawing.process_frame(frame=frame,
                           x=None,
                           y=None,
                           area=None,
                           action="Erasing")
     ma.analyse((0, 0), 5)
     drawing.process_frame(frame=frame,
                           x=None,
                           y=None,
                           area=None,
                           action="Erasing")
     print(drawing.view_corner)
     drawing.process_frame(frame=frame,
                           x=300,
                           y=300,
                           area=200,
                           action="Blue")
     drawing.process_frame(frame=frame,
                           x=300,
                           y=300,
                           area=200,
                           action="Blue")
     drawing.process_frame(frame=frame,
                           x=400,
                           y=400,
                           area=200,
                           action="Blue")
     for x in range(300, 400):
         print(np.array([255, 0, 0]).all())
         assert (drawing.canvas[x + 1830, x + 1920] == np.array([255, 0,
                                                                 0])).all()
 def test_scale_out_of_bounds_low(self):
     drawing = Drawing(1920, 1080)
     drawing.scale_factor = 0.5
     drawing.scale(-10)
     assert drawing.scale_factor == 0.5
 def test_scale_near_canvas_bound(self):
     drawing = Drawing(1920, 1080)
     drawing.view_corner = (1920 * 2, 1080 * 2)
     drawing.scale(1080 / 10)
     assert drawing.view_corner == (3360, 1890)
def main_cam(phone_cam,
             video_path=None,
             imgs_paths=None,
             default_pen_color=None):
    cap, fps = init_cam(phone_cam, video_path, imgs_paths)
    fps_count = 0.0
    W = cap.get(3)
    H = cap.get(4)
    drawing = Drawing(W, H, default_pen_color)
    ma = MotionAnalyser(W, H, drawing)
    logger = Logger(drawing, ma)
    mp_hands = mp.solutions.hands
    detector = mp_hands.Hands(min_detection_confidence=0.7,
                              min_tracking_confidence=0.5)
    pairs = {
        3: "Yellow",
        5: "Erasing",
        0: "Green",
        2: "Brown",
        1: "Blue",
        4: "Black"
    }
    cv2.namedWindow("Cam", cv2.WINDOW_NORMAL)
    cv2.setWindowProperty("Cam", cv2.WND_PROP_FULLSCREEN, 1)

    n_skipped_frames = 0

    while True:
        frame = cap.read()
        if isinstance(frame, tuple):
            frame = frame[1]
        if frame is None or frame.size == 0:
            n_skipped_frames += 1
            print("Skipped", n_skipped_frames)
            if n_skipped_frames == 90:
                print("End of sequence")
                break
            continue
        frame = cv2.flip(frame, 1)
        cv2.setMouseCallback('Cam', callback, (drawing, frame))
        n_fingers_l, center_l = count_fingers(frame, detector)
        x, y, area = drawing.find_pen(frame)
        if x is None:  # no pen in frame
            ma.analyse(center_l, n_fingers_l)

        if n_fingers_l is not None:
            action = pairs[n_fingers_l]
            text = action + " (" + str(n_fingers_l) + ") "
        else:
            action = None
            text = "None "

        frame = drawing.process_frame(frame, x, y, area, action)
        cv2.putText(frame,
                    text=text + str(x),
                    org=(30, 100),
                    fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                    fontScale=2,
                    color=(0, 255, 20),
                    thickness=3)
        fps.update()
        if fps._numFrames == 25:
            fps.stop()
            fps_count = fps.fps()
            fps = FPS().start()
        cv2.putText(frame,
                    text=str(round(fps_count, 1)),
                    org=(1750, 50),
                    fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                    fontScale=2,
                    color=(0, 255, 20),
                    thickness=3)
        cv2.putText(frame,
                    text=str(round(drawing.scale_factor, 2)),
                    org=(1750, 1000),
                    fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                    fontScale=2,
                    color=(0, 255, 20),
                    thickness=3)

        cv2.imshow('Cam', frame)
        logger.log(n_fingers_l, center_l, (x, y), area)
        if cv2.waitKey(1) & 0xFF == 27:
            break

    cv2.destroyAllWindows()
    return logger
 def test_draw_after_color_green_then_blue_and_cross_black(self):
     drawing = Drawing(1920, 1080)
     ma = MotionAnalyser(1080, 1920, drawing)
     ma.analyse((0, 0), 5)
     ma.analyse((0, 300), 5)
     frame = np.zeros((1080, 1920, 3), dtype="uint8")
     drawing.process_frame(frame=frame, x=300, y=300, area=196, action="Green")
     drawing.process_frame(frame=frame, x=300, y=300, area=196, action="Green")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Green")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Blue")
     drawing.process_frame(frame=frame, x=400, y=400, area=196, action="Blue")
     drawing.process_frame(frame=frame, x=350, y=350, area=196, action="Blue")
     drawing.process_frame(frame=frame, x=400, y=300, area=196, action="Black")
     drawing.process_frame(frame=frame, x=400, y=300, area=196, action="Black")
     drawing.process_frame(frame=frame, x=300, y=400, area=196, action="Black")
     # cross top-left part
     for x in range(300, int(350 - 14 / math.sqrt(2))):
         assert (drawing.canvas[x + 330, x + 1920] == np.array([0, 255, 0])).all(), x
     # cross intersection part
     for x in range(int(350 - 14 / math.sqrt(2)) + 1, int(350 + 14 / math.sqrt(2))):
         assert (drawing.canvas[x + 330, x + 1920] == np.array([255, 255, 255])).all(), x
     # after cross intersection, must be same as topleft
     for x in range(int(350 + 14 / math.sqrt(2)) + 2, 400):
         assert (drawing.canvas[x + 330, x + 1920] == np.array([255, 0, 0])).all(), x