Esempio n. 1
0
def video_completion_seamless(args):

    print('Pytorch 1.6.0 for flow prediction')
    try:
        RAFT_model = initialize_RAFT(args)
    except:
        RAFT_model = None

    # Loads frames.
    filename_list = glob.glob(os.path.join(args.path, '*.png')) + \
                    glob.glob(os.path.join(args.path, '*.jpg'))

    # Obtains imgH, imgW and nFrame.
    imgH, imgW = np.array(Image.open(filename_list[0])).shape[:2]
    nFrame = len(filename_list)

    # Loads video.
    video = []
    for filename in sorted(filename_list):
        video.append(
            torch.from_numpy(np.array(Image.open(filename)).astype(
                np.uint8)).permute(2, 0, 1).float())

    video = torch.stack(video, dim=0)
    video = video.to('cuda')

    # Calcutes the corrupted flow.
    corrFlowF = calculate_flow(args, RAFT_model, video, 'forward')
    corrFlowB = calculate_flow(args, RAFT_model, video, 'backward')
    print('\nFinish Calculating flow.')

    # Makes sure video is in BGR (opencv) format.
    video = video.permute(2, 3, 1, 0).cpu().numpy()[:, :, ::-1, :] / 255.

    if args.mode == 'video_extrapolation':

        # Creates video and flow where the extrapolated region are missing.
        video, corrFlowF, corrFlowB, flow_mask, mask_dilated, start_point, end_point = extrapolation(
            args, video, corrFlowF, corrFlowB)
        imgH, imgW = video.shape[:2]

        # mask indicating the missing region in the video.
        mask = np.tile(flow_mask[..., None], (1, 1, nFrame))
        flow_mask = np.tile(flow_mask[..., None], (1, 1, nFrame))
        mask_dilated = np.tile(mask_dilated[..., None], (1, 1, nFrame))

    else:
        # Loads masks.
        filename_list = glob.glob(os.path.join(args.path_mask, '*.png')) + \
                        glob.glob(os.path.join(args.path_mask, '*.jpg'))

        mask = []
        mask_dilated = []
        flow_mask = []
        for filename in sorted(filename_list):
            mask_img = np.array(Image.open(filename).convert('L'))

            # Dilate 15 pixel so that all known pixel is trustworthy
            flow_mask_img = scipy.ndimage.binary_dilation(mask_img,
                                                          iterations=15)
            # Close the small holes inside the foreground objects
            flow_mask_img = cv2.morphologyEx(flow_mask_img.astype(np.uint8),
                                             cv2.MORPH_CLOSE,
                                             np.ones((21, 21),
                                                     np.uint8)).astype(np.bool)
            flow_mask_img = scipy.ndimage.binary_fill_holes(
                flow_mask_img).astype(np.bool)
            flow_mask.append(flow_mask_img)

            mask_img = scipy.ndimage.binary_dilation(mask_img, iterations=5)
            mask_img = scipy.ndimage.binary_fill_holes(mask_img).astype(
                np.bool)
            mask.append(mask_img)
            mask_dilated.append(gradient_mask(mask_img))

        # mask indicating the missing region in the video.
        mask = np.stack(mask, -1).astype(np.bool)
        mask_dilated = np.stack(mask_dilated, -1).astype(np.bool)
        flow_mask = np.stack(flow_mask, -1).astype(np.bool)

    if args.edge_guide:

        print('Pytorch 1.6.0 for edge completion')
        try:
            from edgeconnect.networks import EdgeGenerator_
            EdgeGenerator = EdgeGenerator_()
            EdgeComp_ckpt = torch.load(args.edge_completion_model)
            EdgeGenerator.load_state_dict(EdgeComp_ckpt['generator'])
            EdgeGenerator.to(torch.device('cuda:0'))
            EdgeGenerator.eval()
        except:
            EdgeGenerator = None

        # Edge completion.
        FlowF_edge = edge_completion(args, EdgeGenerator, corrFlowF, flow_mask,
                                     'forward')
        FlowB_edge = edge_completion(args, EdgeGenerator, corrFlowB, flow_mask,
                                     'backward')
    else:
        FlowF_edge, FlowB_edge = None, None

    # Completes the flow.
    videoFlowF = complete_flow(args, corrFlowF, flow_mask, 'forward',
                               FlowF_edge)
    videoFlowB = complete_flow(args, corrFlowB, flow_mask, 'backward',
                               FlowB_edge)

    # Prepare gradients
    gradient_x = np.empty(((imgH, imgW, 3, 0)), dtype=np.float32)
    gradient_y = np.empty(((imgH, imgW, 3, 0)), dtype=np.float32)

    for indFrame in range(nFrame):
        img = video[:, :, :, indFrame]
        img[mask[:, :, indFrame], :] = 0
        img = cv2.inpaint(
            (img * 255).astype(np.uint8), mask[:, :, indFrame].astype(
                np.uint8), 3, cv2.INPAINT_TELEA).astype(np.float32) / 255.

        gradient_x_ = np.concatenate(
            (np.diff(img, axis=1), np.zeros((imgH, 1, 3), dtype=np.float32)),
            axis=1)
        gradient_y_ = np.concatenate(
            (np.diff(img, axis=0), np.zeros((1, imgW, 3), dtype=np.float32)),
            axis=0)
        gradient_x = np.concatenate(
            (gradient_x, gradient_x_.reshape(imgH, imgW, 3, 1)), axis=-1)
        gradient_y = np.concatenate(
            (gradient_y, gradient_y_.reshape(imgH, imgW, 3, 1)), axis=-1)

        gradient_x[mask_dilated[:, :, indFrame], :, indFrame] = 0
        gradient_y[mask_dilated[:, :, indFrame], :, indFrame] = 0

    iter = 0
    mask_tofill = mask
    gradient_x_filled = gradient_x  # corrupted gradient_x, mask_gradient indicates the missing gradient region
    gradient_y_filled = gradient_y  # corrupted gradient_y, mask_gradient indicates the missing gradient region
    mask_gradient = mask_dilated
    video_comp = video
    try:
        from spatial_inpaint import spatial_inpaint
        from frame_inpaint import DeepFillv1
        deepfill = DeepFillv1(
            pretrained_model='/home/chengao/Weight/imagenet_deepfill.pth',
            image_shape=[imgH, imgW])
    except:
        print('Please switch to Pytorch 0.4.0')
        return

    while ((np.sum(mask) > 0) and iter <= 5):
        create_dir(
            os.path.join(args.outroot, 'frame_seamless_comp_' + str(iter)))

        # Gradient propagation.
        gradient_x_filled, gradient_y_filled, mask_gradient = \
            get_flowNN_gradient(args,
                                gradient_x_filled,
                                gradient_y_filled,
                                mask,
                                mask_gradient,
                                videoFlowF,
                                videoFlowB,
                                None,
                                None)

        # if there exist holes in mask, Poisson blending will fail. So I did this trick. I sacrifice some value. Another solution is to modify Poisson blending.
        for indFrame in range(nFrame):
            mask_gradient[:, :, indFrame] = scipy.ndimage.binary_fill_holes(
                mask_gradient[:, :, indFrame]).astype(np.bool)

        # After one gradient propagation iteration
        # gradient --> RGB
        for indFrame in range(nFrame):
            print("Poisson blending frame {0:3d}".format(indFrame))

            if mask[:, :, indFrame].sum() > 0:
                try:
                    flowBlend, UnfilledMask = Poisson_blend_img(
                        video_comp[:, :, :, indFrame],
                        gradient_x_filled[:, 0:imgW - 1, :, indFrame],
                        gradient_y_filled[0:imgH - 1, :, :, indFrame],
                        mask[:, :, indFrame], mask_gradient[:, :, indFrame])
                    # UnfilledMask = scipy.ndimage.binary_fill_holes(UnfilledMask).astype(np.bool)
                except:
                    flowBlend, UnfilledMask = video_comp[:, :, :,
                                                         indFrame], mask[:, :,
                                                                         indFrame]

                flowBlend = np.clip(flowBlend, 0, 1.0)
                tmp = cv2.inpaint((flowBlend * 255).astype(np.uint8),
                                  UnfilledMask.astype(np.uint8), 3,
                                  cv2.INPAINT_TELEA).astype(np.float32) / 255.
                flowBlend[UnfilledMask, :] = tmp[UnfilledMask, :]

                video_comp[:, :, :, indFrame] = flowBlend
                mask[:, :, indFrame] = UnfilledMask

                flowBlend_ = copy.deepcopy(flowBlend)
                flowBlend_[mask[:, :, indFrame], :] = [0, 1., 0]
            else:
                flowBlend_ = video_comp[:, :, :, indFrame]

            cv2.imwrite(
                os.path.join(args.outroot, 'frame_seamless_comp_' + str(iter),
                             '%05d.png' % indFrame), flowBlend_ * 255.)

        video_comp_ = (video_comp * 255).astype(np.uint8).transpose(
            3, 0, 1, 2)[:, :, :, ::-1]
        imageio.mimwrite(os.path.join(args.outroot,
                                      'frame_seamless_comp_' + str(iter),
                                      'video_extrapolation.mp4'),
                         video_comp_,
                         fps=12,
                         quality=8,
                         macro_block_size=1)
        imageio.mimsave(os.path.join(args.outroot,
                                     'frame_seamless_comp_' + str(iter),
                                     'video_extrapolation.gif'),
                        video_comp_,
                        format='gif',
                        fps=12)

        mask, video_comp = spatial_inpaint(deepfill, mask, video_comp)
        iter += 1

        # Re-calculate gradient_x/y_filled and mask_gradient
        for indFrame in range(nFrame):
            mask_gradient[:, :, indFrame] = gradient_mask(mask[:, :, indFrame])

            gradient_x_filled[:, :, :, indFrame] = np.concatenate(
                (np.diff(video_comp[:, :, :, indFrame],
                         axis=1), np.zeros((imgH, 1, 3), dtype=np.float32)),
                axis=1)
            gradient_y_filled[:, :, :, indFrame] = np.concatenate(
                (np.diff(video_comp[:, :, :, indFrame],
                         axis=0), np.zeros((1, imgW, 3), dtype=np.float32)),
                axis=0)

            gradient_x_filled[mask_gradient[:, :, indFrame], :, indFrame] = 0
            gradient_y_filled[mask_gradient[:, :, indFrame], :, indFrame] = 0
