Page 1 of 1
Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-07T10:38:10-07:00
by fieel
Hello,
for a project i have to take a physical deck of playing cards and turn it into a digital collection of pictures.
Basically, i have to scan a black (or any solid color) piece of cardboard with an entire deck of playing cards on it. Then, after scanning and once i have the high-quality file, i have to extract the single cards into single files. I have to automatize this process so i thought ImageMagick might be the perfect tool for the job.
I never used ImageMagick, i just want to find out if it's the right tool so i can start using and learning how to use it.
Initially, i tried using
shoebox which has a "sprite extract" feature which is perfect in this case, except for one thing: it works only from the GUI... the CLI commands are broken. Here are some screenshots of the resulting behavior that i want to re-create:
Transparent background image with collection of cards:
Result:
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-07T12:08:21-07:00
by fmw42
What platform are you on? Can you provide your input image without arrows and annotation?
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-07T12:36:27-07:00
by fieel
fmw42 wrote: ↑2018-02-07T12:08:21-07:00
What platform are you on? Can you provide your input image without arrows and annotation?
Sure thing! Here it is:
https://i.imgur.com/kh6MRaf.png
Keep in mind this is just a picture i'm using for testing, the end result will be a big high-quality picture.
I'm working on windows btw.
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-07T13:08:47-07:00
by Bonzo
And what IM version as that can have an effect?
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-07T13:17:05-07:00
by fmw42
I do not code for windows, but here is how I would do that for Unix.
Add 1 pixel transparent border and make sure all color under the transparency is white:
Code: Select all
convert cards.png -bordercolor none -border 1 -background white -alpha background -bordercolor white cards_border.png
Threshold to black and white:
Code: Select all
convert cards_border.png -alpha off -negate -threshold 0 -type bilevel cards_white_t0.png
Run connected components labeling to extract the bounds of the white thresholded cards and crop the white background image to extract the cards.
Code: Select all
OLD_IFS=$IFS
IFS=$'\n'
arr=(`convert cards_white_t0.png \
-define connected-components:verbose=true \
-define connected-components:area-threshold=10 \
-define connected-components:mean-color=true \
-connected-components 8 \
null: | tail -n +2 | sed 's/^[ ]*//'`)
IFS=$OLD_IFS
num=${#arr[*]}
for ((i=0; i<num; i++)); do
bbox=`echo "${arr[$i]}" | cut -d\ -f2`
color=`echo "${arr[$i]}" | cut -d\ -f5`
if [ "$color" = "gray(255)" ]; then
convert cards_border.png -crop $bbox +repage -background none -deskew 40% cards_$i.png
fi
done
Results in a zip archive:
http://www.fmwconcepts.com/misc_tests/cards/Archive.zip
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-07T13:25:51-07:00
by Bonzo
Could you also add a -deskew and -trim to help clean up the images in the process fmw42?
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-07T16:11:23-07:00
by fmw42
I have modified the code I posted earlier to keep the background transparent about the image and the output card images. I also added a deskew to try to straighten the resulting card images, but it does not always help much. Some results are corrected better than others.
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-08T12:33:07-07:00
by fieel
As far as i noticed it's working perfectly on Linux and it's what i was looking for: thank you!
I'll have a better look as soon as i have more time then i'll have to convert it into a Windows script and post back here.
Another question: what's the best way to automatically deal with a similar image without having already a transparent background? Fortunately, even if not perfect, the background will be some kind of solid color, like this:
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-08T14:13:29-07:00
by fmw42
The best way is to be sure that the background color is completely unique relative to any other color on the cards. Also not to have JPG for the input. JPG is lossy and any solid color will not be truly constant. That way you can use something like
Code: Select all
convert image.png -transparent your_background_color new_image.png
Otherwise, one can do the following, but one has to use an area-threshold that is larger than any black in the cards but smaller than the size of the cards.
Input:
Code: Select all
convert cards2.png -bordercolor black -border 1 cards2_border.png
Code: Select all
convert cards_border2.png -auto-level -fuzz 20% -fill black -opaque black -fill white +opaque -type bilevel black mask.png
Code: Select all
OLD_IFS=$IFS
IFS=$'\n'
arr=(`convert mask.png \
-define connected-components:verbose=true \
-define connected-components:area-threshold=9000 \
-define connected-components:mean-color=true \
-connected-components 8 \
new_mask.png | tail -n +2 | sed 's/^[ ]*//'`)
IFS=$OLD_IFS
num=${#arr[*]}
for ((i=0; i<num; i++)); do
bbox=`echo "${arr[$i]}" | cut -d\ -f2`
color=`echo "${arr[$i]}" | cut -d\ -f5`
if [ "$color" = "gray(255)" ]; then
convert \( cards2_border.png new_mask.png -alpha off -compose copy_opacity -composite \) \
-crop $bbox +repage -background none -deskew 40% cards_$i.png
fi
done
new_mask.png:
zip archive of individual cards:
http://www.fmwconcepts.com/misc_tests/c ... rchive.zip
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-22T06:53:55-07:00
by fieel
I'm trying to implement the script but i still have one problem.
Given that the initial image i'll be working on will be a scan done by a scanner or even a photograph, the background color won't be truly unique.
It will probably be some kind of shade of a solid color (which i still have to choose, not a color used by the cards themselves for sure though).
What's the best way to filter and delete the background so i can have a transparent background if i don't have a solid color?
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-22T07:32:23-07:00
by snibgo
Probably something like:
Code: Select all
convert in.png -fuzz 10% -transparent #abc out.png
... where abc is the average background colour and the fuzz percentage covers the range of background colours.
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-02-28T05:11:43-07:00
by fieel
Okay i took all the data from this topic, some info i found on the internet, some personal thoughts and tried to create a proper script. It's not that complicated as of now.
Kinda simplified but these are the steps:
1. Detect
any background and remove it, replacing it with transparency. This is accomplished by this awesome prebuilt script from hackerb9
https://github.com/hackerb9/mktrans
2.1 Add a 1 px white border around cards
2.2 Create a mask using the 1px border to understand where cards are
3. Use the mask to extract the single cards
Now i'd like to apply some minimal antialiasing
before extracting the single cards but only
after creating the mask, this is very important because i need a clear contrasting line between white and black when extracting the cards using the mask otherwise it won't work properly.
This is some relevant code from the script:
Code: Select all
#Variables declaration
FILENAME=$1
FILENAME_NO_EXTENSION=$(echo $FILENAME | cut -d '.' -f 1)
DECKNAME=$2
echo ''
echo '*******************************'
echo ' Input file: '$FILENAME
echo ' Deck name: '$DECKNAME
echo '*******************************'
echo ''
#Replace bg color with transparent alpha channel
echo '1. Removing background...'
bash ./mktrans -A $FILENAME
#Add 1 pixel transparent border and make sure all color under the transparency is white:
convert $FILENAME_NO_EXTENSION-transparent.png -bordercolor none -border 1 -background white -alpha background -bordercolor white tmp_border.png
#Threshold to black and white - creating a mask used to cut single cards in the next step
echo '2. Creating mask...'
convert tmp_border.png -alpha off -negate -threshold 0 -type bilevel tmp_mask.png
#Run connected components labeling to extract the bounds of the white thresholded cards using the mask
#and crop the white background image to extract the cards
echo '3. Extracting cards...'
OLD_IFS=$IFS
IFS=$'\n'
arr=(`convert tmp_mask.png \
-define connected-components:verbose=true \
-define connected-components:area-threshold=10 \
-define connected-components:mean-color=true \
-connected-components 8 \
null: | tail -n +2 | sed 's/^[ ]*//'`)
IFS=$OLD_IFS
num=${#arr[*]}
for ((i=0; i<num; i++))
do
bbox=`echo "${arr[$i]}" | cut -d\ -f2`
color=`echo "${arr[$i]}" | cut -d\ -f5`
if [ "$color" = "gray(255)" ]; then
convert tmp_border.png -crop $bbox +repage -background none -deskew 40% ${DECKNAME}${i}.png
echo -n '.'
fi
done
Re: Extract sprites/images from a bigger image with transparent background
Posted: 2018-03-06T09:26:42-07:00
by fieel
Any help? I'm having an hard time finding the correct and best way to approach this problem.
I think the only solution is applying some antialiasing to every single generated card as output, but i'm sure there must be another (and less CPU intensive) way.
If i soften edges before extracting the single cards the extraction won't work properly due to the absence of clear and linear boundaries between white and black in the mask, this is the biggest problem here.