Page 1 of 1

the how-do-I-remove-the-background problem

Posted: 2011-03-03T12:26:43-07:00
by h.nietnagel
Hello,

I am trying to remove the background of plenty pictures. Unfortunately, the background of these pictures are neither solid nor always the same. Since I have to do the removal for more than 100 pictures, I would like to do that using a shell script.

First, some example pictures that resemble mine quite good:
http://www.bottleopener.com/images/P/op ... rew-01.jpg
http://3.bp.blogspot.com/_mByq_7EPwjg/S ... conome.jpg
http://upload.wikimedia.org/wikipedia/c ... stange.jpg

And here what I managed so far (sorry, I am a programmers beginner)

Code: Select all

#!/bin/bash

for k in *.jpg; do
convert $k $k.png
convert $k.png \( +clone -fx 'p{0,0}' \) -compose Difference -composite -modulate 100,0  +matte  ${k}_diff.png
convert ${k}_diff.png -fill black -fuzz 03% -bordercolor black -border 1x1 -floodfill +0+0 black -shave 1x1 ${k}_diff03.png
convert ${k}_diff03.png $k.png -compose Difference -composite  ${k}_diff03bg_removed.png
done
The percentage for the fuzz option I got by trial and error. Obviously, it is not the most suitable idea.
I did so far not really understand how that masking works. As far as I understand what I wrote in the code, I kind of subtract them from another. But this is not sufficient as it is now.

Does anyone have an advice?

Thank you very much in advance!!!

Hannes

Re: the how-do-I-remove-the-background problem

Posted: 2011-03-03T17:37:54-07:00
by anthony
You seem to be following the one good suggestion I have.

All methods generally involve generating one or more masks that differentiates between background and foreground (and possibly shadow). Work only on the mask, and don't try to map directly to transparency, when you have the mask right then you can apply it to the original image to extract the colors wanted.

See Removing Background
http://www.imagemagick.org/Usage/channe ... k_creation

Essentially if you can get a copy of the background without the foreground image, you can create a difference (mask) image that will let you remove the background. That is about the best method there is.

Your example images is however made much more difficult be using a plan background that is simlar to the foreground image. That is everything is grey scale. that makes generating your mask much more difficult.

Fuzz factor may be easiest for the first two images. for mask creation.

Your 'candycane' may be able to be masked using a 'chroma key' as yoru foreground does not appear to have any light blue in it. See Photo Handling, Chroma Key
http://www.imagemagick.org/Usage/photos/#chroma_key

One aspect you may also like to consider is 'anti-alising' of the edges. Masks tend to be purely on/off, and sometimes it is better to generate some semi-transparency edge pixels to the result, to give it a smooth outline. Resizing the resulting image is one way to do this. Another is to take the masked image, blur it by say 0x0.7 and overlay the original on the blur, so you only get some extra semi-transparent edges.

One method that I explored is double-masking. generate two masks, one of the area that is definatally internal, and another of the parts that are definitely external, generating a 'zone of semi-transparency' between the two masks, where you can generate anti-aliasing and shadow effects.
http://www.imagemagick.org/Usage/channe ... antialised
This has been scripted into the shell script...
http://www.imagemagick.org/Usage/scripts/bg_removal

Now one MAJOR point. do not be afraid of doing some extra work on difficult masks. Either using a image editor like GIMP, or Photoshop, Or making use of "Morphology" to expand/reduce or just to smooth masks by a few pixels. That is what they are for, and I use them all the time for mask modifications.
http://www.imagemagick.org/Usage/morphology/#basic
http://www.imagemagick.org/Usage/morphology/#kernel

Also don't be afraid of using blur, just make sure you only blur edges and not your 'definite internal' pixels, such as I described above.


The real problem is there is no one size fits all solution. Each image has its own problems and difficulty in generating the background removal mask.

Re: the how-do-I-remove-the-background problem

Posted: 2011-03-04T08:24:08-07:00
by h.nietnagel
Hi Anthony,

thanks for your detailed comments!
So, in the end I will have to edit each picture individually... :(
I hoped that there might be one general and flexible solution that can be applied to all pictures.
I guess I will come again with more specific question for single pictures :)