Esempio n. 2
0
def video_completion(args):

    print('Pytorch 1.6.0 for flow prediction')
    try:
        RAFT_model = initialize_RAFT(args)
    except:
        RAFT_model = None

    # Loads frames.
    filename_list = glob.glob(os.path.join(args.path, '*.png')) + \
                    glob.glob(os.path.join(args.path, '*.jpg'))

    # Obtains imgH, imgW and nFrame.
    imgH, imgW = np.array(Image.open(filename_list[0])).shape[:2]
    nFrame = len(filename_list)

    # Loads video.
    video = []
    for filename in sorted(filename_list):
        video.append(
            torch.from_numpy(np.array(Image.open(filename)).astype(
                np.uint8)).permute(2, 0, 1).float())

    video = torch.stack(video, dim=0)
    video = video.to('cuda')

    # Calcutes the corrupted flow.
    corrFlowF = calculate_flow(args, RAFT_model, video, 'forward')
    corrFlowB = calculate_flow(args, RAFT_model, video, 'backward')
    print('\nFinish Calculating flow.')

    # Makes sure video is in BGR (opencv) format.
    video = video.permute(2, 3, 1, 0).cpu().numpy()[:, :, ::-1, :] / 255.

    if args.mode == 'video_extrapolation':

        # Creates video and flow where the extrapolated region are missing.
        video, corrFlowF, corrFlowB, flow_mask, mask_dilated, start_point, end_point = extrapolation(
            args, video, corrFlowF, corrFlowB)
        imgH, imgW = video.shape[:2]

        # mask indicating the missing region in the video.
        mask = np.tile(flow_mask[..., None], (1, 1, nFrame))
        flow_mask = np.tile(flow_mask[..., None], (1, 1, nFrame))

    else:
        # Loads masks.
        filename_list = glob.glob(os.path.join(args.path_mask, '*.png')) + \
                        glob.glob(os.path.join(args.path_mask, '*.jpg'))

        mask = []
        flow_mask = []
        for filename in sorted(filename_list):
            mask_img = np.array(Image.open(filename).convert('L'))
            mask.append(mask_img)

            # Dilate 15 pixel so that all known pixel is trustworthy
            flow_mask_img = scipy.ndimage.binary_dilation(mask_img,
                                                          iterations=15)
            # Close the small holes inside the foreground objects
            flow_mask_img = cv2.morphologyEx(flow_mask_img.astype(np.uint8),
                                             cv2.MORPH_CLOSE,
                                             np.ones((21, 21),
                                                     np.uint8)).astype(np.bool)
            flow_mask_img = scipy.ndimage.binary_fill_holes(
                flow_mask_img).astype(np.bool)
            flow_mask.append(flow_mask_img)

        # mask indicating the missing region in the video.
        mask = np.stack(mask, -1).astype(np.bool)
        flow_mask = np.stack(flow_mask, -1).astype(np.bool)

    if args.edge_guide:

        print('Pytorch 1.6.0 for edge completion')
        try:
            from edgeconnect.networks import EdgeGenerator_
            EdgeGenerator = EdgeGenerator_()
            EdgeComp_ckpt = torch.load(args.edge_completion_model)
            EdgeGenerator.load_state_dict(EdgeComp_ckpt['generator'])
            EdgeGenerator.to(torch.device('cuda:0'))
            EdgeGenerator.eval()
        except:
            EdgeGenerator = None

        # Edge completion.
        FlowF_edge = edge_completion(args, EdgeGenerator, corrFlowF, flow_mask,
                                     'forward')
        FlowB_edge = edge_completion(args, EdgeGenerator, corrFlowB, flow_mask,
                                     'backward')
    else:
        FlowF_edge, FlowB_edge = None, None

    # Completes the flow.
    videoFlowF = complete_flow(args, corrFlowF, flow_mask, 'forward',
                               FlowF_edge)
    videoFlowB = complete_flow(args, corrFlowB, flow_mask, 'backward',
                               FlowB_edge)

    iter = 0
    mask_tofill = mask
    video_comp = video

    try:
        from spatial_inpaint import spatial_inpaint
        from frame_inpaint import DeepFillv1
        deepfill = DeepFillv1(
            pretrained_model='/home/chengao/Weight/imagenet_deepfill.pth',
            image_shape=[imgH, imgW])
    except:
        print('Please switch to Pytorch 0.4.0')
        return

    while ((np.sum(mask_tofill) > 0) and iter <= 5):
        create_dir(os.path.join(args.outroot, 'frame_comp_' + str(iter)))

        # Color propagation.
        video_comp, mask_tofill, _ = get_flowNN(args, video_comp, mask_tofill,
                                                videoFlowF, videoFlowB, None,
                                                None)

        for i in range(nFrame):
            mask_tofill[:, :,
                        i] = scipy.ndimage.binary_dilation(mask_tofill[:, :,
                                                                       i],
                                                           iterations=2)
            img = video_comp[:, :, :, i] * 255
            img[mask_tofill[:, :, i]] = [0, 255, 0]
            cv2.imwrite(
                os.path.join(args.outroot, 'frame_comp_' + str(iter),
                             '%05d.png' % i), img)

        video_comp_ = (video_comp * 255).astype(np.uint8).transpose(
            3, 0, 1, 2)[:, :, :, ::-1]
        imageio.mimwrite(os.path.join(args.outroot, 'frame_comp_' + str(iter),
                                      'video_extrapolation.mp4'),
                         video_comp_,
                         fps=12,
                         quality=8,
                         macro_block_size=1)
        imageio.mimsave(os.path.join(args.outroot, 'frame_comp_' + str(iter),
                                     'video_extrapolation.gif'),
                        video_comp_,
                        format='gif',
                        fps=12)
        mask_tofill, video_comp = spatial_inpaint(deepfill, mask_tofill,
                                                  video_comp)
        iter += 1
