def select_region(img, mask, color=None): """ Given a color mask and image and a given color, create an alpha channel on the given image, exposing only the regions associated with the color mask matching the given color. If the color is not provided, choose one of the available colors in the mask. Return the RGBA image and the color. :param img: :param mask: :return: @type img: image_wrap.ImageWrapper @type mask: image_wrap.ImageWrapper """ rgba = img.convert('RGBA').to_array() mask = mask.to_array() channel = np.zeros((mask.shape[0], mask.shape[1])).astype('uint8') if color is None or color == 'None': colors = np.unique( np.vstack(mask).view([('', mask.dtype)] * np.prod(np.vstack(mask).shape[1]))) colors = [color for color in colors.tolist()] colors.remove((0, 0, 0)) color = colors[np.random.randint(0, len(colors) - 1)] channel[np.all(mask == [color[0], color[1], color[2]], axis=2)] = 255 (contours, _) = cv2api.findContours(channel.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: if len(cnt) > 3: channel = np.zeros((mask.shape[0], mask.shape[1])).astype('uint8') cv2.fillConvexPoly(channel, cnt, 255) break rgba[:, :, 3] = channel return image_wrap.ImageWrapper(rgba), color
def minimum_bounding_ellipse(image): """ :param image: :return: (x, y, MA, ma, angle, area, contour) @rtype : (int,int,int,int,float, float,np.array) """ (contours, _) = cv2api.findContours(image.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) selected = [] for cnt in contours: try: bounded_info = minimum_bounding_ellipse_of_points(cnt) if bounded_info is not None: selected.append(bounded_info) except: continue if len(selected) == 0: return None selected = sorted(selected, key=lambda cnt: cnt[5], reverse=True) return selected[0] if len(selected) > 0 else None
def minimum_bounding_box(image): # (contours, _) = cv2.findContours(image.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) contours, hierarchy = cv2api.findContours(image.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) selected = [] for cnt in contours: try: M = cv2.moments(cnt) x = int(M['m10'] / M['m00']) y = int(M['m01'] / M['m00']) x1, y1, w, h = cv2.boundingRect(cnt) w = w - 1 h = h - 1 selected.append((w, h, w * h, x, y)) except: continue selected = sorted(selected, key=lambda cnt: cnt[2], reverse=True) if len(selected) == 0: x, y, w, h = tool_set.widthandheight(image) selected = [(w, h, w * h, x + w / 2, y + h / 2)] return selected[0]
def performPaste(img, img_to_paste, approach, segment_algorithm): mask_of_image_to_paste = img_to_paste.to_mask().to_array() out2 = None if approach == 'texture': denoise_img = denoise_tv_bregman(np.asarray(img), weight=0.4) denoise_img = (denoise_img * 255).astype('uint8') gray = cv2.cvtColor(denoise_img, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) mask_of_image_to_paste_ellipse = minimum_bounding_ellipse( mask_of_image_to_paste) if mask_of_image_to_paste_ellipse is not None: img_to_paste = img_to_paste.apply_mask_rgba(mask_of_image_to_paste) dims = (math.ceil(denoise_img.shape[0] / 500.0) * 500.0, math.ceil(denoise_img.shape[1] / 500.0) * 500.0) sigma = max(1.0, math.log10(dims[0] * dims[1] / 10000.0) - 0.5) min_size = max(100.0, math.ceil(sigma * 10.0) * 10) while out2 is None and sigma < 5: if segment_algorithm == 'slic': masksize = float(sum(sum(mask_of_image_to_paste)) / 255) imgsize = float(img.size[0] * img.size[1]) labels1 = segmentation.slic( gray, compactness=5, n_segments=min(500, int(imgsize / (sigma * 2 * masksize)))) else: labels1 = segmentation.felzenszwalb(gray, scale=min_size, sigma=sigma, min_size=int(min_size)) # Compute the Region Adjacency Graph using mean colors. # # Given an image and its initial segmentation, this method constructs the corresponding RAG. # Each node represents a set of pixels within image with the same label in labels. # The weight between two adjacent regions represents how similar or dissimilar two # regions are depending on the mode parameter. cutThresh = 0.00000001 labelset = np.unique(labels1) sizeOfLabelSet = len(labelset) increment = 0.0000005 while increment < 0.01 and (len(labels1) > 100000 or sizeOfLabelSet > 1000): g = graph.rag_mean_color(denoise_img, labels1, mode='similarity') labels1 = graph.cut_threshold(labels1, g, cutThresh) labelset = np.unique(labels1) # too slow of a change if sizeOfLabelSet - len(labelset) < 5: increment *= 10 sizeOfLabelSet = len(labelset) cutThresh += increment labelset = np.unique(labels1) for label in labelset: if label == 0: continue mask = np.zeros(labels1.shape) mask[labels1 == label] = 255 mask = mask.astype('uint8') ret, thresh = cv2.threshold(mask, 127, 255, 0) (contours, _) = cv2api.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) areas = [(cnt, cv2.contourArea(cnt)) for cnt in contours if cv2.moments(cnt)['m00'] > 2.0] contours = sorted(areas, key=lambda cnt: cnt[1], reverse=True) contours = contours[0:min(20, len(contours))] if len(contours) > 0: for contour in contours: try: placement_ellipse = minimum_bounding_ellipse_of_points( contour[0]) if placement_ellipse is not None: transform_matrix = build_transform_matrix( placement_ellipse, mask_of_image_to_paste_ellipse) if transform_matrix is None: continue transformed_image = transform_image( img_to_paste.to_array(), transform_matrix) else: transformed_image = img_to_paste.to_array() out2 = tool_set.place_in_image( ImageWrapper(transformed_image).to_mask(). to_array(), transformed_image, np.asarray(img), (placement_ellipse[0], placement_ellipse[1])) if out2 is not None: break except Exception as e: continue if out2 is not None: break sigma += 0.5 if out2 is None: transform_matrix, out2 = pasteAnywhere(img, img_to_paste.to_array(), mask_of_image_to_paste, approach == 'simple') return transform_matrix, out2
def transform(img, source, target, **kwargs): op = kwargs['op'] if 'op' in kwargs else 'felzenszwalb' denoise_img = denoise_tv_bregman(numpy.asarray(img), weight=0.4) denoise_img = (denoise_img * 255).astype('uint8') gray = cv2.cvtColor(denoise_img, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) imgsize = denoise_img.shape[0] * denoise_img.shape[1] max_area = imgsize / 100 dims = (math.ceil(denoise_img.shape[0] / 500.0) * 500.0, math.ceil(denoise_img.shape[1] / 500.0) * 500.0) sigma = max(0.75, math.log10(dims[0] * dims[1] / 10000.0) - 0.5) min_size = max(0.05 * denoise_img.shape[0] * denoise_img.shape[1], math.ceil(sigma * 10.0) * 10) if op == 'felzenszwalb': segment_labels = felzenszwalb(gray, scale=min_size, sigma=sigma, min_size=int(min_size)) unique_labels, label_counts = numpy.unique(segment_labels, return_counts=True) else: numsegments = max(16, int(imgsize * 0.000025)) segment_labels = slic(img, compactness=5, n_segments=numsegments) unique_labels, label_counts = numpy.unique(segment_labels, return_counts=True) cnts = [] for label in unique_labels: mask = numpy.zeros(gray.shape, dtype="uint8") mask[segment_labels == label] = 255 cnts.extend( cv2api.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]) areas = [(cnt, cv2.contourArea(cnt)) for cnt in cnts] areas = [area for area in areas if area[1] > 4.0 and area[1] <= max_area] cnts = sorted(areas, key=lambda cnt: cnt[1], reverse=True) cnts = [cnt for cnt in cnts] # top 15 largest cnts = cnts[0:min(15, len(cnts))] if len(cnts) == 0: cnt = build_box_contour(denoise_img.shape) else: cnt = random.choice(cnts)[0] mask = numpy.zeros((denoise_img.shape[0], denoise_img.shape[1]), numpy.uint8) cv2.fillPoly(mask, pts=[cnt], color=255) if 'alpha' not in kwargs or kwargs['alpha'] == 'yes': rgba = numpy.asarray(img.convert('RGBA')) rgba = numpy.copy(rgba) rgba[mask != 255] = 0 ImageWrapper(rgba).save(target) else: ImageWrapper(mask.astype('uint8')).save(target) shape = mask.shape x, y, w, h = cv2.boundingRect(cnt) trial_boxes = [[0, 0, x, shape[0] - h], [0, 0, shape[1] - w, y], [x + w, 0, shape[1] - w, shape[0] - h], [0, y + h, shape[1] - w, shape[0] - h]] boxes = [box for box in trial_boxes \ if (box[2] - box[0]) > 0 and (box[3] - box[1]) > 0] if len(boxes) == 0: box = [1, 1, shape[1] - w, shape[0] - h] else: box = choice(boxes) new_position_x = randint(box[0], box[2]) new_position_y = randint(box[1], box[3]) return {'paste_x': new_position_x, 'paste_y': new_position_y}, None