def color(filename):

    try:
        if filename:
            file_as_string = []
            with open(filename, 'r') as fh:
                rgb = ''.join(fh.readlines())

        scan_data_str_keys = json_loads(rgb)
        scan_data = {}

        for (key, value) in scan_data_str_keys.items():
            scan_data[int(key)] = value

        square_count = len(scan_data.keys())
        square_count_per_side = int(square_count / 6)
        width = int(sqrt(square_count_per_side))

        cube = RubiksColorSolverGeneric(width)
        cube.enter_scan_data(scan_data)
        cube.crunch_colors()

        print(''.join(cube.cube_for_kociemba_strict()))
        with open('scramble.txt', 'w') as f:
            print >> f, ''.join(cube.cube_for_kociemba_strict())

    except Exception as e:
        pass
예제 #2
0
    def scan(self):
        log.info("scan()")
        self.colors = {}
        self.k = 0
        self.scan_face(1)

        self.flip()
        self.scan_face(2)

        self.flip()
        self.scan_face(3)

        self.rotate_cube(-1, 1)
        self.flip()
        self.scan_face(4)

        self.rotate_cube(1, 1)
        self.flip()
        self.scan_face(5)

        self.flip()
        self.scan_face(6)

        if self.shutdown:
            return

        write_text('Züge', 'berechnen...')

        log.info("RGB json:\n%s\n" % json.dumps(self.colors))
        self.rgb_solver = RubiksColorSolverGeneric(3)
        self.rgb_solver.enter_scan_data(self.colors)
        self.rgb_solver.crunch_colors()
        self.cube_kociemba = self.rgb_solver.cube_for_kociemba_strict()
        log.info("Final Colors (kociemba): %s" % ''.join(self.cube_kociemba))

        # This is only used if you want to rotate the cube so U is on top, F is
        # in the front, etc. You would do this if you were troubleshooting color
        # detection and you want to pause to compare the color pattern on the
        # cube vs. what we think the color pattern is.
        '''
예제 #3
0
def CubeScan():

    #return 'DRLUUBFBRBLURRLRUBLRDDFDLFUFUFFDBRDUBRUFLLFDDBFLUBLRBD'
    #return 'UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB'
    #return 'UUUUUUUUULLLLLLLLLFFFFFFFFFRRRRRRRRRBBBBBBBBBDDDDDDDDD'

    #data = json.loads(str)
    data = {}
    # F,R,B,L,U,D
    #  (letters stand for Up, Left, Front, Right, Back, and Down)
    #for (side_index, side_name) in enumerate(('U', 'R', 'F', 'D', 'L', 'B')):
    for (side_index, side_name) in enumerate(('U', 'R', 'F', 'D', 'L', 'B')):
        index = 0
        if side_name == 'U':
            index = 4
        elif side_name == 'L':
            index = 1
        elif side_name == 'F':
            index = 0
        elif side_name == 'R':
            index = 2
        elif side_name == 'B':
            index = 3
        elif side_name == 'D':
            index = 5

        filename = os.path.join(os.getcwd(), "images", "%s.png" % index)
        print('file = ', filename)
        rimg = RubiksImage(index, side_name)
        rimg.analyze_file(filename)
        data = merge_two_dicts(data, rimg.data)

    cube = RubiksColorSolverGeneric(3)
    cube.enter_scan_data(data)
    cube.crunch_colors()
    return ''.join(cube.cube_for_kociemba_strict())
예제 #4
0
results = []

for (desc, filename, expected) in test_cases:
    log.warning("Test: %s" % desc)
    with open('test/' + filename, 'r') as fh:
        scan_data_str_keys = json.load(fh)
        scan_data = {}

        for (key, value) in scan_data_str_keys.items():
            scan_data[int(key)] = value

        square_count = len(scan_data.keys())
        square_count_per_side = int(square_count / 6)
        width = int(sqrt(square_count_per_side))

        cube = RubiksColorSolverGeneric(width)
        try:
            cube.enter_scan_data(scan_data)
            cube.crunch_colors()
            output = ''.join(cube.cube_for_kociemba_strict())
        except Exception as e:
            log.exception(e)
            log.info(json.dumps(scan_data))
            output = 'Exception'
            #break

        if output == expected:
            results.append("\033[92mPASS\033[0m: %s" % desc)
        else:
            results.append("\033[91mFAIL\033[0m: %s" % desc)
            results.append("   expected %s" % expected)
예제 #5
0
class MindCuber(object):
    scan_order = [
        5, 9, 6, 3, 2, 1, 4, 7, 8, 23, 27, 24, 21, 20, 19, 22, 25, 26, 50, 54,
        51, 48, 47, 46, 49, 52, 53, 14, 10, 13, 16, 17, 18, 15, 12, 11, 41, 43,
        44, 45, 42, 39, 38, 37, 40, 32, 34, 35, 36, 33, 30, 29, 28, 31
    ]

    hold_cube_pos = 85
    rotate_speed = 400
    flip_speed = 300
    flip_speed_push = 400

    def __init__(self):
        self.shutdown = False
        self.flipper = LargeMotor(OUTPUT_A)
        self.turntable = LargeMotor(OUTPUT_B)
        self.colorarm = MediumMotor(OUTPUT_C)
        self.color_sensor = ColorSensor()
        self.color_sensor.mode = self.color_sensor.MODE_RGB_RAW
        self.infrared_sensor = InfraredSensor()
        self.init_motors()
        self.state = ['U', 'D', 'F', 'L', 'B', 'R']
        self.rgb_solver = None
        signal.signal(signal.SIGTERM, self.signal_term_handler)
        signal.signal(signal.SIGINT, self.signal_int_handler)

        filename_max_rgb = 'max_rgb.txt'

        if os.path.exists(filename_max_rgb):
            with open(filename_max_rgb, 'r') as fh:
                for line in fh:
                    (color, value) = line.strip().split()

                    if color == 'red':
                        self.color_sensor.red_max = int(value)
                        log.info("red max is %d" % self.color_sensor.red_max)
                    elif color == 'green':
                        self.color_sensor.green_max = int(value)
                        log.info("green max is %d" %
                                 self.color_sensor.green_max)
                    elif color == 'blue':
                        self.color_sensor.blue_max = int(value)
                        log.info("blue max is %d" % self.color_sensor.blue_max)

    def init_motors(self):

        for x in (self.flipper, self.turntable, self.colorarm):
            if not x.connected:
                log.error("%s is not connected" % x)
                sys.exit(1)
            x.reset()

        log.info("Initialize flipper %s" % self.flipper)
        self.flipper.on(SpeedDPS(-50), block=True)
        self.flipper.off()
        self.flipper.reset()

        log.info("Initialize colorarm %s" % self.colorarm)
        self.colorarm.on(SpeedDPS(500), block=True)
        self.colorarm.off()
        self.colorarm.reset()

        log.info("Initialize turntable %s" % self.turntable)
        self.turntable.off()
        self.turntable.reset()

    def shutdown_robot(self):
        log.info('Shutting down')
        self.shutdown = True

        if self.rgb_solver:
            self.rgb_solver.shutdown = True

        for x in (self.flipper, self.turntable, self.colorarm):
            # We are shutting down so do not 'hold' the motors
            x.stop_action = 'brake'
            x.off(False)

    def signal_term_handler(self, signal, frame):
        log.error('Caught SIGTERM')
        self.shutdown_robot()

    def signal_int_handler(self, signal, frame):
        log.error('Caught SIGINT')
        self.shutdown_robot()

    def apply_transformation(self, transformation):
        self.state = [self.state[t] for t in transformation]

    def rotate_cube(self, direction, nb):
        current_pos = self.turntable.position
        final_pos = 135 * round(
            (self.turntable.position + (270 * direction * nb)) / 135.0)
        log.info(
            "rotate_cube() direction %s, nb %s, current_pos %d, final_pos %d" %
            (direction, nb, current_pos, final_pos))

        if self.flipper.position > 35:
            self.flipper_away()

        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed),
                                      final_pos)

        if nb >= 1:
            for i in range(nb):
                if direction > 0:
                    transformation = [0, 1, 5, 2, 3, 4]
                else:
                    transformation = [0, 1, 3, 4, 5, 2]
                self.apply_transformation(transformation)

    def rotate_cube_1(self):
        self.rotate_cube(1, 1)

    def rotate_cube_2(self):
        self.rotate_cube(1, 2)

    def rotate_cube_3(self):
        self.rotate_cube(-1, 1)

    def rotate_cube_blocked(self, direction, nb):

        # Move the arm down to hold the cube in place
        self.flipper_hold_cube()

        # OVERROTATE depends on lot on MindCuber.rotate_speed
        current_pos = self.turntable.position
        OVERROTATE = 18
        final_pos = int(135 * round(
            (current_pos + (270 * direction * nb)) / 135.0))
        temp_pos = int(final_pos + (OVERROTATE * direction))

        log.info(
            "rotate_cube_blocked() direction %s nb %s, current pos %s, temp pos %s, final pos %s"
            % (direction, nb, current_pos, temp_pos, final_pos))

        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed),
                                      temp_pos)
        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed / 4),
                                      final_pos)

    def rotate_cube_blocked_1(self):
        self.rotate_cube_blocked(1, 1)

    def rotate_cube_blocked_2(self):
        self.rotate_cube_blocked(1, 2)

    def rotate_cube_blocked_3(self):
        self.rotate_cube_blocked(-1, 1)

    def flipper_hold_cube(self, speed=300):
        current_position = self.flipper.position

        # Push it forward so the cube is always in the same position
        # when we start the flip
        if (current_position <= MindCuber.hold_cube_pos - 10
                or current_position >= MindCuber.hold_cube_pos + 10):

            self.flipper.ramp_down_sp = 400
            self.flipper.on_to_position(SpeedDPS(speed),
                                        MindCuber.hold_cube_pos)
            sleep(0.05)

    def flipper_away(self, speed=300):
        """
        Move the flipper arm out of the way
        """
        log.info("flipper_away()")
        self.flipper.ramp_down_sp = 400
        self.flipper.on_to_position(SpeedDPS(speed), 0)

    def flip(self):
        """
        Motors will sometimes stall if you call on_to_position() multiple
        times back to back on the same motor. To avoid this we call a 50ms
        sleep in flipper_hold_cube() and after each on_to_position() below.

        We have to sleep after the 2nd on_to_position() because sometimes
        flip() is called back to back.
        """
        log.info("flip()")

        if self.shutdown:
            return

        # Move the arm down to hold the cube in place
        self.flipper_hold_cube()

        # Grab the cube and pull back
        self.flipper.ramp_up_sp = 200
        self.flipper.ramp_down_sp = 0
        self.flipper.on_to_position(SpeedDPS(self.flip_speed), 190)
        sleep(0.05)

        # At this point the cube is at an angle, push it forward to
        # drop it back down in the turntable
        self.flipper.ramp_up_sp = 200
        self.flipper.ramp_down_sp = 400
        self.flipper.on_to_position(SpeedDPS(self.flip_speed_push),
                                    MindCuber.hold_cube_pos)
        sleep(0.05)

        transformation = [2, 4, 1, 3, 0, 5]
        self.apply_transformation(transformation)

    def colorarm_middle(self):
        log.info("colorarm_middle()")
        self.colorarm.on_to_position(SpeedDPS(600), -750)

    def colorarm_corner(self, square_index):
        """
        The lower the number the closer to the center
        """
        log.info("colorarm_corner(%d)" % square_index)
        position_target = -580

        if square_index == 1:
            position_target -= 10

        elif square_index == 3:
            position_target -= 30

        elif square_index == 5:
            position_target -= 20

        elif square_index == 7:
            pass

        else:
            raise ScanError(
                "colorarm_corner was given unsupported square_index %d" %
                square_index)

        self.colorarm.on_to_position(SpeedDPS(600), position_target)

    def colorarm_edge(self, square_index):
        """
        The lower the number the closer to the center
        """
        log.info("colorarm_edge(%d)" % square_index)
        position_target = -640

        if square_index == 2:
            position_target -= 20

        elif square_index == 4:
            position_target -= 40

        elif square_index == 6:
            position_target -= 20

        elif square_index == 8:
            pass

        else:
            raise ScanError(
                "colorarm_edge was given unsupported square_index %d" %
                square_index)

        self.colorarm.on_to_position(SpeedDPS(600), position_target)

    def colorarm_remove(self):
        log.info("colorarm_remove()")
        self.colorarm.on_to_position(SpeedDPS(600), 0)

    def colorarm_remove_halfway(self):
        log.info("colorarm_remove_halfway()")
        self.colorarm.on_to_position(SpeedDPS(600), -400)

    def scan_face(self, face_number):
        log.info("scan_face() %d/6" % face_number)

        if self.shutdown:
            return

        if self.flipper.position > 35:
            self.flipper_away(100)

        self.colorarm_middle()
        self.colors[int(MindCuber.scan_order[self.k])] = self.color_sensor.rgb

        self.k += 1
        i = 1
        target_pos = 115
        self.colorarm_corner(i)

        # The gear ratio is 3:1 so 1080 is one full rotation
        self.turntable.reset()
        self.turntable.on_to_position(SpeedDPS(MindCuber.rotate_speed),
                                      1080,
                                      block=False)
        self.turntable.wait_until('running')

        while True:

            # 135 is 1/8 of full rotation
            if self.turntable.position >= target_pos:
                current_color = self.color_sensor.rgb
                self.colors[int(MindCuber.scan_order[self.k])] = current_color

                i += 1
                self.k += 1

                if i == 9:
                    # Last face, move the color arm all the way out of the way
                    if face_number == 6:
                        self.colorarm_remove()

                    # Move the color arm far enough away so that the flipper
                    # arm doesn't hit it
                    else:
                        self.colorarm_remove_halfway()

                    break

                elif i % 2:
                    self.colorarm_corner(i)

                    if i == 1:
                        target_pos = 115
                    elif i == 3:
                        target_pos = 380
                    else:
                        target_pos = i * 135

                else:
                    self.colorarm_edge(i)

                    if i == 2:
                        target_pos = 220
                    elif i == 8:
                        target_pos = 1060
                    else:
                        target_pos = i * 135

            if self.shutdown:
                return

        if i < 9:
            raise ScanError('i is %d..should be 9' % i)

        self.turntable.wait_until_not_moving()
        self.turntable.off()
        self.turntable.reset()
        log.info("\n")

    def scan(self):
        log.info("scan()")
        self.colors = {}
        self.k = 0
        self.scan_face(1)

        self.flip()
        self.scan_face(2)

        self.flip()
        self.scan_face(3)

        self.rotate_cube(-1, 1)
        self.flip()
        self.scan_face(4)

        self.rotate_cube(1, 1)
        self.flip()
        self.scan_face(5)

        self.flip()
        self.scan_face(6)

        if self.shutdown:
            return

        log.info("RGB json:\n%s\n" % json.dumps(self.colors))
        self.rgb_solver = RubiksColorSolverGeneric(3)
        self.rgb_solver.enter_scan_data(self.colors)
        self.rgb_solver.crunch_colors()
        self.cube_kociemba = self.rgb_solver.cube_for_kociemba_strict()
        log.info("Final Colors (kociemba): %s" % ''.join(self.cube_kociemba))

        # This is only used if you want to rotate the cube so U is on top, F is
        # in the front, etc. You would do this if you were troubleshooting color
        # detection and you want to pause to compare the color pattern on the
        # cube vs. what we think the color pattern is.
        '''
        log.info("Position the cube so that U is on top, F is in the front, etc...to make debugging easier")
        self.rotate_cube(-1, 1)
        self.flip()
        self.flipper_away()
        self.rotate_cube(1, 1)
        input('Paused')
        '''

    def move(self, face_down):
        log.info("move() face_down %s" % face_down)

        position = self.state.index(face_down)
        actions = {
            0: ["flip", "flip"],
            1: [],
            2: ["rotate_cube_2", "flip"],
            3: ["rotate_cube_1", "flip"],
            4: ["flip"],
            5: ["rotate_cube_3", "flip"]
        }.get(position, None)

        for a in actions:

            if self.shutdown:
                break

            getattr(self, a)()

    def run_kociemba_actions(self, actions):
        log.info('Action (kociemba): %s' % ' '.join(actions))
        total_actions = len(actions)

        for (i, a) in enumerate(actions):

            if self.shutdown:
                break

            if a.endswith("'"):
                face_down = list(a)[0]
                rotation_dir = 1
            elif a.endswith("2"):
                face_down = list(a)[0]
                rotation_dir = 2
            else:
                face_down = a
                rotation_dir = 3

            log.info("Move %d/%d: %s%s (a %s)" %
                     (i, total_actions, face_down, rotation_dir, pformat(a)))
            self.move(face_down)

            if rotation_dir == 1:
                self.rotate_cube_blocked_1()
            elif rotation_dir == 2:
                self.rotate_cube_blocked_2()
            elif rotation_dir == 3:
                self.rotate_cube_blocked_3()
            log.info("\n")

    def resolve(self):

        if self.shutdown:
            return

        cmd = ['kociemba', ''.join(map(str, self.cube_kociemba))]
        output = check_output(cmd).decode('ascii')

        if 'ERROR' in output:
            msg = "'%s' returned the following error\n%s\n" % (' '.join(cmd),
                                                               output)
            log.error(msg)
            print(msg)
            sys.exit(1)

        actions = output.strip().split()
        self.run_kociemba_actions(actions)
        self.cube_done()

    def cube_done(self):
        self.flipper_away()

    def wait_for_cube_insert(self):
        rubiks_present = 0
        rubiks_present_target = 10
        log.info('wait for cube...to be inserted')

        while True:

            if self.shutdown:
                break

            dist = self.infrared_sensor.proximity

            # It is odd but sometimes when the cube is inserted
            # the IR sensor returns a value of 100...most of the
            # time it is just a value less than 50
            if dist < 50 or dist == 100:
                rubiks_present += 1
                log.info("wait for cube...distance %d, present for %d/%d" %
                         (dist, rubiks_present, rubiks_present_target))
            else:
                if rubiks_present:
                    log.info('wait for cube...cube removed (%d)' % dist)
                rubiks_present = 0

            if rubiks_present >= rubiks_present_target:
                log.info('wait for cube...cube found and stable')
                break

            time.sleep(0.1)
예제 #6
0
    def analyze_webcam(self, width=352, height=240):
        self.reset(True)
        window_width = width * 2
        window_height = height * 2

        capture = cv2.VideoCapture(self.webcam)

        # Set the capture resolution
        capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, width)
        capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, height)
        # capture.set(cv2.cv.CV_CAP_PROP_SATURATION, 0.10)

        # Create the window and set the size to match the capture resolution
        cv2.namedWindow("Fig", cv2.cv.CV_WINDOW_NORMAL)
        cv2.resizeWindow("Fig", window_width, window_height)

        while True:
            (ret, self.image) = capture.read()

            # If we've already solve the cube and have instructions printed on the
            # screen don't bother looking for the cube in the image
            if not self.solution:
                self.analyze(webcam=True)
                self.draw_circles()

            self.draw_cube_face(self.draw_cube_size,
                                height - (self.draw_cube_size * 3),
                                self.U_data, 'U')
            self.draw_cube_face(self.draw_cube_size * 0,
                                height - (self.draw_cube_size * 2),
                                self.L_data, 'L')
            self.draw_cube_face(self.draw_cube_size * 1,
                                height - (self.draw_cube_size * 2),
                                self.F_data, 'F')
            self.draw_cube_face(self.draw_cube_size * 2,
                                height - (self.draw_cube_size * 2),
                                self.R_data, 'R')
            self.draw_cube_face(self.draw_cube_size * 3,
                                height - (self.draw_cube_size * 2),
                                self.B_data, 'B')
            self.draw_cube_face(self.draw_cube_size,
                                height - self.draw_cube_size, self.D_data, 'D')

            self.draw_cube_face(width - (self.draw_cube_size * 4),
                                height - (self.draw_cube_size * 3),
                                self.U_html, 'U-html')
            self.draw_cube_face(width - (self.draw_cube_size * 5),
                                height - (self.draw_cube_size * 2),
                                self.L_html, 'L-html')
            self.draw_cube_face(width - (self.draw_cube_size * 4),
                                height - (self.draw_cube_size * 2),
                                self.F_html, 'F-html')
            self.draw_cube_face(width - (self.draw_cube_size * 3),
                                height - (self.draw_cube_size * 2),
                                self.R_html, 'R-html')
            self.draw_cube_face(width - (self.draw_cube_size * 2),
                                height - (self.draw_cube_size * 2),
                                self.B_html, 'B-html')
            self.draw_cube_face(width - (self.draw_cube_size * 4),
                                height - self.draw_cube_size, self.D_html,
                                'D-html')

            if self.save_colors and self.size and len(
                    self.data.keys()) == (self.size * self.size):
                self.total_data = merge_two_dicts(self.total_data, self.data)
                log.info("Saved side %s, %d squares" %
                         (self.name, len(self.data.keys())))

                if self.name == 'F':
                    self.F_data = deepcopy(self.data)
                    self.name = 'R'
                    self.index = 3

                elif self.name == 'R':
                    self.R_data = deepcopy(self.data)
                    self.name = 'B'
                    self.index = 4

                elif self.name == 'B':
                    self.B_data = deepcopy(self.data)
                    self.name = 'L'
                    self.index = 1

                elif self.name == 'L':
                    self.L_data = deepcopy(self.data)
                    self.name = 'U'
                    self.index = 0

                elif self.name == 'U':
                    self.U_data = deepcopy(self.data)
                    self.name = 'D'
                    self.index = 5

                elif self.name == 'D':
                    self.D_data = deepcopy(self.data)
                    self.name = 'F'
                    self.index = 2
                    print(json.dumps(self.total_data, sort_keys=True) + '\n')

                    if self.size in (2, 3, 4):
                        color_resolver = RubiksColorSolverGeneric(self.size)
                        color_resolver.enter_scan_data(self.total_data)
                        color_resolver.crunch_colors()
                        print "Final Colors"
                        final_colors = color_resolver.cube_for_json()
                        kociemba_string = final_colors['kociemba']
                        print(kociemba_string)

                        for (square_index,
                             value) in final_colors['squares'].items():
                            html_colors = final_colors['sides'][
                                value['finalSide']]['colorHTML']
                            rgb = (html_colors['red'], html_colors['green'],
                                   html_colors['blue'])
                            side_name = get_side_name(self.size, square_index)

                            if side_name == 'U':
                                self.U_html[square_index] = rgb
                            elif side_name == 'L':
                                self.L_html[square_index] = rgb
                            elif side_name == 'F':
                                self.F_html[square_index] = rgb
                            elif side_name == 'R':
                                self.R_html[square_index] = rgb
                            elif side_name == 'B':
                                self.B_html[square_index] = rgb
                            elif side_name == 'D':
                                self.D_html[square_index] = rgb

                        if self.size == 2:
                            cmd = ['rubiks_2x2x2_solver.py', kociemba_string]
                            self.solution = check_output(cmd).strip()
                            if self.solution == 'Cube is already solved':
                                self.solution = 'S O L V E D'
                            print self.solution

                        elif self.size == 3:
                            if kociemba_string == 'UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB':
                                self.solution = 'S O L V E D'
                            else:
                                cmd = ['kociemba', kociemba_string]
                                self.solution = check_output(cmd).strip()
                                print self.solution

                        elif self.size == 4:
                            if kociemba_string == 'UUUUUUUUUUUUUUUURRRRRRRRRRRRRRRRFFFFFFFFFFFFFFFFDDDDDDDDDDDDDDDDLLLLLLLLLLLLLLLLBBBBBBBBBBBBBBBB':
                                self.solution = 'S O L V E D'
                            else:
                                cmd = 'cd ~/rubiks-cube-solvers/4x4x4/TPR-4x4x4-Solver/ && java -cp .:threephase.jar:twophase.jar solver %s' % kociemba_string
                                self.solution = check_output(
                                    cmd, shell=True).splitlines()[-1].strip()
                                print self.solution

                else:
                    raise Exception("Invalid side %s" % self.name)

                self.reset(False)
                self.save_colors = False

            if self.solution:
                slist = self.solution.split()
                row = 1

                while slist:
                    to_display = min(10, len(slist))
                    cv2.putText(self.image, ' '.join(slist[0:to_display]),
                                (10, 20 * row), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
                                (255, 255, 255), 1)
                    if to_display == len(slist):
                        break
                    else:
                        slist = slist[to_display:]
                    row += 1
            cv2.imshow("Fig", self.image)

            if not self.process_keyboard_input():
                break

            # Sleep 50ms for 20 fps
            time.sleep(0.05)

        capture.release()
        cv2.destroyWindow("Fig")
        with open(args.filename, 'r') as fh:
            rgb = ''.join(fh.readlines())
    elif args.rgb:
        rgb = args.rgb
    else:
        print("ERROR: Neither --filename or --rgb was specified")
        sys.exit(1)

    scan_data_str_keys = json.loads(rgb)
    scan_data = {}

    for (key, value) in scan_data_str_keys.items():
        scan_data[int(key)] = value

    square_count = len(scan_data.keys())
    square_count_per_side = int(square_count / 6)
    width = int(sqrt(square_count_per_side))

    cube = RubiksColorSolverGeneric(width)
    cube.enter_scan_data(scan_data)
    cube.crunch_colors()

    if args.json:
        print(json.dumps(cube.cube_for_json(), indent=4, sort_keys=True))
    else:
        print(''.join(cube.cube_for_kociemba_strict()))

except Exception as e:
    log.exception(e)
    sys.exit(1)