def get_data(self, host_dict): if self.type == 'landmarks-manual': need_remark_face = False redraw_needed = False while len(self.input_data) > 0: data = self.input_data[0] filepath, data_rects, data_landmarks = data.filepath, data.rects, data.landmarks is_frame_done = False if need_remark_face: # need remark image from input data that already has a marked face? need_remark_face = False if len( data_rects ) != 0: # If there was already a face then lock the rectangle to it until the mouse is clicked self.rect = data_rects.pop() self.landmarks = data_landmarks.pop() data_rects.clear() data_landmarks.clear() redraw_needed = True self.rect_locked = True self.rect_size = (self.rect[2] - self.rect[0]) / 2 self.x = (self.rect[0] + self.rect[2]) / 2 self.y = (self.rect[1] + self.rect[3]) / 2 if len(data_rects) == 0: if self.cache_original_image[0] == filepath: self.original_image = self.cache_original_image[1] else: self.original_image = imagelib.normalize_channels( cv2_imread(filepath), 3) self.cache_original_image = (filepath, self.original_image) (h, w, c) = self.original_image.shape self.view_scale = 1.0 if self.manual_window_size == 0 else self.manual_window_size / ( h * (16.0 / 9.0)) if self.cache_image[0] == (h, w, c) + (self.view_scale, filepath): self.image = self.cache_image[1] else: self.image = cv2.resize(self.original_image, (int( w * self.view_scale), int(h * self.view_scale)), interpolation=cv2.INTER_LINEAR) self.cache_image = ((h, w, c) + (self.view_scale, filepath), self.image) (h, w, c) = self.image.shape sh = (0, 0, w, min(100, h)) if self.cache_text_lines_img[0] == sh: self.text_lines_img = self.cache_text_lines_img[1] else: self.text_lines_img = (imagelib.get_draw_text_lines( self.image, sh, [ '[Mouse click] - lock/unlock selection', '[Mouse wheel] - change rect', '[Enter] / [Space] - confirm / skip frame', '[,] [.]- prev frame, next frame. [Q] - skip remaining frames', '[a] - accuracy on/off (more fps)', '[h] - hide this help' ], (1, 1, 1)) * 255).astype(np.uint8) self.cache_text_lines_img = (sh, self.text_lines_img) while True: io.process_messages(0.0001) new_x = self.x new_y = self.y new_rect_size = self.rect_size mouse_events = io.get_mouse_events(self.wnd_name) for ev in mouse_events: (x, y, ev, flags) = ev if ev == io.EVENT_MOUSEWHEEL and not self.rect_locked: mod = 1 if flags > 0 else -1 diff = 1 if new_rect_size <= 40 else np.clip( new_rect_size / 10, 1, 10) new_rect_size = max(5, new_rect_size + diff * mod) elif ev == io.EVENT_LBUTTONDOWN: self.rect_locked = not self.rect_locked self.extract_needed = True elif not self.rect_locked: new_x = np.clip(x, 0, w - 1) / self.view_scale new_y = np.clip(y, 0, h - 1) / self.view_scale key_events = io.get_key_events(self.wnd_name) key, chr_key, ctrl_pressed, alt_pressed, shift_pressed = key_events[ -1] if len(key_events) > 0 else (0, 0, False, False, False) if key == ord('\r') or key == ord('\n'): #confirm frame is_frame_done = True data_rects.append(self.rect) data_landmarks.append(self.landmarks) break elif key == ord(' '): #confirm skip frame is_frame_done = True break elif key == ord(',') and len(self.result) > 0: #go prev frame if self.rect_locked: self.rect_locked = False # Only save the face if the rect is still locked data_rects.append(self.rect) data_landmarks.append(self.landmarks) self.input_data.insert(0, self.result.pop()) io.progress_bar_inc(-1) need_remark_face = True break elif key == ord('.'): #go next frame if self.rect_locked: self.rect_locked = False # Only save the face if the rect is still locked data_rects.append(self.rect) data_landmarks.append(self.landmarks) need_remark_face = True is_frame_done = True break elif key == ord('q'): #skip remaining if self.rect_locked: self.rect_locked = False data_rects.append(self.rect) data_landmarks.append(self.landmarks) while len(self.input_data) > 0: self.result.append(self.input_data.pop(0)) io.progress_bar_inc(1) break elif key == ord('h'): self.hide_help = not self.hide_help break elif key == ord('a'): self.landmarks_accurate = not self.landmarks_accurate break if self.x != new_x or \ self.y != new_y or \ self.rect_size != new_rect_size or \ self.extract_needed or \ redraw_needed: self.x = new_x self.y = new_y self.rect_size = new_rect_size self.rect = (int(self.x - self.rect_size), int(self.y - self.rect_size), int(self.x + self.rect_size), int(self.y + self.rect_size)) if redraw_needed: redraw_needed = False return ExtractSubprocessor.Data( filepath, landmarks_accurate=self.landmarks_accurate) else: return ExtractSubprocessor.Data( filepath, rects=[self.rect], landmarks_accurate=self.landmarks_accurate) else: is_frame_done = True if is_frame_done: self.result.append(data) self.input_data.pop(0) io.progress_bar_inc(1) self.extract_needed = True self.rect_locked = False else: if len(self.input_data) > 0: return self.input_data.pop(0) return None
def get_data(self, host_dict): if self.type == 'landmarks-manual': need_remark_face = False while len(self.input_data) > 0: data = self.input_data[0] filepath, data_rects, data_landmarks = data.filepath, data.rects, data.landmarks is_frame_done = False if self.image_filepath != filepath: self.image_filepath = filepath if self.cache_original_image[0] == filepath: self.original_image = self.cache_original_image[1] else: self.original_image = imagelib.normalize_channels( cv2_imread(filepath), 3) self.cache_original_image = (filepath, self.original_image) (h, w, c) = self.original_image.shape self.view_scale = 1.0 if self.manual_window_size == 0 else self.manual_window_size / ( h * (16.0 / 9.0)) if self.cache_image[0] == (h, w, c) + (self.view_scale, filepath): self.image = self.cache_image[1] else: self.image = cv2.resize(self.original_image, (int( w * self.view_scale), int(h * self.view_scale)), interpolation=cv2.INTER_LINEAR) self.cache_image = ((h, w, c) + (self.view_scale, filepath), self.image) (h, w, c) = self.image.shape sh = (0, 0, w, min(100, h)) if self.cache_text_lines_img[0] == sh: self.text_lines_img = self.cache_text_lines_img[1] else: self.text_lines_img = (imagelib.get_draw_text_lines( self.image, sh, [ '[L Mouse click] - lock/unlock selection. [Mouse wheel] - change rect', '[R Mouse Click] - manual face rectangle', '[Enter] / [Space] - confirm / skip frame', '[,] [.]- prev frame, next frame. [Q] - skip remaining frames', '[a] - accuracy on/off (more fps)', '[h] - hide this help' ], (1, 1, 1)) * 255).astype(np.uint8) self.cache_text_lines_img = (sh, self.text_lines_img) if need_remark_face: # need remark image from input data that already has a marked face? need_remark_face = False if len( data_rects ) != 0: # If there was already a face then lock the rectangle to it until the mouse is clicked self.rect = data_rects.pop() self.landmarks = data_landmarks.pop() data_rects.clear() data_landmarks.clear() self.rect_locked = True self.rect_size = (self.rect[2] - self.rect[0]) / 2 self.x = (self.rect[0] + self.rect[2]) / 2 self.y = (self.rect[1] + self.rect[3]) / 2 self.redraw() if len(data_rects) == 0: (h, w, c) = self.image.shape while True: io.process_messages(0.0001) self.ea.loop() if not self.force_landmarks: new_x = self.x new_y = self.y new_rect_size = self.rect_size mouse_events = io.get_mouse_events(self.wnd_name) for ev in mouse_events: (x, y, ev, flags) = ev if ev == io.EVENT_MOUSEWHEEL and not self.rect_locked: mod = 1 if flags > 0 else -1 diff = 1 if new_rect_size <= 40 else np.clip( new_rect_size / 10, 1, 10) new_rect_size = max(5, new_rect_size + diff * mod) elif ev == io.EVENT_LBUTTONDOWN: if self.force_landmarks: self.x = new_x self.y = new_y self.force_landmarks = False self.rect_locked = True self.redraw() else: self.rect_locked = not self.rect_locked self.extract_needed = True elif ev == io.EVENT_RBUTTONDOWN: self.ea.right_btn_down = True # self.force_landmarks = not self.force_landmarks # if self.force_landmarks: # self.rect_locked = False elif not self.rect_locked: new_x = np.clip(x, 0, w - 1) / self.view_scale new_y = np.clip(y, 0, h - 1) / self.view_scale key_events = io.get_key_events(self.wnd_name) key, chr_key, ctrl_pressed, alt_pressed, shift_pressed = key_events[ -1] if len(key_events) > 0 else (0, 0, False, False, False) if self.ea.right_btn_down and self.rect_locked: is_frame_done = True data_rects.append(self.rect) data_landmarks.append(self.landmarks) self.ea.last_outer = self.ea.cur_outer self.ea.last_landmarks = self.ea.cur_landmarks self.ea.auto = True break elif key == ord('s'): self.ea.auto = False break elif self.ea.auto and len( self.ea.last_outer) > 0 and len( self.ea.last_landmarks) > 0: # 根据上次的外框算出这次的x/y,以及外框大小 border_ratio = 0.6 last_mid = F.mid_point_by_range( self.ea.last_landmarks) last_border = np.linalg.norm( np.array(self.ea.last_outer[0]) - np.array(self.ea.last_outer[1])) last_area = F.poly_area(self.ea.last_outer) x, y = last_mid new_x = np.clip(x, 0, w - 1) / self.view_scale new_y = np.clip(y, 0, h - 1) / self.view_scale new_rect_size = last_border / 2 / self.view_scale * border_ratio # make sure rect and landmarks have been refreshed if len(self.ea.cur_outer) != 0: # 根据本次外框大小算是否valid,通过边长,面积,角度 # temp_mid = F.mid_point(self.temp_outer) cur_mid = F.mid_point_by_range( self.ea.cur_landmarks) dist = np.linalg.norm( np.array(cur_mid) - np.array(last_mid)) dist_r = dist / last_border temp_area = F.poly_area(self.ea.cur_outer) area_r = temp_area / last_area v0 = np.array(last_mid) - np.array( self.ea.last_outer[0]) v1 = np.array(cur_mid) - np.array( self.ea.cur_outer[0]) angle = math.fabs(F.angle_between(v0, v1)) if dist_r < 0.5 and 0.5 < area_r < 1.5 and angle < 0.7: is_frame_done = True self.ea.last_outer = self.ea.cur_outer self.ea.last_landmarks = self.ea.cur_landmarks data_rects.append(self.rect) data_landmarks.append(self.landmarks) self.ea.auto = True break elif self.x != new_x or self.y != new_y: # 可以在等一轮更新后试一下 pass else: self.ea.auto = False F.beep() elif key == ord('n') and len(self.result) > 0: # go prev frame without save and clear result self.rect_locked = False n = 10 if shift_pressed else 1 while n > 0 and len(self.result) > 0: self.input_data.insert(0, self.result.pop()) self.input_data[0].rects.clear() self.input_data[0].landmarks.clear() io.progress_bar_inc(-1) n -= 1 # 直接无视之前的结果,重新标注 self.extract_needed = True break elif key == ord('m') and len(self.input_data) > 0: # go next frame without save self.rect_locked = False n = 10 if shift_pressed else 1 while n > 0 and len(self.input_data) > 0: self.result.append(self.input_data.pop(0)) io.progress_bar_inc(1) n -= 1 # 直接无视之前的结果,重新标注 self.extract_needed = True break elif key == ord('\r') or key == ord('\n'): #confirm frame is_frame_done = True data_rects.append(self.rect) data_landmarks.append(self.landmarks) break elif key == ord(' '): #confirm skip frame is_frame_done = True break elif key == ord(',') and len(self.result) > 0: #go prev frame if self.rect_locked: self.rect_locked = False # Only save the face if the rect is still locked data_rects.append(self.rect) data_landmarks.append(self.landmarks) self.input_data.insert(0, self.result.pop()) io.progress_bar_inc(-1) need_remark_face = True break elif key == ord('.'): #go next frame if self.rect_locked: self.rect_locked = False # Only save the face if the rect is still locked data_rects.append(self.rect) data_landmarks.append(self.landmarks) need_remark_face = True is_frame_done = True break elif key == ord('q'): #skip remaining if self.rect_locked: self.rect_locked = False data_rects.append(self.rect) data_landmarks.append(self.landmarks) while len(self.input_data) > 0: self.result.append(self.input_data.pop(0)) io.progress_bar_inc(1) break elif key == ord('h'): self.hide_help = not self.hide_help break elif key == ord('a'): self.landmarks_accurate = not self.landmarks_accurate break if self.force_landmarks: pt2 = np.float32([new_x, new_y]) pt1 = np.float32([self.x, self.y]) pt_vec_len = npla.norm(pt2 - pt1) pt_vec = pt2 - pt1 if pt_vec_len != 0: pt_vec /= pt_vec_len self.rect_size = pt_vec_len self.rect = (int(self.x - self.rect_size), int(self.y - self.rect_size), int(self.x + self.rect_size), int(self.y + self.rect_size)) if pt_vec_len > 0: lmrks = np.concatenate( (np.zeros((17, 2), np.float32), LandmarksProcessor.landmarks_2D), axis=0) lmrks -= lmrks[30:31, :] mat = cv2.getRotationMatrix2D( (0, 0), -np.arctan2(pt_vec[1], pt_vec[0]) * 180 / math.pi, pt_vec_len) mat[:, 2] += (self.x, self.y) self.landmarks = LandmarksProcessor.transform_points( lmrks, mat) self.redraw() elif self.x != new_x or \ self.y != new_y or \ self.rect_size != new_rect_size or \ self.extract_needed: self.x = new_x self.y = new_y self.rect_size = new_rect_size self.rect = (int(self.x - self.rect_size), int(self.y - self.rect_size), int(self.x + self.rect_size), int(self.y + self.rect_size)) return ExtractSubprocessor.Data( filepath, rects=[self.rect], landmarks_accurate=self.landmarks_accurate) else: is_frame_done = True if is_frame_done: self.result.append(data) self.input_data.pop(0) io.progress_bar_inc(1) self.extract_needed = True self.rect_locked = False self.ea.cur_outer = [] else: if len(self.input_data) > 0: return self.input_data.pop(0) return None