0

Original Image

I edited it to view the foreground image on a white background but now, none of the images are visible.

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('91_photo.jpg')
mask = np.zeros(img.shape[:2],np.uint8)

bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)

rect = (10,10,360,480)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)

mask2 = np.where((mask==2)|(mask==0),0,255).astype('uint8')
img = img*mask2[:,:,np.newaxis]


plt.imshow(img),plt.colorbar(),plt.show()

Expecting the result to be a visible image on a white background

This is what i'm getting

enter image description here

Dima Chubarov
  • 16,199
  • 6
  • 40
  • 76
Moses
  • 13
  • 3
  • Can we chat privately? – Moses Dec 08 '17 at 13:46
  • How can i solve it then? From what I see the code should be able to run smoothly – Moses Dec 08 '17 at 13:52
  • Please upload the original image. And, well, you probably have seen the [grabcut tutorial](https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.html), did you? They get black background because they set background pixels to 0, so do you. Why do you expect them to be white? – Dima Chubarov Dec 08 '17 at 14:07
  • 1
    Check [OpenCV giving wrong color to colored images on loading](https://stackoverflow.com/questions/39316447/opencv-giving-wrong-color-to-colored-images-on-loading) too. – alkasm Dec 08 '17 at 14:13
  • I have seen the tutorials, that's why I added 255. here is the image; – Moses Dec 08 '17 at 14:13
  • 1
    You didn't add 255 to the image. `img*mask2[:,:,np.newaxis]` is multiplying with the 0 and 255 values of the mask. Keep the mask boolean and do `img[~mask] = 255` to set the values which are `False` in the mask to 255 in the image. – alkasm Dec 08 '17 at 14:16
  • So where does the 255 come in? cos 255 should be white – Moses Dec 08 '17 at 14:17
  • Check the [docs for `np.where()`](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.where.html) to see what that line is doing. You're setting the mask to 0 or 255, not the image. Change the masking lines to `mask2 = (mask==2) | (mask==0)` and `img[mask2] = 255`. – alkasm Dec 08 '17 at 14:18

1 Answers1

2

There are a number of small issues with your code that are adding up to that weird result.

OpenCV uses BGR ordering of the channels of an image, where matplotlib uses RGB. That means if you read an image with OpenCV but want to display with matplotlib, you need to convert the image from BGR to RGB before displaying (that's the reason the colors are weird). Also, not that important, but color images are not displayed with a colormap, so showing the colormap does not do anything for you.

In numpy, it's best to keep masks boolean whenever you can, because you can use them to index your arrays. Your current code converts a boolean mask to a uint8 image with 0 and 255 values and then you multiply that with your image. That means your image will be set to zero wherever the mask is zero---and your image values will explode (or do weird stuff with overflow). Instead, keep the mask boolean and use it to index your array. That way anywhere the mask is True you can just set the value in your image to something specific (like 255 for white).

This should fix you up:

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('91_photo.jpg')
mask = np.zeros(img.shape[:2], np.uint8)

bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)

rect = (10, 10, 360, 480)
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)

mask2 = (mask==2) | (mask==0)
img[mask2] = 255

img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()

Masked image

alkasm
  • 22,094
  • 5
  • 78
  • 94
  • Wow! Thank you so much. Seems i still have a lot of research to do on Python image processing. Can we chat privately? i still have a few questions – Moses Dec 08 '17 at 14:39
  • Wow! Thank you so much. Seems i still have a lot of research to do on Python image processing. Can we chat privately? i still have a few questions – Moses Dec 08 '17 at 14:39
  • Yeah the dimensions, The shoulder is cut off on one end and the grey patches are still visible. It would be great if there are no grey patches. – Moses Dec 08 '17 at 15:23
  • Well `grabCut()` isn't a perfect segmenting tool, and you could define better foregrounds and backgrounds to help. You could try `floodFill()` with different thresholds (works like paint bucket). – alkasm Dec 08 '17 at 15:29
  • Ok, thank you! although there should be a way out with grabCut(). I would also love if the output didn't have those metering dimensions by the sides. – Moses Dec 08 '17 at 15:40
  • Then don't use matplotlib and just save the image directly with OpenCV using `cv2.imwrite('filename.ext', image_to_save)`. Note that in this case you'll want to remove the color conversion. If you want to preview with OpenCV you can do so using `cv2.imshow('window_name', image_to_show)` and then draw the window with `cv2.waitKey()`. Check out the introductory articles on OpenCV's Python tutorials: https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_tutorials.html – alkasm Dec 08 '17 at 15:43