2

I'm using opencv to process some images. I have a lot of images like below. They have some very light, shadow-like color.

What is the dimension that determine the color of the pixel is very light? What color space should I use to identify those light color pixels?

enter image description here

Aaron Shen
  • 8,124
  • 10
  • 44
  • 86
  • http://www.di.ubi.pt/~hugomcp/visaoComp/docs/Shadow_removal_5.pdf – GPPK May 11 '18 at 07:33
  • 1
    Have you tried looking at [HSV](https://en.wikipedia.org/wiki/HSL_and_HSV)? You can also try playing with the parameters of Lab/Luv color spaces. Additionally, if you have a lot of images with different colors, hence different shadows, you can train an SVN/neural network to bring all the shadows either to white (255, 255, 255) or the color next to it. – Rick M. May 11 '18 at 07:35
  • Those light areas are there for antialiasing. Why do you want to remove them ? –  May 11 '18 at 10:28

2 Answers2

2

Here's a fairly simple method:

img = cv2.imread('4.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

img[gray > 200] = 255

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
2

As mentioned by @RickM there are various color spaces available to analyze your image. Since you are focused on removing the shade/shadow you need to focus on channels that contain brightness information and keep the color channels aside.

In this case the LAB color space turned out to be helpful. The luminance channel expressed a lot of info on the amount of brightness in the image

img = cv2.imread('4.png')
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)

cv2.imshow('Luminance', l)

enter image description here

Then I obtained a threshold and masked the result with the original image to get mask1:

ret2, th = cv2.threshold(l, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
mask1 = cv2.bitwise_and(img, img, mask = th)
cv2.imshow('mask1', mask1)

enter image description here

But now the background is not what you intended it to be. I created an image with white pixels of the same image dimension (white) and masked the inverted threshold image with it to get mask2:

white = np.zeros_like(img)
white = cv2.bitwise_not(white)

mask2 = cv2.bitwise_and(white, white, mask = cv2.bitwise_not(th))
cv2.imshow('mask2', mask2)

enter image description here

Upon adding both these images you get he intended image:

cv2.imshow('fin_img', mask2 + mask1)

enter image description here

Keep in mind that this would work only for similar images provided in the question.

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
  • As you mentioned, this would work only for the images (or similar) provided in the question. If the dataset has a lot of variation, using ML would be the best bet. – Rick M. May 11 '18 at 09:57
  • @RickM. The OP has mentioned *'I have a lot of images like below'*, I agree if this method is used for images with a dark background it would fail. Using ML wouldn't you have to provide a mask? – Jeru Luke May 11 '18 at 10:07
  • 1
    Not necessarily, you could do a color collection by looking at the color around the shadow and bring it to the required value (white or what the OP wants) – Rick M. May 11 '18 at 10:11