Ask Your Question
1

How to use cv2.xphoto.inpaint in Python3

asked 2019-04-16 09:49:57 -0600

DaveK gravatar image

updated 2019-04-17 04:26:45 -0600

I'm trying to inpaint an image using cv2.xphoto.inpaint in Python 3, however it just produces a zero image. I installed opencv=3.4.2 via conda. The docs say the images need to be in Lab colorspace, however I get the same result with RGB.

My code:

import cv2
import numpy as np
from scipy.misc import imread
import matplotlib.pyplot as plt

cow = imread('C:/cow.png')
mask = imread('C:/mask.png')

img_lab = cv2.cvtColor(src=cow, code=cv2.COLOR_RGB2Lab)
inverse_mask = np.uint8(np.max(mask == 255, axis=-1))

dst = np.zeros_like(cow)
cv2.xphoto.inpaint(src=img_lab, mask=inverse_mask, dst=dst, algorithmType=cv2.xphoto.INPAINT_SHIFTMAP)
dst = cv2.cvtColor(src=dst, code=cv2.COLOR_Lab2RGB)

plt.imshow(dst)
plt.show()

Used images:

image description image description

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
0

answered 2020-01-06 08:40:48 -0600

zeit gravatar image

updated 2020-01-09 21:03:05 -0600

I modified your codes and it worked!

Hope my codes will help you.

import cv2
import numpy as np

if __name__ == "__main__":
    s_img_src = 'source.jpg'
    s_img_mask = 'mask.png'

    img_src = cv2.imread(s_img_src)
    img_src_lab = cv2.cvtColor(img_src, cv2.COLOR_BGR2Lab)

    img_mask = cv2.imread(s_img_mask, cv2.IMREAD_GRAYSCALE)
    img_mask_inv = cv2.bitwise_not(img_mask)

    img_dst = np.zeros_like(img_src)
    cv2.xphoto.inpaint(img_src_lab, img_mask_inv, img_dst,
                       cv2.xphoto.INPAINT_SHIFTMAP)
    img_dst = cv2.cvtColor(img_dst, cv2.COLOR_Lab2BGR)

    cv2.imshow('temp', img_dst)
    cv2.waitKey(0)

source mask

result

edit flag offensive delete link more
0

answered 2019-04-16 10:26:09 -0600

LBerger gravatar image

updated 2019-04-17 05:21:43 -0600

there is sample here White = good pixels and Black unknow pixel : inpaintMask Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that needs to be inpainted.

Now in xphoto : in c++

    Mat img = imread("g:/lib/opencv/samples/data/lena.jpg");
    Mat mask(img.size(),CV_8UC1,Scalar(255));
    circle(mask, Point(256, 256), 50, Scalar(0), -1);
    Mat res;
    cv::xphoto::inpaint(img, mask, res, cv::xphoto::INPAINT_SHIFTMAP);
    imshow("shiftmap", res);
    waitKey();

results is

image description

Same program in python

import numpy as np
import cv2 as cv
img = cv.imread('g:/lib/opencv/samples/data/lena.jpg')
mask = 255 * np.ones((img.shape[0],img.shape[1]),np.uint8)
mask = cv.circle(mask,(256,256),0,-1)
res = np.zeros(img.shape,np.uint8)
cv.xphoto.inpaint(img,mask,res,cv.xphoto.INPAINT_SHIFTMAP)
cv.imshow('e',res)
cv.waitKey()
cv.destroyAllWindows()

result is an empty image

image description

You should post an issue python binding is wrong and mask must be modify to use same definition

edit flag offensive delete link more

Comments

Are you also using opencv=3.4.2 in c++?

DaveK gravatar imageDaveK ( 2019-04-17 02:05:04 -0600 )edit

No opencv 4.1-dev

LBerger gravatar imageLBerger ( 2019-04-17 04:35:19 -0600 )edit

Ok, I also tried it with pip opencv-contrib-python-4.1.0.25 with the same result. Thanks for your efforts.

DaveK gravatar imageDaveK ( 2019-04-17 04:36:39 -0600 )edit

There is a bug in python binding. If you can compile opencv and opencv_contrib and python binding then it can be solved

LBerger gravatar imageLBerger ( 2019-04-17 04:51:31 -0600 )edit
1

I just noticed some problems in your python code. It seems you forgot to specify a radius for the circle?

mask = cv.circle(mask, (256, 256), 50, 0, -1)

Also the line

res = np.array(img.shape,np.uint8)

creates an array of the shape tuple itself. Not a new array of this shape. You have to use np.zeros instead.

And while I checked your code, I randomly tried to use a 255, 0 mask instead of a 1, 0 mask which fixed the issue.

The following works for me now:

img = imread('C:/ma/lenna.png')
mask = 255 * np.ones((img.shape[0], img.shape[1]), np.uint8)
mask = cv.circle(mask, (256, 256), 50, 0, -1)
res = np.zeros(img.shape, np.uint8)
cv.xphoto.inpaint(img, mask, res, cv.xphoto.INPAINT_SHIFTMAP)

plt.imshow(res)
plt.show()
DaveK gravatar imageDaveK ( 2019-04-17 04:52:30 -0600 )edit

The doc states the following:

mask: (CV_8UC1), where non-zero pixels indicate valid image area, while zero pixels indicate area to be inpainted

which seems to be wrong. I'll open an issue for that.

DaveK gravatar imageDaveK ( 2019-04-17 04:54:40 -0600 )edit

Too much copy and paste gives error

LBerger gravatar imageLBerger ( 2019-04-17 05:00:02 -0600 )edit
1

Question Tools

1 follower

Stats

Asked: 2019-04-16 09:49:57 -0600

Seen: 3,891 times

Last updated: Jan 09 '20