Esempio n. 3
0
def video_completion(args):

    # Flow model.
    RAFT_model = initialize_RAFT(args)

    # Loads frames.
    filename_list = glob.glob(os.path.join(args.path, '*.png')) + \
                    glob.glob(os.path.join(args.path, '*.jpg'))

    # Obtains imgH, imgW and nFrame.
    imgH, imgW = np.array(Image.open(filename_list[0])).shape[:2]
    nFrame = len(filename_list)

    # Loads video.
    video = []
    for filename in sorted(filename_list):
        video.append(
            torch.from_numpy(
                np.array(Image.open(filename)).astype(
                    np.uint8)[..., :3]).permute(2, 0, 1).float())

    video = torch.stack(video, dim=0)
    video = video.to('cuda')

    # Calcutes the corrupted flow.
    corrFlowF, corrFlowB, corrFlowNLF, corrFlowNLB = calculate_flow(
        args, RAFT_model, video)
    print('\nFinish flow prediction.')

    # Makes sure video is in BGR (opencv) format.
    video = video.permute(2, 3, 1, 0).cpu().numpy()[:, :, ::-1, :] / 255.

    if args.mode == 'video_extrapolation':

        # Creates video and flow where the extrapolated region are missing.
        video, corrFlowF, corrFlowB, corrFlowNLF, corrFlowNLB, flow_mask, mask_dilated, start_point, end_point = extrapolation(
            args, video, corrFlowF, corrFlowB, corrFlowNLF, corrFlowNLB)
        imgH, imgW = video.shape[:2]

        # mask indicating the missing region in the video.
        mask = np.tile(flow_mask[..., None], (1, 1, nFrame))
        flow_mask = np.tile(flow_mask[..., None], (1, 1, nFrame))

    else:
        # Loads masks.
        filename_list = glob.glob(os.path.join(args.path_mask, '*.png')) + \
                        glob.glob(os.path.join(args.path_mask, '*.jpg'))

        mask = []
        flow_mask = []
        for filename in sorted(filename_list):
            mask_img = np.array(Image.open(filename).convert('L'))
            mask.append(mask_img)

            # Dilate 15 pixel so that all known pixel is trustworthy
            flow_mask_img = scipy.ndimage.binary_dilation(mask_img,
                                                          iterations=15)
            # Close the small holes inside the foreground objects
            flow_mask_img = cv2.morphologyEx(flow_mask_img.astype(np.uint8),
                                             cv2.MORPH_CLOSE,
                                             np.ones((21, 21),
                                                     np.uint8)).astype(bool)
            flow_mask_img = scipy.ndimage.binary_fill_holes(
                flow_mask_img).astype(bool)
            flow_mask.append(flow_mask_img)

        # mask indicating the missing region in the video.
        mask = np.stack(mask, -1).astype(bool)
        flow_mask = np.stack(flow_mask, -1).astype(bool)

    if args.edge_guide:
        # Edge completion model.
        EdgeGenerator = EdgeGenerator_()
        EdgeComp_ckpt = torch.load(args.edge_completion_model)
        EdgeGenerator.load_state_dict(EdgeComp_ckpt['generator'])
        EdgeGenerator.to(torch.device('cuda:0'))
        EdgeGenerator.eval()

        # Edge completion.
        FlowF_edge = edge_completion(args, EdgeGenerator, corrFlowF, flow_mask,
                                     'forward')
        FlowB_edge = edge_completion(args, EdgeGenerator, corrFlowB, flow_mask,
                                     'backward')
        print('\nFinish edge completion.')
    else:
        FlowF_edge, FlowB_edge = None, None

    # Completes the flow.
    videoFlowF = complete_flow(args, corrFlowF, flow_mask, 'forward',
                               FlowF_edge)
    videoFlowB = complete_flow(args, corrFlowB, flow_mask, 'backward',
                               FlowB_edge)

    if args.Nonlocal:
        videoNonLocalFlowF = complete_flow(args, corrFlowNLF, flow_mask,
                                           'nonlocal_forward', None)
        videoNonLocalFlowB = complete_flow(args, corrFlowNLB, flow_mask,
                                           'nonlocal_backward', None)
    else:
        videoNonLocalFlowF = None
        videoNonLocalFlowB = None
    print('\nFinish flow completion.')

    iter = 0
    mask_tofill = mask
    video_comp = video

    # Image inpainting model.
    deepfill = DeepFillv1(pretrained_model=args.deepfill_model,
                          image_shape=[imgH, imgW])

    # We iteratively complete the video.
    while (np.sum(mask_tofill) > 0):
        create_dir(os.path.join(args.outroot, 'frame_comp_' + str(iter)))

        # Color propagation.
        video_comp, mask_tofill, _ = get_flowNN(args, video_comp, mask_tofill,
                                                videoFlowF, videoFlowB,
                                                videoNonLocalFlowF,
                                                videoNonLocalFlowB)

        for i in range(nFrame):
            mask_tofill[:, :,
                        i] = scipy.ndimage.binary_dilation(mask_tofill[:, :,
                                                                       i],
                                                           iterations=2)
            img = video_comp[:, :, :, i] * 255
            # Green indicates the regions that are not filled yet.
            img[mask_tofill[:, :, i]] = [0, 255, 0]
            cv2.imwrite(
                os.path.join(args.outroot, 'frame_comp_' + str(iter),
                             '%05d.png' % i), img)

        # video_comp_ = (video_comp * 255).astype(np.uint8).transpose(3, 0, 1, 2)[:, :, :, ::-1]
        # imageio.mimwrite(os.path.join(args.outroot, 'frame_comp_' + str(iter), 'intermediate_{0}.mp4'.format(str(iter))), video_comp_, fps=12, quality=8, macro_block_size=1)
        # imageio.mimsave(os.path.join(args.outroot, 'frame_comp_' + str(iter), 'intermediate_{0}.gif'.format(str(iter))), video_comp_, format='gif', fps=12)
        mask_tofill, video_comp = spatial_inpaint(deepfill, mask_tofill,
                                                  video_comp)
        iter += 1

    create_dir(os.path.join(args.outroot, 'frame_comp_' + 'final'))
    video_comp_ = (video_comp * 255).astype(np.uint8).transpose(
        3, 0, 1, 2)[:, :, :, ::-1]
    for i in range(nFrame):
        img = video_comp[:, :, :, i] * 255
        cv2.imwrite(
            os.path.join(args.outroot, 'frame_comp_' + 'final',
                         '%05d.png' % i), img)
        imageio.mimwrite(os.path.join(args.outroot, 'frame_comp_' + 'final',
                                      'final.mp4'),
                         video_comp_,
                         fps=12,
                         quality=8,
                         macro_block_size=1)
