├── .DS_Store ├── __pycache__ ├── video.cpython-37.pyc ├── combiner.cpython-37.pyc ├── normalizer.cpython-37.pyc └── colordetection.cpython-37.pyc ├── images ├── Screenshot 2021-08-27 at 8.26.33 AM.png ├── Screenshot 2021-08-27 at 8.34.35 AM.png ├── Screenshot 2021-08-27 at 8.47.24 AM.png ├── Screenshot 2021-08-27 at 8.53.58 AM.png ├── Screenshot 2021-08-27 at 8.55.30 AM.png ├── Screenshot 2021-08-27 at 9.19.43 AM.png └── Screenshot 2021-08-27 at 9.26.25 AM.png ├── testInput.txt ├── combiner.py ├── normalizer.py ├── README.md ├── solve-manual.json ├── solver.py ├── colordetection.py └── video.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/.DS_Store -------------------------------------------------------------------------------- /__pycache__/video.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/__pycache__/video.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/combiner.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/__pycache__/combiner.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/normalizer.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/__pycache__/normalizer.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/colordetection.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/__pycache__/colordetection.cpython-37.pyc -------------------------------------------------------------------------------- /images/Screenshot 2021-08-27 at 8.26.33 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/images/Screenshot 2021-08-27 at 8.26.33 AM.png -------------------------------------------------------------------------------- /images/Screenshot 2021-08-27 at 8.34.35 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/images/Screenshot 2021-08-27 at 8.34.35 AM.png -------------------------------------------------------------------------------- /images/Screenshot 2021-08-27 at 8.47.24 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/images/Screenshot 2021-08-27 at 8.47.24 AM.png -------------------------------------------------------------------------------- /images/Screenshot 2021-08-27 at 8.53.58 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/images/Screenshot 2021-08-27 at 8.53.58 AM.png -------------------------------------------------------------------------------- /images/Screenshot 2021-08-27 at 8.55.30 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/images/Screenshot 2021-08-27 at 8.55.30 AM.png -------------------------------------------------------------------------------- /images/Screenshot 2021-08-27 at 9.19.43 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/images/Screenshot 2021-08-27 at 9.19.43 AM.png -------------------------------------------------------------------------------- /images/Screenshot 2021-08-27 at 9.26.25 AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshaynarisetti/RubiksCube_Solver/HEAD/images/Screenshot 2021-08-27 at 9.26.25 AM.png -------------------------------------------------------------------------------- /testInput.txt: -------------------------------------------------------------------------------- 1 | FLR FUB RLB 2 | RRF RRR FRD 3 | BDU BFU UUL 4 | RFD FDF LLL 5 | LLD BLU UDF 6 | DUU DBD BBB 7 | 8 | 9 | FRF BFB LDL 10 | LFD RRL BUD 11 | UBR LLD UDF 12 | FDR UUU DFD 13 | UFU RDR BFL 14 | BLR UBB BLR -------------------------------------------------------------------------------- /combiner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | class Combine: 5 | 6 | def sides(self, sides): 7 | """Join all the sides together into one single string. 8 | 9 | :param sides: dictionary with all the sides 10 | :returns: string 11 | """ 12 | combined = '' 13 | for face in 'URFDLB': 14 | combined += ''.join(sides[face]) 15 | return combined 16 | 17 | combine = Combine() 18 | -------------------------------------------------------------------------------- /normalizer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from sys import exit as Die 5 | try: 6 | import sys 7 | import json 8 | except ImportError as err: 9 | Die(err) 10 | 11 | 12 | class Normalizer: 13 | 14 | def algorithm(self, alg, language): 15 | """ Noramlize an algorithm from the 16 | json-written manual. 17 | 18 | :param alg: The algorithm itself 19 | :returns: list 20 | """ 21 | with open('solve-manual.json') as f: 22 | manual = json.load(f) 23 | 24 | solution = [] 25 | for notation in alg.split(' '): 26 | solution.append(manual[language][notation]) 27 | return solution 28 | 29 | normalize = Normalizer() 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computer Vision Rubik's Cube Solver 2 | 3 | 4 | 5 | 6 | This is a Computer Vision based Rubik's Cube Solver which will solve the Rubik's cube in 20 Moves 7 | 8 | 9 | # Usage 10 | 11 | `python3 solver.py` 12 | 13 | 14 | This will open a live feed and you can scan the faces of the cube. 15 | 16 | 17 | You may change the calibration values with the live Calibration Feature! 18 | 19 | ### Press 'C' to Start Live calibration 20 | 21 | 22 | Calibrate all 6 Faces using the Opencv Tackers provided 23 | 24 | #### An Example of a perfect scan looks like this 25 | 26 | 27 | 28 | 29 | Once the scanning is done press `esc` to get the solution. 30 | 31 | #### An Example Solution Looks like this, Follow the instructions to solve the cube 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /solve-manual.json: -------------------------------------------------------------------------------- 1 | { 2 | "en": { 3 | "R" : "Turn the right side a quarter turn away from you." , 4 | "R'" : "Turn the right side a quarter turn towards you." , 5 | "R2" : "Turn the right side 180 degrees." , 6 | "L" : "Turn the left side a quarter turn towards you." , 7 | "L'" : "Turn the left side a quarter turn away from you." , 8 | "L2" : "Turn the left side 180 degrees." , 9 | "U" : "Turn the top layer a quarter turn to the left." , 10 | "U'" : "Turn the top layer a quarter turn to the right." , 11 | "U2" : "Turn the top layer 180 degrees.", 12 | "D" : "Turn the bottom layer a quarter turn to the right." , 13 | "D'" : "Turn the bottom layer a quarter turn to the left." , 14 | "D2" : "Turn the bottom layer 180 degrees." , 15 | "B" : "Turn the back side a quarter turn to the left." , 16 | "B'" : "Turn the back side a quarter turn to the right." , 17 | "B2" : "Turn the back side 180 degrees." , 18 | "F" : "Turn the front side a quarter turn to the right." , 19 | "F'" : "Turn the front side a quarter turn to the left." , 20 | "F2" : "Turn the front side 180 degrees." 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from sys import exit as Die 5 | try: 6 | import sys 7 | import kociemba 8 | import argparse 9 | import video as webcam 10 | 11 | from combiner import combine 12 | from normalizer import normalize 13 | except ImportError as err: 14 | Die(err) 15 | 16 | 17 | class Solver: 18 | 19 | def __init__(self, normalize, language): 20 | self.humanize = normalize 21 | self.language = (language[0]) if isinstance(language, list) else language 22 | 23 | def run(self): 24 | state = webcam.scan() 25 | if not state: 26 | print('\033[0;33m[Solver SCAN ERROR] Ops, you did not scan in all 6 sides.') 27 | print('Please try again.\033[0m') 28 | Die(1) 29 | 30 | unsolvedState = combine.sides(state) 31 | try: 32 | algorithm = kociemba.solve(unsolvedState) 33 | length = len(algorithm.split(' ')) 34 | except Exception as err: 35 | print('\033[0;33m[Solver SOLVE ERROR] Ops, you did not scan in all 6 sides correctly.') 36 | print('Please try again.\033[0m') 37 | Die(1) 38 | 39 | print('-- SOLUTION --') 40 | print('Starting position:\n front: green\n top: white\n') 41 | print(algorithm, '({0} moves)'.format(length), '\n') 42 | 43 | # if self.humanize: 44 | manual = normalize.algorithm(algorithm, self.language) 45 | for index, text in enumerate(manual): 46 | print('{}. {}'.format(index+1, text)) 47 | Die(0) 48 | 49 | if __name__ == '__main__': 50 | # define argument parser. 51 | parser = argparse.ArgumentParser() 52 | parser.add_argument('-n', '--normalize', default=False, action='store_true', 53 | help='Shows the solution normalized. For example "R2" would be: \ 54 | "Turn the right side 180 degrees".') 55 | parser.add_argument('-l', '--language', nargs=1, default='en', 56 | help='You can pass in a single \ 57 | argument which will be the language for the normalization output. \ 58 | Default is "en".') 59 | args = parser.parse_args() 60 | 61 | # run Solver with its arguments. 62 | Solver( 63 | args.normalize, 64 | args.language 65 | ).run() -------------------------------------------------------------------------------- /colordetection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from sys import exit as Die 5 | try: 6 | import sys 7 | import numpy as np 8 | except ImportError as err: 9 | Die(err) 10 | 11 | class ColorDetection: 12 | 13 | def get_color_name(self, hsv, cal): 14 | """ Get the name of the color based on the hue. 15 | 16 | :returns: string 17 | """ 18 | (h,s,v) = hsv 19 | for color in cal: 20 | if color == 'red' or color == 'orange': 21 | if (h < cal[color][1][0] or h > cal[color][0][0]) and s in range(cal[color][1][1],cal[color][0][1]) and v in range(cal[color][1][2],cal[color][0][2]): 22 | return color 23 | elif h in range(cal[color][1][0],cal[color][0][0]) and s in range(cal[color][1][1],cal[color][0][1]) and v in range(cal[color][1][2],cal[color][0][2]): 24 | return color 25 | 26 | 27 | return 'white' 28 | 29 | def name_to_rgb(self, name): 30 | """ 31 | Get the main RGB color for a name. 32 | 33 | :param name: the color name that is requested 34 | :returns: tuple 35 | """ 36 | color = { 37 | 'red' : (0,0,255), 38 | 'orange' : (0,165,255), 39 | 'blue' : (255,0,0), 40 | 'green' : (0,255,0), 41 | 'white' : (255,255,255), 42 | 'yellow' : (0,255,255) 43 | } 44 | return color[name] 45 | 46 | def average_hsv(self, roi): 47 | """ Average the HSV colors in a region of interest. 48 | 49 | :param roi: the image array 50 | :returns: tuple 51 | """ 52 | h = 0 53 | s = 0 54 | v = 0 55 | num = 0 56 | for y in range(len(roi)): 57 | if y % 10 == 0: 58 | for x in range(len(roi[y])): 59 | if x % 10 == 0: 60 | chunk = roi[y][x] 61 | num += 1 62 | 63 | if chunk[0] != 0: 64 | h += chunk[0] 65 | s += chunk[1] 66 | v += chunk[2] 67 | h /= num 68 | s /= num 69 | v /= num 70 | return (int(h), int(s), int(v)) 71 | 72 | def median_hsv(self, roi): 73 | """ Average the HSV colors in a region of interest. 74 | 75 | :param roi: the image array 76 | :returns: tuple 77 | """ 78 | h = [] 79 | s = [] 80 | v = [] 81 | num = 0 82 | for y in range(len(roi)): 83 | if y % 10 == 0: 84 | for x in range(len(roi[y])): 85 | if x % 10 == 0: 86 | chunk = roi[y][x] 87 | num += 1 88 | h.append(chunk[0]) 89 | s.append(chunk[1]) 90 | v.append(chunk[2]) 91 | 92 | return (int(np.median(h)), int(np.median(s)), int(np.median(v))) 93 | 94 | ColorDetector = ColorDetection() 95 | -------------------------------------------------------------------------------- /video.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | ## Import the relevant files 5 | from sys import exit as Die 6 | try: 7 | import sys 8 | import cv2 9 | import numpy as np 10 | from colordetection import ColorDetector 11 | except ImportError as err: 12 | Die(err) 13 | 14 | #Variable Used For testing 15 | cameratesting = False 16 | 17 | ''' 18 | Initialize the camera here 19 | ''' 20 | #change cam_port if Video in Live feed is not being Displayed 21 | cam_port = 2 22 | #create a my camera object to read from 23 | cam = cv2.VideoCapture(cam_port) 24 | 25 | 26 | 27 | """ 28 | We are going to want to draw some stickers. In the solution 29 | we have 3 sets of stickers. Each set has 9 stickers to represent 30 | each sticker on any given face of the rubik's cube. 31 | 32 | The 'stickers' set of stickers are physical markers used to help the 33 | user see where to place the cube for color scanning. 34 | 35 | The 'current_stickers' set show which colors are currently being detected 36 | for each position on the face. 37 | 38 | The 'preview_stickers' set shows the most recently recorded face. 39 | You can rescan a face if the preview does not match the actual colors 40 | on the face of the rubik's cube. 41 | 42 | These are the coordinates of each sticker for each set. Feel free to play 43 | with these values if you don't like the sticker placement. 44 | 45 | 46 | """ 47 | detector_stickers = [[200, 120], [300, 120], [400, 120], 48 | [200, 220], [300, 220], [400, 220], 49 | [200, 320], [300, 320], [400, 320]] 50 | 51 | current_stickers = [[20, 20], [54, 20], [88, 20], 52 | [20, 54], [54, 54], [88, 54], 53 | [20, 88], [54, 88], [88, 88]] 54 | 55 | recorded_stickers = [[20, 130], [54, 130], [88, 130], 56 | [20, 164], [54, 164], [88, 164], 57 | [20, 198], [54, 198], [88, 198]] 58 | 59 | #Draws the 9 static stickers in the frame 60 | def draw_detector_stickers(frame): 61 | for (x,y) in (detector_stickers): 62 | cv2.rectangle(frame, (x,y), (x+50, y+50), (255,255,255), 1) 63 | 64 | #Draws the 9 detected stickers in the frame 65 | def draw_current_stickers(frame, state): 66 | 67 | for index,(x,y) in enumerate(current_stickers): 68 | cv2.rectangle(frame, (x,y), (x+32, y+32), ColorDetector.name_to_rgb(state[index]), -1) 69 | 70 | #Draws the 9 Recorded stickers in the frame 71 | def draw_recorded_stickers(frame, state): 72 | 73 | 74 | for index,(x,y) in enumerate(recorded_stickers): 75 | cv2.rectangle(frame, (x,y), (x+32, y+32), ColorDetector.name_to_rgb(state[index]), -1) 76 | 77 | 78 | def color_to_notation(color): 79 | """ 80 | Helper function for converting colors to notation 81 | used by solver. 82 | """ 83 | notation = { 84 | 'green' : 'F', 85 | 'white' : 'U', 86 | 'blue' : 'B', 87 | 'red' : 'R', 88 | 'orange' : 'L', 89 | 'yellow' : 'D' 90 | } 91 | return notation[color] 92 | 93 | def empty_callback(x): 94 | ''' 95 | Empty function for callback when slider positions change. Need input x, this is the value 96 | the slider has changed to. 97 | ''' 98 | pass 99 | 100 | def scan(): 101 | """ 102 | Opens up the webcam and scans the 9 regions in the center 103 | and show a preview. 104 | 105 | After hitting the space bar to confirm, the block below the 106 | current stickers shows the current state that you have. 107 | This is show every user can see what the computer took as input. 108 | 109 | :returns: dictionary 110 | """ 111 | 112 | sides = {} # collection of scanned sides 113 | preview = ['white','white','white', # default starting preview sticker colors 114 | 'white','white','white', 115 | 'white','white','white'] 116 | state = [0,0,0, # current sticker colors 117 | 0,0,0, 118 | 0,0,0] 119 | 120 | defaultcal = { # default color calibration 121 | 'white':[[179,67,255],[0,0,0]], 122 | 'green':[[72,255,218],[47,61,21]], 123 | 'red':[[179,255,240],[6,0,102]], 124 | 'orange':[[179,255,255],[17,147,207]], 125 | 'yellow':[[49,242,255],[18,61,211]], 126 | 'blue':[[127,255,212],[82,72,51]] 127 | } 128 | 129 | colorcal = {} # color calibration dictionary 130 | color = ['white', 'green', 'red', 'orange', 'yellow', 'blue'] # list of valid colors 131 | 132 | cv2.namedWindow('default',0) 133 | # create trackbars here 134 | cv2.createTrackbar('H Upper','default',defaultcal[color[len(colorcal)]][0][0], 179, empty_callback) 135 | cv2.createTrackbar('S Upper','default',defaultcal[color[len(colorcal)]][0][1], 255, empty_callback) 136 | cv2.createTrackbar('V Upper','default',defaultcal[color[len(colorcal)]][0][2], 255, empty_callback) 137 | cv2.createTrackbar('H Lower','default',defaultcal[color[len(colorcal)]][1][0], 179, empty_callback) 138 | cv2.createTrackbar('S Lower','default',defaultcal[color[len(colorcal)]][1][1], 255, empty_callback) 139 | cv2.createTrackbar('V Lower','default',defaultcal[color[len(colorcal)]][1][2], 255, empty_callback) 140 | 141 | # Remember that the range for S and V are not 0 to 179 142 | 143 | 144 | colorcal = defaultcal 145 | 146 | # Creates a window named 'my_window_name' 147 | cv2.createTrackbar('My track bar','my_window_name',125,255, empty_callback) 148 | 149 | while cameratesting: 150 | #--------------- Used for Testing ------------------------ 151 | # Captures a frame of video from the camera object 152 | _,frame = cam.read() 153 | hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 154 | 155 | # create a mask 156 | # Bounds for HSV values we are interested in (Blue) 157 | lower_hsv = np.array([89,178,51]) #hmin,smin,vmin 158 | upper_hsv = np.array([118,255,194]) #hmax,smax,vmax 159 | 160 | mask = cv2.inRange(hsv, lower_hsv, upper_hsv) 161 | frame = cv2.bitwise_and(frame,frame, mask= mask) 162 | 163 | # Draw rectangle on the frame 164 | cv2.rectangle(frame, (200,200), (250, 250), (255,0,0), 2) 165 | 166 | # -1 borderwidth is a fill 167 | cv2.rectangle(frame, (300,200), (350, 250), (0,0,255), -1) 168 | 169 | # Note the construction of a rectangle 170 | # arg1 = frame to draw on 171 | # arg2 = x,y coordinates of the rectangle's top left corner 172 | # arg3 = x,y coordinates of the rectangle's bottom right corner 173 | # arg4 = r,g,b values 174 | # arg5 = borderwidth => width of the border or make a fill using -1 175 | 176 | # cv2.rectangle(frame, (xtop_left,ytop_left), (xbot_right,ybot_right), (r,g,b), borderwidth) 177 | 178 | # Displays the frame on the window we made 179 | value = cv2.getTrackbarPos('My track bar','my_window_name') 180 | print(value) 181 | cv2.imshow('my_window_name', frame) 182 | 183 | # Sets the amount of time to display a frame in milliseconds 184 | key = cv2.waitKey(10) 185 | 186 | 187 | 188 | 189 | while not cameratesting: 190 | 191 | _, frame = cam.read() 192 | hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 193 | key = cv2.waitKey(10) 194 | 195 | # init certain stickers. 196 | draw_detector_stickers(frame) 197 | draw_recorded_stickers(frame, preview) 198 | 199 | for index,(x,y) in enumerate(detector_stickers): 200 | roi = hsv[y:y+32, x:x+32] # extracts hsv values within sticker 201 | avg_hsv = ColorDetector.median_hsv(roi) # filters the hsv values into one hsv 202 | color_name = ColorDetector.get_color_name(avg_hsv,colorcal) # extracts the color based on hsv 203 | state[index] = color_name # stores the color 204 | 205 | # update when space bar is pressed. 206 | if key == 32: 207 | preview = list(state) 208 | draw_recorded_stickers(frame, state) # draw the saved colors on the preview 209 | face = color_to_notation(state[4]) # convert the color to notation of the middle sticker and label this as the face 210 | notation = [color_to_notation(color) for color in state] # convert all colors to notation 211 | sides[face] = notation # update the face in the sides dictionary 212 | 213 | # show the new stickers 214 | draw_current_stickers(frame, state) # draw live sampling of face colors 215 | 216 | # append amount of scanned sides 217 | text = 'scanned sides: {}/6'.format(len(sides)) 218 | cv2.putText(frame, text, (20, 460), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255,255,0), 1, cv2.LINE_AA) 219 | 220 | # indicate the scanning instruction 221 | textInstruction = 'scan and rotate the cube with white on the top and green on the front (towards camera)' 222 | textInstruction2 = 'the color of center brick is used as the side identifier (since the center brick does not move)' 223 | textInstruction3 = 'you can scan as many times as you want' 224 | textInstruction4 = 'the program will overwrite the old scan when same side is detected, press esc key get the solution' 225 | cv2.putText(frame, textInstruction, (20, 600), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255,255,0), 1, cv2.LINE_AA) 226 | cv2.putText(frame, textInstruction2, (20, 620), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255,255,0), 1, cv2.LINE_AA) 227 | cv2.putText(frame, textInstruction3, (20, 640), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255,255,0), 1, cv2.LINE_AA) 228 | cv2.putText(frame, textInstruction4, (20, 660), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255,255,0), 1, cv2.LINE_AA) 229 | 230 | # quit on escape. 231 | if key == 27: 232 | break 233 | 234 | # show result 235 | cv2.imshow("default", frame) 236 | 237 | if key == 99: 238 | colorcal = {} 239 | while len(colorcal) < 6: 240 | _, frame = cam.read() 241 | 242 | 243 | hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 244 | key = cv2.waitKey(10) & 0xff 245 | 246 | # hue upper lower 247 | hu = cv2.getTrackbarPos('H Upper','default') 248 | hl = cv2.getTrackbarPos('H Lower','default') 249 | # saturation upper lower 250 | su = cv2.getTrackbarPos('S Upper','default') 251 | sl = cv2.getTrackbarPos('S Lower','default') 252 | # value upper lower 253 | vu = cv2.getTrackbarPos('V Upper','default') 254 | vl = cv2.getTrackbarPos('V Lower','default') 255 | print("H upper", hu) 256 | print("H Lower", hl) 257 | print("S upper", su) 258 | print("S Lower", sl) 259 | print("V upper", vu) 260 | print("V Lower", vl) 261 | 262 | 263 | if color[len(colorcal)] == 'red' or color[len(colorcal)] == 'orange': 264 | lower_hsv = np.array([0,sl,vl]) 265 | upper_hsv = np.array([hl,su,vu]) 266 | mask1 = cv2.inRange(hsv, lower_hsv, upper_hsv) 267 | lower_hsv = np.array([hu,sl,vl]) 268 | upper_hsv = np.array([179,su,vu]) 269 | mask2 = cv2.inRange(hsv, lower_hsv, upper_hsv) 270 | mask = cv2.bitwise_or(mask1, mask2) 271 | res = cv2.bitwise_and(frame,frame, mask= mask) 272 | lower_hsv = np.array([hl,sl,vl]) 273 | upper_hsv = np.array([hu,su,vu]) 274 | else: 275 | lower_hsv = np.array([hl,sl,vl]) 276 | upper_hsv = np.array([hu,su,vu]) 277 | 278 | 279 | mask = cv2.inRange(hsv, lower_hsv, upper_hsv) 280 | res = cv2.bitwise_and(frame,frame, mask = mask) 281 | 282 | if key == 32: 283 | defaultcal[color[len(colorcal)]] = [upper_hsv,lower_hsv] 284 | colorcal[color[len(colorcal)]] = [upper_hsv,lower_hsv] 285 | 286 | if(len(colorcal) < 6): 287 | cv2.setTrackbarPos('H Upper','default',defaultcal[color[len(colorcal)]][0][0]) 288 | cv2.setTrackbarPos('S Upper','default',defaultcal[color[len(colorcal)]][0][1]) 289 | cv2.setTrackbarPos('V Upper','default',defaultcal[color[len(colorcal)]][0][2]) 290 | cv2.setTrackbarPos('H Lower','default',defaultcal[color[len(colorcal)]][1][0]) 291 | cv2.setTrackbarPos('S Lower','default',defaultcal[color[len(colorcal)]][1][1]) 292 | cv2.setTrackbarPos('V Lower','default',defaultcal[color[len(colorcal)]][1][2]) 293 | 294 | if(len(colorcal) < 6): 295 | text = 'calibrating {}'.format(color[len(colorcal)]) 296 | cv2.putText(res, text, (20, 460), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA) 297 | 298 | cv2.imshow("default", res) 299 | # quit on escape key. 300 | if key == 27: 301 | break 302 | 303 | cam.release() 304 | cv2.destroyAllWindows() 305 | return sides if len(sides) == 6 else False 306 | 307 | --------------------------------------------------------------------------------