Thanks a lot!

Hannes

Re: the how-do-I-remove-the-background problem

Posted: 2011-03-05T19:49:06-07:00
by anthony
Generally you create create a mask in a fairly automated way. Though how automated this is depends on the images. Your image examples are highly varied and difficult. Other than that tweeking the mask is recommended, especially when you have little original background control.

Basically anything you use will need some method of determining what is background and what is not. Automatic mask generation relies on some knowledge of how it can determine this.

Re: the how-do-I-remove-the-background problem

Posted: 2011-03-05T20:18:34-07:00
by fmw42
Sometimes choosing the right channel in the right colorspace can help with mask generation.

Re: the how-do-I-remove-the-background problem

Posted: 2011-03-07T05:16:39-07:00
by phuoq
Thanks for the script. I tried this and hit the following problem:-

Code: Select all

./bg_removal.sh triangle.png 5 5 trianglenobg.png
convert: no decode delegate for this image format `triangle.png' @ error/constitute.c/ReadImage/532.
convert: image sequence is required `-clone' @ error/convert.c/ConvertImageCommand/918.
It's a recent upgrade (to support -sparse-color) so I checked the conversions

Code: Select all

convert logo: logo.jpg
convert logo: logo.png
Both of which were fine.

I tried some debugging but saw nothing obvious

Code: Select all

sh -x ./bg_removal.sh triangle.png 5 5 trianglenobg.png
++ type ./bg_removal.sh
++ awk '{print $3}'
+ PROGNAME=./bg_removal.sh
++ dirname ./bg_removal.sh
+ PROGDIR=.
++ basename ./bg_removal.sh
+ PROGNAME=bg_removal.sh
+ background=black
+ '[' 4 -gt 0 ']'
+ case "$1" in
+ break
+ case $# in
+ image=triangle.png
+ shift
+ '[' 3 -eq 4 ']'
+ bgnd='( +clone -sparse-color voronoi 0,0,%[fx:p{0,0}] )'
+ fzout=5
+ shift
+ fzin=5
+ shift
+ image_out=trianglenobg.png
+ shift
+ '[' '' ']'
+ fill='-bordercolor black -border 1x1 -floodfill +0+0 black -shave 1x1'
+ '[' '' ']'
+ '[' '' ']'
+ grayscale='-colorspace gray'
+ '[' '' ']'
+ convert triangle.png '(' -clone 0 '(' +clone -sparse-color voronoi '0,0,%[fx:p{0,0}]' ')' -compose Difference -composite -colorspace gray -channel B -evaluate set 0 +channel ')' '(' -clone 1 -fill blue -fuzz 5% -bordercolor black -border 1x1 -floodfill +0+0 black -shave 1x1 -channel B -separate +channel ')' '(' -clone 1 -fill blue -fuzz 5% -bordercolor black -border 1x1 -floodfill +0+0 black -shave 1x1 -channel B -separate +channel -negate ')' '(' -clone 2,3 -negate -compose multiply -composite ')' '(' -clone 0,3 +matte -compose CopyOpacity -composite ')' '(' -clone 1 -channel R -separate +channel -clone 4 +matte -compose CopyOpacity -composite '(' +clone -blur 0x30 +matte ')' +swap -compose Over -composite +matte -normalize -clone 4 -compose multiply -composite -background black -alpha shape -clone 5 -compose over -composite ')' -delete 0--2 trianglenobg.png
convert: no decode delegate for this image format `triangle.png' @ error/constitute.c/ReadImage/532.
convert: image sequence is required `-clone' @ error/convert.c/ConvertImageCommand/918.
+ exit 0

Code: Select all

convert --version
Version: ImageMagick 6.3.7 11/16/10 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2008 ImageMagick Studio LLC
Any ideas,

Thanks,

Paul.

Re: the how-do-I-remove-the-background problem

Posted: 2011-03-07T20:12:26-07:00
by anthony
Pointer to the triangle.png image?

PS: using the same fuzz values is not the normal usage of this script which is designed to generate a linear transparency gradient (black by default) between the two fuzz values.

I do hope to expand the script to include an option to use 'edge pixel colors' from the central 'full-opaque' fuzz mask, at some point.