import cv2 import os import numpy as np import sys def draw_poly(img, bounding_poly): pts = np.array(bounding_poly, np.int32) #http://stackoverflow.com/a/15343106/3479446 mask = np.zeros(img.shape[:2], dtype=np.uint8) roi_corners = np.array([pts], dtype=np.int32) ignore_mask_color = (255,) cv2.fillPoly(mask, roi_corners, ignore_mask_color, lineType=cv2.LINE_8) return mask def post_process(img): # img = open_close(img) img = get_largest_cc(img) img = fill_holes(img) # img = min_area_rectangle(img) img, coords = improve_min_area_rectangle(img) return img, coords def open_close(img): kernel = np.ones((3,3),np.uint8) erosion = cv2.erode(img,kernel,iterations = 15) dilation = cv2.dilate(erosion,kernel,iterations = 15) return dilation def get_largest_cc(img): img = img.copy() ret, th = cv2.threshold(img,127,255,cv2.THRESH_BINARY) connectivity = 4 output= cv2.connectedComponentsWithStats(th, connectivity, cv2.CV_32S) cnts = output[2][1:,4] largest = cnts.argmax() + 1 img[output[1] != largest] = 0 return img def get_iou(gt_img, pred_img): inter = gt_img & pred_img union = gt_img | pred_img iou = np.count_nonzero(inter) / float(np.count_nonzero(union)) return iou def draw_box(img, box): box = np.int0(box) draw = np.zeros_like(img) cv2.drawContours(draw,[box],0,(255),-1) return draw def compute_iou(img, box): # box = np.int0(box) # draw = np.zeros_like(img) # cv2.drawContours(draw,[box],0,(255),-1) draw = draw_box(img, box) v = get_iou(img, draw) return v def step_box(img, box, step_size=1): best_val = -1 best_box = None for index, x in np.ndenumerate(box): for d in [-step_size, step_size]: alt_box = box.copy() alt_box[index] = x + d v = compute_iou(img, alt_box) if best_val < v: best_val = v best_box = alt_box return best_val, best_box def improve_min_area_rectangle(img): img = img.copy() _, contours,_ = cv2.findContours(img, 1, 2) cnt = contours[0] rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) best_val = compute_iou(img, box) best_box = box while True: new_val, new_box = step_box(img, best_box, step_size=1) # print new_val if new_val <= best_val: break best_val = new_val best_box = new_box return draw_box(img, best_box), best_box def min_area_rectangle(img): img = img.copy() _, contours,_ = cv2.findContours(img, 1, 2) cnt = contours[0] rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) box = np.int0(box) draw = np.zeros_like(img) cv2.drawContours(draw,[box],0,(255),-1) return draw def fill_holes(img): im_th = img.copy() # Copy the thresholded image. im_floodfill = im_th.copy() # Mask used to flood filling. # Notice the size needs to be 2 pixels than the image. h, w = im_th.shape[:2] mask = np.zeros((h+2, w+2), np.uint8) # Floodfill from point (0, 0) if img[0,0] != 0: print "WARNING: Filling something you shouldn't" cv2.floodFill(im_floodfill, mask, (0,0), 255); # Invert floodfilled image im_floodfill_inv = cv2.bitwise_not(im_floodfill) # Combine the two images to get the foreground. im_out = im_th | im_floodfill_inv return im_out if __name__ == "__main__": pred_folder = sys.argv[1] out_folder = sys.argv[2] pred_imgs = {} for root, folders, files in os.walk(pred_folder): for f in files: if f.endswith(".png"): pred_imgs[f] = os.path.join(root, f) for k in pred_imgs: pred_img = cv2.imread(pred_imgs[k], 0) post_img = post_process(pred_img) cv2.imwrite(os.path.join(out_folder, k), post_img)