def video_completion_seamless(args):
    os.environ["CUDA_VISIBLE_DEVICES"] = '0,1,2,3'

    # Flow model.
    RAFT_model = initialize_RAFT(args)

    # Loads frames.
    filename_list = glob.glob(os.path.join(args.path, '*.png')) + \
                    glob.glob(os.path.join(args.path, '*.jpg'))

    # Obtains imgH, imgW and nFrame.
    imgH, imgW = np.array(Image.open(filename_list[0])).shape[:2]
    nFrame = len(filename_list)

    # Loads video.
    video = []
    for filename in sorted(filename_list):
        video.append(
            torch.from_numpy(np.array(Image.open(filename)).astype(
                np.uint8)).permute(2, 0, 1).float())
    video = torch.stack(video, dim=0)
    video = video.to('cuda')

    # Loads masks.
    filename_list = glob.glob(os.path.join(args.path_mask, '*.png')) + \
                    glob.glob(os.path.join(args.path_mask, '*.jpg'))
    mask = []
    mask_dilated = []
    flow_mask = []
    for filename in sorted(filename_list):
        mask_img = np.array(Image.open(filename).convert('L'))
        flow_mask_img = scipy.ndimage.binary_dilation(mask_img, iterations=3)
        # Close the small holes inside the foreground objects
        flow_mask_img = cv2.morphologyEx(flow_mask_img.astype(np.uint8),
                                         cv2.MORPH_CLOSE,
                                         np.ones((11, 11),
                                                 np.uint8)).astype(np.bool)
        flow_mask_img = scipy.ndimage.binary_fill_holes(flow_mask_img).astype(
            np.bool)
        flow_mask.append(flow_mask_img)

        # Dilate a little bit
        mask_img = scipy.ndimage.binary_dilation(mask_img, iterations=3)
        mask_img = scipy.ndimage.binary_fill_holes(mask_img).astype(np.bool)
        mask.append(mask_img)
        mask_dilated.append(gradient_mask(mask_img))

    minbbox_tl, minbbox_br = find_minbbox(flow_mask)

    # Image inpainting model.
    deepfill = DeepFillv1(pretrained_model=args.deepfill_model,
                          image_shape=[imgH, imgW])

    # timer
    time_start = time.time()

    # Calcutes the corrupted flow.
    corrFlowF = calculate_flow(args, RAFT_model, video, 'forward')
    corrFlowB = calculate_flow(args, RAFT_model, video, 'backward')
    print('\nFinish flow prediction.')

    # Makes sure video is in BGR (opencv) format.
    video = video.permute(2, 3, 1, 0).cpu().numpy()[:, :, ::-1, :] / 255.

    # mask indicating the missing region in the video.
    mask = np.stack(mask, -1).astype(np.bool)
    mask_dilated = np.stack(mask_dilated, -1).astype(np.bool)
    flow_mask = np.stack(flow_mask, -1).astype(np.bool)

    if args.edge_guide:
        # Edge completion model.
        EdgeGenerator = EdgeGenerator_()
        EdgeComp_ckpt = torch.load(args.edge_completion_model)
        EdgeGenerator.load_state_dict(EdgeComp_ckpt['generator'])
        EdgeGenerator.to(torch.device('cuda:1'))
        EdgeGenerator.eval()

        # Edge completion.
        FlowF_edge = edge_completion(args, EdgeGenerator, corrFlowF, flow_mask,
                                     'forward')
        FlowB_edge = edge_completion(args, EdgeGenerator, corrFlowB, flow_mask,
                                     'backward')
        print('\nFinish edge completion.')
    else:
        FlowF_edge, FlowB_edge = None, None

    # Completes the flow.
    videoFlowF = complete_flow(args, corrFlowF, flow_mask, 'forward',
                               minbbox_tl, minbbox_br, FlowF_edge)
    videoFlowB = complete_flow(args, corrFlowB, flow_mask, 'backward',
                               minbbox_tl, minbbox_br, FlowB_edge)
    print('\nFinish flow completion.')

    # Prepare gradients
    gradient_x = np.empty(((imgH, imgW, 3, 0)), dtype=np.float32)
    gradient_y = np.empty(((imgH, imgW, 3, 0)), dtype=np.float32)

    for indFrame in range(nFrame):
        img = video[:, :, :, indFrame]
        img[mask[:, :, indFrame], :] = 0

        img = cv2.inpaint(
            (img * 255).astype(np.uint8), mask[:, :, indFrame].astype(
                np.uint8), 3, cv2.INPAINT_TELEA).astype(np.float32) / 255.

        gradient_x_ = np.concatenate(
            (np.diff(img, axis=1), np.zeros((imgH, 1, 3), dtype=np.float32)),
            axis=1)
        gradient_y_ = np.concatenate(
            (np.diff(img, axis=0), np.zeros((1, imgW, 3), dtype=np.float32)),
            axis=0)
        gradient_x = np.concatenate(
            (gradient_x, gradient_x_.reshape(imgH, imgW, 3, 1)), axis=-1)
        gradient_y = np.concatenate(
            (gradient_y, gradient_y_.reshape(imgH, imgW, 3, 1)), axis=-1)

        gradient_x[mask_dilated[:, :, indFrame], :, indFrame] = 0
        gradient_y[mask_dilated[:, :, indFrame], :, indFrame] = 0

    iter = 0
    mask_tofill = mask
    gradient_x_filled = gradient_x  # corrupted gradient_x, mask_gradient indicates the missing gradient region
    gradient_y_filled = gradient_y  # corrupted gradient_y, mask_gradient indicates the missing gradient region
    mask_gradient = mask_dilated
    video_comp = video

    # We iteratively complete the video.
    while (np.sum(mask) > 0):
        #   create_dir(os.path.join(args.outroot, 'frame_seamless_comp_' + str(iter)))

        # Gradient propagation.
        gradient_x_filled, gradient_y_filled, mask_gradient = \
            get_flowNN_gradient(args,
                                gradient_x_filled,
                                gradient_y_filled,
                                mask,
                                mask_gradient,
                                videoFlowF,
                                videoFlowB,
                                None,
                                None)

        # if there exist holes in mask, Poisson blending will fail. So I did this trick. I sacrifice some value. Another solution is to modify Poisson blending.
        for indFrame in range(nFrame):
            mask_gradient[:, :, indFrame] = scipy.ndimage.binary_fill_holes(
                mask_gradient[:, :, indFrame]).astype(np.bool)

        # After one gradient propagation iteration
        # gradient --> RGB
        for indFrame in range(nFrame):
            print("Poisson blending frame {0:3d}".format(indFrame))

            if mask[:, :, indFrame].sum() > 0:
                try:
                    video_comp_crop = video_comp[
                        minbbox_tl[indFrame][1]:minbbox_br[indFrame][1],
                        minbbox_tl[indFrame][0]:minbbox_br[indFrame][0], :,
                        indFrame]
                    gradient_x_filled_crop = gradient_x_filled[
                        minbbox_tl[indFrame][1]:minbbox_br[indFrame][1],
                        minbbox_tl[indFrame][0]:minbbox_br[indFrame][0] - 1, :,
                        indFrame]
                    gradient_y_filled_crop = gradient_y_filled[
                        minbbox_tl[indFrame][1]:minbbox_br[indFrame][1] - 1,
                        minbbox_tl[indFrame][0]:minbbox_br[indFrame][0], :,
                        indFrame]
                    mask_crop = mask[
                        minbbox_tl[indFrame][1]:minbbox_br[indFrame][1],
                        minbbox_tl[indFrame][0]:minbbox_br[indFrame][0],
                        indFrame]
                    mask_gradient_crop = mask_gradient[
                        minbbox_tl[indFrame][1]:minbbox_br[indFrame][1],
                        minbbox_tl[indFrame][0]:minbbox_br[indFrame][0],
                        indFrame]
                    frameBlend_crop, UnfilledMask_crop = Poisson_blend_img(
                        video_comp_crop, gradient_x_filled_crop,
                        gradient_y_filled_crop, mask_crop, mask_gradient_crop)

                    frameBlend, UnfilledMask = video_comp[:, :, :,
                                                          indFrame], mask[:, :,
                                                                          indFrame]
                    frameBlend[minbbox_tl[indFrame][1]:minbbox_br[indFrame][1],
                               minbbox_tl[indFrame][0]:minbbox_br[indFrame]
                               [0], :] = frameBlend_crop
                    UnfilledMask[
                        minbbox_tl[indFrame][1]:minbbox_br[indFrame][1],
                        minbbox_tl[indFrame][0]:minbbox_br[indFrame]
                        [0]] = UnfilledMask_crop
                    # UnfilledMask = scipy.ndimage.binary_fill_holes(UnfilledMask).astype(np.bool)

                    # frameBlend, UnfilledMask = Poisson_blend_img(video_comp[:, :, :, indFrame], gradient_x_filled[:, 0 : imgW - 1, :, indFrame], gradient_y_filled[0 : imgH - 1, :, :, indFrame], mask[:, :, indFrame], mask_gradient[:, :, indFrame])
                #  UnfilledMask = scipy.ndimage.binary_fill_holes(UnfilledMask).astype(np.bool)
                except:
                    frameBlend, UnfilledMask = video_comp[:, :, :,
                                                          indFrame], mask[:, :,
                                                                          indFrame]

                frameBlend = np.clip(frameBlend, 0, 1.0)
                tmp = cv2.inpaint((frameBlend * 255).astype(np.uint8),
                                  UnfilledMask.astype(np.uint8), 3,
                                  cv2.INPAINT_TELEA).astype(np.float32) / 255.
                frameBlend[UnfilledMask, :] = tmp[UnfilledMask, :]

                video_comp[:, :, :, indFrame] = frameBlend
                mask[:, :, indFrame] = UnfilledMask

                frameBlend_ = copy.deepcopy(frameBlend)
                # Green indicates the regions that are not filled yet.
                frameBlend_[mask[:, :, indFrame], :] = [0, 1., 0]
            else:
                frameBlend_ = video_comp[:, :, :, indFrame]

        # cv2.imwrite(os.path.join(args.outroot, 'frame_seamless_comp_' + str(iter), '%05d.png'%indFrame), frameBlend_ * 255.)

        # video_comp_ = (video_comp * 255).astype(np.uint8).transpose(3, 0, 1, 2)[:, :, :, ::-1]
        # imageio.mimwrite(os.path.join(args.outroot, 'frame_seamless_comp_' + str(iter), 'intermediate_{0}.mp4'.format(str(iter))), video_comp_, fps=12, quality=8, macro_block_size=1)
        # imageio.mimsave(os.path.join(args.outroot, 'frame_seamless_comp_' + str(iter), 'intermediate_{0}.gif'.format(str(iter))), video_comp_, format='gif', fps=12)

        mask, video_comp = spatial_inpaint(deepfill, mask, video_comp)
        iter += 1

        # Re-calculate gradient_x/y_filled and mask_gradient
        for indFrame in range(nFrame):
            mask_gradient[:, :, indFrame] = gradient_mask(mask[:, :, indFrame])

            gradient_x_filled[:, :, :, indFrame] = np.concatenate(
                (np.diff(video_comp[:, :, :, indFrame],
                         axis=1), np.zeros((imgH, 1, 3), dtype=np.float32)),
                axis=1)
            gradient_y_filled[:, :, :, indFrame] = np.concatenate(
                (np.diff(video_comp[:, :, :, indFrame],
                         axis=0), np.zeros((1, imgW, 3), dtype=np.float32)),
                axis=0)

            gradient_x_filled[mask_gradient[:, :, indFrame], :, indFrame] = 0
            gradient_y_filled[mask_gradient[:, :, indFrame], :, indFrame] = 0

    video_comp_ = (video_comp * 255).astype(np.uint8).transpose(
        3, 0, 1, 2)[:, :, :, ::-1]

    time_end = time.time()
    print('time cost', time_end - time_start, 's')

    # write out
    create_dir(os.path.join(args.outroot, 'frame_seamless_comp_' + 'final'))
    for i in range(nFrame):
        img = video_comp[:, :, :, i] * 255
        cv2.imwrite(
            os.path.join(args.outroot, 'frame_seamless_comp_' + 'final',
                         '%06d.png' % i), img)
