2

I have some product images. The background of these images is white. Now, in my website I want to use the same image of different sizes in different places. The problem is that, since the color of the background of an image is white. But, the color of the background I need as a thumbnail is green. Similarly, as the main product image I want the background as light blue. Here is an image for example. link. You can see the background of this image is white. I want to use the same image as a thumbnail. I have written a code to generate thumbnails of images. But I want background as some other color. Can this be done with image processing preferably in python? Thank you.

Edit: I cannot comment on any answers do, cannot understand why. Please reply.

Rishi
  • 1,987
  • 6
  • 32
  • 49
  • Process them to 4 channel images with transparency – wim Feb 11 '13 at 06:49
  • 1
    This is tricky actually, you need to handle jpg artifacts in your linked image and also handle the background pixels which should be white but are not. After that you have to make a transformation such that it doesn't look completely horrible. I believe I've seen a very similar question in this site, maybe someone else knows what I'm referring to and will include a link to it. – mmgp Feb 11 '13 at 19:42
  • @mmgp were you thinking of this one? http://stackoverflow.com/questions/8041703/remove-white-background-from-an-image-and-make-it-transparent – Mark Ransom Feb 11 '13 at 21:35
  • @MarkRansom yes, thank you. I'm actually surprised that the accepted answer is doing almost the same approach as mine here, but it depends on an implementation of Chan & Vese methods, which I don't remember being available in OpenCV and other typical tools. The problem there is that it assumes the background color is not present in the image, the problem on my approach is that it assumes the object has no holes. – mmgp Feb 11 '13 at 21:43

1 Answers1

2

This is simple to do if you can tolerate some ugly effects in the resulting image. If this image with the different background color will be shown as a downscaled version of the original image, then these effects might not be noticeable and all is good.

So here is the simple approach:

  • Flood fill from the pixel at (0, 0) assuming it is a background pixel (white in your example) and accept minor differences when performing the flood fill. The background pixels are replaced by transparent points.
  • The step above gives a mask, which you can, for example, perform erosion and gaussian filtering.
  • Paste the "flood-filled" image with the mask created above.

Here is what you can expect from this approach. Input image and then two transformations to different background colors.

enter image description here enter image description here enter image description here

import sys
import cv2
import numpy
from PIL import Image

def floodfill(im, grayimg, seed, color, tolerance=15):
    width, height = grayimg.size
    grayim = grayimg.load()
    start_color = grayim[seed]

    mask_img = Image.new('L', grayimg.size, 255)
    mask = mask_img.load()
    count = 0
    work = [seed]
    while work:
        x, y = work.pop()
        im[x, y] = color
        for dx, dy in ((-1,0), (1,0), (0,-1), (0,1)):
            nx, ny = x + dx, y + dy
            if nx < 0 or ny < 0 or nx > width - 1 or ny > height - 1:
                continue
            if mask[nx, ny] and abs(grayim[nx, ny] - start_color) <= tolerance:
                mask[nx, ny] = 0
                work.append((nx, ny))
    return mask_img

img = Image.open(sys.argv[1]).convert('RGBA')
width, height = img.size
img_p = Image.new('RGBA', (width + 20, height + 20), img.getpixel((0, 0)))
img_p.paste(img, (3, 3))
img = img_p
img_g = img.convert('L')
width, height = img.size

im = img.load()
mask = floodfill(im, img_g, (0, 0), (0, 0, 0, 0), 20)

mask = numpy.array(mask)
se = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
mask = cv2.erode(mask, se)
mask = cv2.GaussianBlur(mask, (9, 9), 3)
mask = Image.fromarray(mask)

result_bgcolor = (0, 0, 0, 255) # Change to match the color you wish.
result = Image.new('RGBA', (width, height), result_bgcolor)
result.paste(img_p, (0, 0), mask)

result.save(sys.argv[2])
mmgp
  • 18,901
  • 3
  • 53
  • 80