diff --git a/canvas.py b/canvas.py index e79c9fbd..7f1c95bd 100644 --- a/canvas.py +++ b/canvas.py @@ -5,8 +5,8 @@ class canvas(): def __init__(self, width, height): - self.width = width - self.height = height + self.width = int(width) + self.height = int(height) self.new_canvas = np.zeros((self.height, self.width, 3), np.uint8) def set_color(self, B, G, R): @@ -19,10 +19,18 @@ def show_canvas(self): cv2.imshow('newCanvas', self.new_canvas) def save_drawing(self): - """""" + """This function allows users to save their drawing with a name of + their choice. + """ file_name = input('Please name your drawing: ') cv2.imwrite(file_name+'.jpg', self.new_canvas) + def clear(self): + """This function clears the screen. + """ + cv2.rectangle(self.new_canvas, (0, 0), (self.width, self.height), (0, 0, 0)) + + if __name__ == "__main__": canvas1 = canvas(1280, 960) canvas1.set_color(0, 0, 0) diff --git a/fingerTrack.py b/fingerTrack.py index d93bca7b..973d491e 100644 --- a/fingerTrack.py +++ b/fingerTrack.py @@ -16,20 +16,45 @@ def __init__(self): self.red_maskL = [np.array([0, 150, 100]), np.array([178, 150, 100])] self.red_maskH = [np.array([1, 255, 255]), np.array([180, 255, 255])] self.refreshDelay = 0 + self.colors = [] + self.dist = [] + + def map(self, x, oldL, oldH, newL, newH): + """This function maps a value from one range to a differnet range + + x: the value in the old range + oldL: the lower limit of the old range of values + oldH: the upper limit of the old range of values + newL: the lower limit of the new range of values + newH: the upper limit of the new range of values + """ + return int(((x - oldL)/(oldH-oldL))*(newH-newL)+newL) + + def brush_color(self, hue): + """This function takes in a uint8 value for hue and generate + a BGR color range """ + color = np.uint8([[[hue, 255, 255]]]) + return cv2.cvtColor(color, cv2.COLOR_HSV2BGR) def BGR2HSV(self, frame): - """This functions takes in a frame and converts it from BGR to BGR2HSV + """This functions takes in a frame and converts it from BGR + to HSV values """ return cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) def red_mask(self, frame): - """This function generates a red mask based on the frame being passed in + """This function generates a red mask based on the frame being + passed in """ mask1 = cv2.inRange(frame, self.red_maskL[0], self.red_maskH[0]) mask2 = cv2.inRange(frame, self.red_maskL[1], self.red_maskH[1]) return (mask1 | mask2) def find_center(self, mask, target): + """This function takes in a cv2 mask, find the center of the + contours in the mask, and draw a green dot at the center location + on the target frame + """ im2, contours, hierarchy = cv2.findContours(mask, 1, 2) try: if self.frame_num > self.refreshDelay or self.frame_num == 0: @@ -44,37 +69,36 @@ def find_center(self, mask, target): except IndexError: """""" - def draw(self, target): + def refine_path(self): + """This function takes evalutes every two consecutive points, + find the distance between them, and add the new point to a + list of clear path if they are not off by roughly 15 pixels. + It also takes a distance and convert it to a color to be used + when plotting the line. + """ if len(self.path) == 1: - clearpath.append(path[0]) + self.clearpath.append(self.path[0]) elif len(self.path) > 2: pair = self.path[-2] - # print(pair, pair[0], cx, pair[1], cy) diffx = abs(self.cx-pair[0]) diffy = abs(self.cy-pair[1]) distance = math.sqrt(diffx**2+diffy**2) if distance<10: + dist2hue = self.map(distance, 0.0, 10.0, 0.0, 255.0) + paintColor = self.brush_color(dist2hue) + self.colors.append((int(paintColor[0][0][0]), int(paintColor[0][0][1]), int(paintColor[0][0][2]))) self.clearpath.append(pair) + + def draw(self, canvas, disappr=True): + """This function draws the lines on the canvas of the screen. + The default is that only the 20 newest points will be drawn on screen. + """ for i in range(len(self.clearpath)): if len(self.clearpath) < 1: break - elif i<(len(self.clearpath)-1)<21: - cv2.line(res, self.clearpath[i], self.clearpath[i+1], (255,0,0), 3) - elif 20 < i < (len(self.clearpath)-1): - cv2.rectangle(res, (0,0), (600, 400), (0,0,0)) + elif i<(len(self.clearpath)-1)<21 and not disappr: + cv2.line(canvas.new_canvas, self.clearpath[i], self.clearpath[i+1], self.colors[i], 3) + elif 20 < i < (len(self.clearpath)-1) and disappr: + canvas.clear() for j in range(20): - cv2.line(res, self.clearpath[-(j+1)], self.clearpath[-(j+2)], (255,0,0), 3) - # for i in range(len(self.path)): - # # TODO: Add if statements to make sure that any outliers - # # would be removed from the list or ignored when drawing - # # the linewidth - # diffx = math.abs(self.cx-self.path[-1][0]) - # print(diffx) - # diffy = math.abs(cy-path[-1][1]) - # print(diffy) - # if len(self.path) == 1: - # break - # # elif math.sqrt(diffx**2+diffy**2) > 30: - # # break - # if i < (len(self.clearpath)-1): - # cv2.line(target, self.clearpath[i], self.path[i+1], (255, 0, 0), 3) + cv2.line(canvas.new_canvas, self.clearpath[-(j+1)], self.clearpath[-(j+2)], self.colors[-(j+2)], 3) diff --git a/main.py b/main.py index c7f9e08e..9ef1382a 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,43 @@ from fingerTrack import * from canvas import * +import cv2 + def main(): """ """ + track = finger_track() + cap = cv2.VideoCapture(0) + newCanvas = canvas(cap.get(3), cap.get(4)) + disappr = True + + + while True: + ret, frame = cap.read() + frame = cv2.flip(frame,1) + cv2.imshow('original', frame) + hsv = track.BGR2HSV(frame) + redMask = track.red_mask(hsv) + mask = cv2.bilateralFilter(redMask, 10, 40, 40) + mask = cv2.blur(mask, (5, 5)) + res = cv2.bitwise_and(frame, frame, mask=redMask) + mask = cv2.blur(mask, (20, 20)) + track.find_center(mask, frame) + track.refine_path() + track.draw(newCanvas, disappr=disappr) + newCanvas.show_canvas() + + if cv2.waitKey(1) & 0xFF == ord('s'): + newCanvas.save_drawing() + break + elif cv2.waitKey(1) & 0xFF == ord('q'): + break + elif cv2.waitKey(1) & 0xFF == ord('d'): + disappr = ~disappr + elif cv2.waitKey(1) & 0xFF == ord('c'): + newCanvas.clear() + + cv2.destroyAllWindows() if __name__ == "__main__": main() diff --git a/paint.py b/paint.py index 60936467..a936e7cc 100644 --- a/paint.py +++ b/paint.py @@ -10,6 +10,26 @@ cy = 0 path = [] clearpath = [] +dist = [] +colors = [] + + +def map(x, oldL, oldH, newL, newH): + """This function maps a value from one range to a differnet range + + x: the value in the old range + oldL: the lower limit of the old range of values + oldH: the upper limit of the old range of values + newL: the lower limit of the new range of values + newH: the upper limit of the new range of values + """ + return int(((x - oldL)/(oldH-oldL))*(newH-newL)+newL) + +def brush_color(hue): + """This function takes in a uint8 value for hue and generate + a BGR color range """ + color = np.uint8([[[hue, 255, 255]]]) + return cv2.cvtColor(color, cv2.COLOR_HSV2BGR) while(True): #capture frame by frame @@ -17,7 +37,7 @@ frame = cv2.flip(frame,1) hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) #find specific color - lower_white = np.array([[0, 0, 230]]) + lower_white = np.array([0, 0, 230]) upper_white = np.array([180, 25, 255]) lower_color = np.array([0,80,50]) upper_color = np.array([20,100,100]) @@ -69,18 +89,25 @@ diffy = abs(cy-pair[1]) distance = math.sqrt(diffx**2+diffy**2) if distance<10: + dist2hue = map(distance, 0.0, 10.0, 0.0, 255.0) + paintColor = brush_color(dist2hue) + print(paintColor[0][0][0]) + colors.append((int(paintColor[0][0][0]), int(paintColor[0][0][1]), int(paintColor[0][0][2]))) + print(colors) clearpath.append(pair) for i in range(len(clearpath)): if len(clearpath) < 1: break elif i<(len(clearpath)-1)<21: - cv2.line(res, clearpath[i], clearpath[i+1], (255,0,0), 3) + cv2.line(res, clearpath[i], clearpath[i+1], colors[i], 3) elif 20 < i < (len(clearpath)-1): cv2.rectangle(res, (0,0), (600, 400), (0,0,0)) for j in range(20): - cv2.line(res, clearpath[-(j+1)], clearpath[-(j+2)], (255,0,0), 3) + cv2.line(res, clearpath[-(j+1)], clearpath[-(j+2)], colors[-(j+2)], 3) + + # print(dist) frame_num += 1 # cnts = cv2.findContours(res, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #display the resulting frame