def run(self): # コマンド引数で画像ファイル名を指定した場合 if len(sys.argv) >= 2: filename = sys.argv[1] # for drawing purposes workDir = filename[:filename.rfind(".")] if not os.path.exists(workDir): os.mkdir(workDir) # 画像ファイルからランドマーク取得 landmark = Landmark(filename) if len(sys.argv) == 3: # コマンド引数で認識するパーツを指定した場合 key = sys.argv[2] lm, rect = landmark.get_landmark(key) else: # パーツを指定しなかった場合、切り取りたい部分を手動で選択 print("右クリック&ドラッグで切り取りたいパーツを囲んでください\n") else: # コマンド引数で画像ファイルを指定しなかった場合デフォルトの画像を使う print("画像ファイルを入力していないため、test.pngを読み込みます\n") print("正しい入力方法: python grabcut_auto.py <filename> \n") filename = 'test.png' # 画像読み込み self.img = cv.imread(cv.samples.findFile(filename)) self.img2 = self.img.copy() # 画像をコピー self.mask = np.zeros(self.img.shape[:2], dtype=np.uint8) # マスクを初期化 self.output = np.zeros(self.img.shape, np.uint8) # 出力画像 self.rect_or_mask = 0 if len(sys.argv) >= 3: #コマンドラインで顔パーツを入力した場合 self.img = self.img2.copy() # ランドマークで座標設定した顔パーツを四角で囲む cv.rectangle(self.img, (rect[0], rect[1]), (rect[2], rect[3]), self.BLUE, 2) self.rect = (min(rect[0], rect[2]), min(rect[1], rect[3]), abs(rect[0] - rect[2]), abs(rect[1] - rect[3])) else: pass self.rect_over = True print("画像に変化があるまで'n'を数回押してください") # 入力ウィンドウと出力ウィンドウの表示 cv.namedWindow('output', cv.WINDOW_NORMAL) cv.namedWindow('input', cv.WINDOW_NORMAL) cv.setMouseCallback('input', self.onmouse) cv.moveWindow('input', self.img.shape[1] + 10, 90) while (1): #入力、出力画像の出力 cv.imshow('output', self.output) cv.imshow('input', self.img) k = cv.waitKey(1) # キーボード入力 if k == ord('q'): #終了 break elif k == ord('0'): # 背景領域を選択 print("左のマウスボタンで背景領域を選択してください\n") self.value = self.DRAW_BG elif k == ord('1'): # 前景領域を選択 print("左のマウスボタンで前景領域を選択してください\n") self.value = self.DRAW_FG elif k == ord('2'): # 曖昧な背景領域を選択 print("左のマウスボタンで曖昧な背景領域を選択してください\n") self.value = self.DRAW_PR_BG elif k == ord('3'): # 曖昧な前景領域を選択 print("左のマウスボタンで曖昧な前景領域を選択してください\n") self.value = self.DRAW_PR_FG elif k == ord('4'): #白目を楕円で抽出 print("白目部分を抽出します") #楕円 long = int(np.linalg.norm(lm[0] - lm[2]) / 2) #直径/2 short = int(np.linalg.norm(lm[1] - lm[3]) / 2) #短径/2 center = (int(abs(lm[0][0] + lm[2][0]) / 2), int(abs(lm[0][1] + lm[2][1]) / 2)) tmp = (int(abs(lm[1][0] + lm[3][0]) / 2), int(abs(lm[1][1] + lm[3][1]) / 2)) center = (int( (center[0] + tmp[0]) / 2), int( (center[1] + tmp[1]) / 2)) #中心 cv.ellipse(self.img, center, (long, short), 0, 0, 360, self.value['color'], -1) cv.ellipse(self.mask, center, (long, short), 0, 0, 360, self.value['val'], -1) self.value = self.DRAW_FG elif k == ord('5') and sys.argv[2] == "nose": #鼻を丸で抽出 print("鼻を抽出します") #円 radius = int(np.linalg.norm(rect[0] - rect[2]) / 2) #半径 center = int((rect[0] + rect[2]) / 2), int( (rect[1] + rect[3]) / 2) cv.circle(self.img, center, radius, self.value['color'], -1) cv.circle(self.mask, center, radius, self.value['val'], -1) self.value = self.DRAW_FG elif k == ord('s'): # 出力画像を保存 bar = np.zeros((self.img.shape[0], 5, 3), np.uint8) bgr = cv.split(self.output) bgra = bgr + [mask2] self.output_alpha = cv.merge(bgra) if len(sys.argv) >= 3 and sys.argv[2] == "nose": #鼻パーツ保存 img_key_name = filename.split( ".", 1)[0] + "_" + str(key) + ".png" cv.imwrite( img_key_name, self.output_alpha[rect[1] - 30:rect[3] + 30, rect[0] - 10:rect[2] + 10]) elif len(sys.argv) >= 3: #顔パーツをコマンドラインで選択した場合、顔パーツをクロップして保存 img_key_name = filename.split( ".", 1)[0] + "_" + str(key) + ".png" cv.imwrite( img_key_name, self.output_alpha[rect[1]:rect[3], rect[0]:rect[2]]) else: #コマンドラインでパーツを選択しなかった場合、パーツに名前を付けて保存する img_g = cv.cvtColor(self.output_alpha, cv.COLOR_BGR2GRAY) #グレースケールへ変換 x, y, w, h = cv.boundingRect(img_g) print("パーツの名前:") parts = input() #顔パーツ保存 img_key_name = filename.split(".", 1)[0] + "_" + parts + ".png" cv.imwrite(img_key_name, self.output_alpha[y:y + h, x:x + w]) print(" 出力結果を保存しました \n") elif k == ord('r'): # リセット print("リセットします \n") self.rect = (0, 0, 1, 1) self.drawing = False self.rectangle = False self.rect_or_mask = 100 self.rect_over = False self.value = self.DRAW_FG self.img = self.img2.copy() self.mask = np.zeros(self.img.shape[:2], dtype=np.uint8) # マスクを初期化 self.output = np.zeros(self.img.shape, np.uint8) # 出力画像 elif k == ord('n'): # 切り取り print("key 0-5を選択して描写することで、切り取る部分を調整することができます。\n") print("描写が終わったら'n'を押してください\n") try: if (self.rect_or_mask == 0): # 四角で囲んだ部分を前景領域抽出 bgdmodel = np.zeros((1, 65), np.float64) fgdmodel = np.zeros((1, 65), np.float64) cv.grabCut(self.img2, self.mask, self.rect, bgdmodel, fgdmodel, 1, cv.GC_INIT_WITH_RECT) self.rect_or_mask = 1 elif self.rect_or_mask == 1: # マスクで前景領域抽出 bgdmodel = np.zeros((1, 65), np.float64) fgdmodel = np.zeros((1, 65), np.float64) cv.grabCut(self.img2, self.mask, self.rect, bgdmodel, fgdmodel, 1, cv.GC_INIT_WITH_MASK) except: import traceback traceback.print_exc() mask2 = np.where((self.mask == 1) + (self.mask == 3), 255, 0).astype('uint8') self.output = cv.bitwise_and(self.img2, self.img2, mask=mask2) print("終了")
def run(self): # コマンド引数で画像ファイル名を指定した場合 if len(sys.argv) >= 2: filename = sys.argv[1] # for drawing purposes workDir = filename[:filename.rfind(".")] if not os.path.exists(workDir): os.mkdir(workDir) # 画像ファイルからランドマーク取得 landmark = Landmark(filename) if len(sys.argv) == 3: # コマンド引数で認識するパーツを指定した場合 key = sys.argv[2] lm, rect = landmark.get_landmark(key) else:#指定しなかった場合 デフォルトで右目認識 key = "right_eye" lm, rect = landmark.get_landmark("right_eye") # コマンド引数で画像ファイルを指定しなかった場合デフォルトの画像を使う else: print("No input image given, so loading default image, lena.jpg \n") print("Correct Usage: python grabcut.py <filename> \n") filename = 'test.png' # 画像読み込み self.img = cv.imread(cv.samples.findFile(filename)) self.img2 = self.img.copy() # a copy of original image self.mask = np.zeros(self.img.shape[:2], dtype = np.uint8) # mask initialized to PR_BG self.output = np.zeros(self.img.shape, np.uint8) # output image to be shown self.img = self.img2.copy() cv.rectangle(self.img, (rect[0], rect[1]), (rect[2], rect[3]), self.BLUE, 2) self.rect = (min(rect[0], rect[2]), min(rect[1], rect[3]), abs(rect[0] - rect[2]), abs(rect[1] - rect[3])) self.rect_or_mask = 0 self.rect_over = True print(" Now press the key 'n' a few times until no further change \n") # input and output windows cv.namedWindow('output', cv.WINDOW_NORMAL) cv.namedWindow('input', cv.WINDOW_NORMAL) cv.setMouseCallback('input', self.onmouse) cv.moveWindow('input', self.img.shape[1]+10,90) hsv = cv.cvtColor(self.img, cv.COLOR_BGR2HSV) SkinLow = np.array([0,30,60]) SkinHigh = np.array([40,150,255]) hsv_mask = cv.inRange(hsv, SkinLow, SkinHigh) print(" Instructions: \n") print(" Draw a rectangle around the object using right mouse button \n") while(1): #入力、出力画像の出力 cv.imshow('output', self.output) cv.imshow('input', self.img) k = cv.waitKey(1) # key bindings if k == 27: # esc to exit break elif k == ord('q'): #終了 break elif k == ord('0'): # BG drawing print(" mark background regions with left mouse button \n") self.value = self.DRAW_BG elif k == ord('1'): # FG drawing print(" mark foreground regions with left mouse button \n") ''' # 顔から白部分を認識 for i in rect: dst = cv.inRange(self.img,(250,250,250),(255,255,255)) # 白部分を前景指定 for ex in range(dst.shape[0]): for ey in range(dst.shape[1]): if dst[ex,ey] == 255: cv.circle(self.img, (ey,ex), self.thickness, self.value['color'], -1) cv.circle(self.mask, (ey,ex), self.thickness, self.value['val'], -1) ''' self.value = self.DRAW_FG elif k == ord('2'): # PR_BG drawing self.value = self.DRAW_PR_BG elif k == ord('3'): # PR_FG drawing self.value = self.DRAW_PR_FG elif k == ord('4') :#白目を楕円で抽出 #楕円 long = int(np.linalg.norm(lm[0] - lm[2]) / 2) #直径/2 short = int(np.linalg.norm(lm[1] - lm[3]) / 2) #短径/2 center = (int(abs(lm[0][0] + lm[2][0]) / 2), int(abs(lm[0][1] + lm[2][1]) / 2)) tmp = (int(abs(lm[1][0] + lm[3][0]) / 2), int(abs(lm[1][1] + lm[3][1]) / 2)) center = (int((center[0]+tmp[0])/2), int((center[1]+tmp[1])/2)) #中心 cv.ellipse(self.img, center, (long, short), 0, 0, 360, self.value['color'], -1) cv.ellipse(self.mask, center, (long, short), 0, 0, 360, self.value['val'], -1) self.value = self.DRAW_FG elif k == ord('5') and sys.argv[2] == "nose" :#鼻を丸で抽出 #円 radius = int(np.linalg.norm(rect[0] - rect[2]) / 2) #半径 center = int((rect[0]+rect[2])/2), int((rect[1]+rect[3])/2) cv.circle(self.img, center, radius, self.value['color'], -1) cv.circle(self.mask, center, radius, self.value['val'], -1) self.value = self.DRAW_FG elif k == ord('s'): # save image bar = np.zeros((self.img.shape[0], 5, 3), np.uint8) bgr = cv.split(self.output) bgra = bgr + [mask2] self.output_alpha = cv.merge(bgra) if sys.argv[2] == "nose": #鼻パーツ保存 img_key_name = filename.split(".",1)[0] + "_" + str(key) + ".png" cv.imwrite(img_key_name,self.output_alpha[rect[1]-30:rect[3]+30,rect[0]-10:rect[2]+10]) else: #顔パーツ保存 img_key_name = filename.split(".",1)[0] + "_" + str(key) + ".png" cv.imwrite(img_key_name,self.output_alpha[rect[1]:rect[3],rect[0]:rect[2]]) print(" Result saved as image \n") elif k == ord('r'): # reset everything print("resetting \n") self.rect = (0,0,1,1) self.drawing = False self.rectangle = False self.rect_or_mask = 100 self.rect_over = False self.value = self.DRAW_FG self.img = self.img2.copy() self.mask = np.zeros(self.img.shape[:2], dtype = np.uint8) # mask initialized to PR_BG self.output = np.zeros(self.img.shape, np.uint8) # output image to be shown elif k == ord('n'): # segment the image print(""" For finer touchups, mark foreground and background after pressing keys 0-3 and again press 'n' \n""") try: if (self.rect_or_mask == 0): # grabcut with rect bgdmodel = np.zeros((1, 65), np.float64) fgdmodel = np.zeros((1, 65), np.float64) cv.grabCut(self.img2, self.mask, self.rect, bgdmodel, fgdmodel, 1, cv.GC_INIT_WITH_RECT) self.rect_or_mask = 1 elif self.rect_or_mask == 1: # grabcut with mask bgdmodel = np.zeros((1, 65), np.float64) fgdmodel = np.zeros((1, 65), np.float64) cv.grabCut(self.img2, self.mask, self.rect, bgdmodel, fgdmodel, 1, cv.GC_INIT_WITH_MASK) except: import traceback traceback.print_exc() mask2 = np.where((self.mask==1) + (self.mask==3), 255, 0).astype('uint8') self.output = cv.bitwise_and(self.img2, self.img2, mask=mask2) print('Done') cv.imwrite(filename.rstrip('.png') + '_mask.png', mask2)#マスクを保存