Esempio n. 5
0
def video_completion_seamless(args):

    if args.gpu_profile == 'high':
        num_gpus = 0.25
    elif args.gpu_profile == 'medium':
        num_gpus = 0.5
    else:
        num_gpus = 1

    create_dirs(args)
    zdata = zarr.open_group(os.path.join(args.outroot, 'datasets.zarr'),
                            mode='a')

    rargs = ray.put(args)
    # Flow model.
    RAFT_model = initialize_RAFT(args)
    rRAFT_model = ray.put(RAFT_model)

    # Loads frames.
    filename_list = glob.glob(os.path.join(args.path, '*.png')) + \
                    glob.glob(os.path.join(args.path, '*.jpg'))
    filename_list = sorted(filename_list)

    # Obtains imgH, imgW and nFrame.
    imgH, imgW = cv2.imread(filename_list[0]).shape[:2]
    nFrame = len(filename_list)

    if args.mode == 'object_removal' and not divisible_by((
            imgH,
            imgW,
    ), 8):
        raise Exception('Height and width must be divisible by 8')

    if args.mode == 'video_extrapolation':
        # Defines new FOV.
        imgH_orig, imgW_orig = imgH, imgW
        imgH = int(8 * round((args.H_scale * imgH) / 8))
        imgW = int(8 * round((args.W_scale * imgW) / 8))
        H_start = int((imgH - imgH_orig) / 2)
        W_start = int((imgW - imgW_orig) / 2)

        shape = (
            slice(H_start, H_start + imgH_orig),
            slice(W_start, W_start + imgW_orig),
        )
    else:
        shape = (
            slice(None, None),
            slice(None, None),
        )

    #Create datasets
    zchecksum = zdata.require_dataset('checksum',
                                      shape=(10, nFrame),
                                      chunks=(10, 1),
                                      fill_value=0,
                                      dtype=np.int)
    zvideo = zdata.require_dataset('video',
                                   shape=(imgH, imgW, 3, nFrame),
                                   chunks=(imgH, imgW, 3, 1),
                                   fill_value=0,
                                   dtype=np.uint8)  #0
    zflow = zdata.require_dataset('flow',
                                  shape=(imgH, imgW, 2, 2, nFrame - 1),
                                  chunks=(imgH, imgW, 2, 2, 1),
                                  fill_value=0,
                                  dtype=np.float32)  #1
    zmasks = zdata.require_dataset('masks',
                                   shape=(imgH, imgW, nFrame),
                                   chunks=(imgH, imgW, 1),
                                   fill_value=0,
                                   dtype=np.bool)  #3
    zflow_masks = zdata.require_dataset('flow_masks',
                                        shape=(imgH, imgW, nFrame),
                                        chunks=(imgH, imgW, 1),
                                        fill_value=0,
                                        dtype=np.bool)  #4
    zmasks_dilated = zdata.require_dataset('masks_dilated',
                                           shape=(imgH, imgW, nFrame),
                                           chunks=(imgH, imgW, 1),
                                           fill_value=0,
                                           dtype=np.bool)  #5
    zflow_comp = zdata.require_dataset('flow_comp',
                                       shape=(imgH, imgW, 2, 2, nFrame - 1),
                                       chunks=(imgH, imgW, 2, 2, 1),
                                       fill_value=0,
                                       dtype=np.float32)  #2
    zgradient_x = zdata.require_dataset('gradient_x',
                                        shape=(imgH, imgW, 3, nFrame),
                                        chunks=(imgH, imgW, 3, 1),
                                        fill_value=0,
                                        dtype=np.float32)  #6
    zgradient_y = zdata.require_dataset('gradient_y',
                                        shape=(imgH, imgW, 3, nFrame),
                                        chunks=(imgH, imgW, 3, 1),
                                        fill_value=0,
                                        dtype=np.float32)  #7
    zedges = zdata.require_dataset(
        'edges',
        shape=(imgH, imgW, 2, nFrame - 1),
        chunks=(imgH, imgW, 2, 1),
        fill_value=0,
        dtype=np.float32) if args.edge_guide else None  #8

    if args.force:
        zchecksum[:] = 0

    rzdataset = ray.put(zdata)
    # Import frames.
    for frame in trange(nFrame, desc="Importing frames"):
        if not valid_checksum(zdata, zvideo[..., frame], 0, frame):
            zvideo[shape[0], shape[1], :,
                   frame] = cv2.imread(filename_list[frame])
            save_checksum(zdata, zvideo[..., frame], 0, frame)

    rayProgressBar([
        calculate_flow.options(num_gpus=num_gpus,
                               name='calculate_flow({})'.format(frame)).remote(
                                   rargs, rRAFT_model, rzdataset, shape, frame)
        for frame in range(nFrame - 1)
    ], 'Calculating flows')

    if args.mode == 'video_extrapolation':
        # Creates video and flow where the extrapolated region are missing.
        rayProgressBar([
            extrapolation.options(
                name='prepare_masks({})'.format(frame)).remote(
                    rargs, rzdataset, shape, frame) for frame in range(nFrame)
        ], 'Processing masks')
    else:
        rayProgressBar([
            prepare_masks.options(
                name='prepare_masks({})'.format(frame)).remote(
                    rargs, rzdataset, frame) for frame in range(nFrame)
        ], 'Processing masks')

    if args.edge_guide:
        # Edge completion model.
        EdgeGenerator = EdgeGenerator_()
        EdgeComp_ckpt = torch.load(args.edge_completion_model)
        EdgeGenerator.load_state_dict(EdgeComp_ckpt['generator'])
        EdgeGenerator.to(torch.device('cuda:0'))
        EdgeGenerator.eval()
        rEdgeGenerator = ray.put(EdgeGenerator)
        #zedges = zarr.open(os.path.join(args.outroot, 'edges_comp.zarr'), mode='w', shape=(imgH, imgW, 2, nFrame),
        #chunks=(imgH, imgW, 2, 1), dtype=np.float32)

        # Edge completion.
        rayProgressBar([
            edge_completion.options(
                num_gpus=num_gpus,
                name='edge_completion({})'.format(frame)).remote(
                    rEdgeGenerator, rzdataset, frame)
            for frame in range(nFrame - 1)
        ], 'Completing edges')

    rayProgressBar([
        complete_flow.options(name='complete_flow({})'.format(frame)).remote(
            rargs, rzdataset, frame) for frame in range(nFrame - 1)
    ], 'Completing flows')

    rayProgressBar([
        get_gradients.options(name='get_gradients({})'.format(frame)).remote(
            rzdataset, frame) for frame in range(nFrame)
    ], 'Calculating gradients')

    print(
        '\nFlow completion finished.\nYou may run python 2-video-completion.py --outroot {}'
        .format(args.outroot))