Categorising Images By Background

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Categorising Images By Background

Post by FUrn »

I am looking to make a number of batch modifications to a set of product images, with the end purpose of getting them all to look somewhat aligned. The following portion of code trims each image and then re-borders it so that each fills the same proportion of the canvas:

Code: Select all

magick $filename -fuzz 10% -trim +repage -bordercolor white -border 12%% "$filename"
The issue I am having is that this works well for images on a white background, but less well on images with any other non-solid background. So for example it works well on this first image but less so on the second:

Image Image

To complicate things, there are images that lie somewhere 'between' these...the first one has some shadows, whilst the second one uses a predominantly light grey, rather than white, background. If possible, I'd also like to apply the trim and re-border operation to images such as these:

Image Image

Given I have several thousand images to go through, I need some way to process images that will come out well and ignore those that can't be operated on in this way. I thought of doing this by detecting the proportion of white (or if need be the colours/shades close to white) in each image and setting a threshold, above which I will trim and re-border those images and below which I will have to leave untouched. To find the right threshold and avoid mistakenly edited images, I thought it would make sense to have ImageMagick first categorise the images into two different directories based on the percentage of white in each image - so those above x% would go into the 'whiteBackground' folder and those below x% go into the 'otherBackground' folder. Is this possible, or for that matter is there a more efficient way to achieve what I am trying to do?

I am using using ImageMagick 7.0.8-14 on a Windows PC, with BASH syntax.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Categorising Images By Background

Post by fmw42 »

I cannot help with images with real world background. I don't think that is possible. But for images with some gray-like color, you can use -filter point -distort SRT 0 with a virtual canvas to extend the background using -virtual-pixel edge or whatever method you want. That may or may not look good. Otherwise, a simpler method is to measure the background color from the average of each edge and then use -border or -extent to pad it out with that average color.

See
https://imagemagick.org/Usage/distorts/#srt
https://imagemagick.org/Usage/distorts/#distort_virtual
https://imagemagick.org/Usage/distorts/ ... t_viewport
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Categorising Images By Background

Post by snibgo »

FUrn wrote:... categorise the images into two different directories based on the percentage of white in each image - so those above x% would go into the 'whiteBackground' folder and those below x% go into the 'otherBackground' folder.
Finding the proportion of pixels that are white is easy. Turn the other pixels black ("-fill Black +opaque White"), and the mean ("-format %[fx:mean]") is the required proportion, on a scale of 0.0 to 1.0. If you want a percentage, multiply by 100 ("-format %[fx:mean*100]").
snibgo's IM pages: im.snibgo.com
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Categorising Images By Background

Post by FUrn »

Thanks Fred. I think a simpler method would be best for now, as I don’t want to risk distorting images wrongly and would therefore prefer a more cautious approach. The issue with taking the average colour of each edge is that this approach would work for images that need additional background, and not those for which I need to reduce the background (i.e. trim it to in essence make the image contents take up more of the canvas). Unless I’ve misunderstood your suggestion, would it not be more suitable to take the percentage of the image that is white vs non-white? Either way, I’d appreciate your guidance of how to actually code this in IM and how to use this to sort images into different folders depending on the percentage of white in the image. Thanks once again, Fred!
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Categorising Images By Background

Post by fmw42 »

How do decide visually which to pad and which to trim?
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Categorising Images By Background

Post by FUrn »

snibgo wrote: 2019-04-23T15:51:43-07:00 Finding the proportion of pixels that are white is easy. Turn the other pixels black ("-fill Black +opaque White"), and the mean ("-format %[fx:mean]") is the required proportion, on a scale of 0.0 to 1.0. If you want a percentage, multiply by 100 ("-format %[fx:mean*100]").
Thanks @snibgo! I’ll give this a try. Assuming I have no issues getting this to work on my end, how would I then use a percentage threshold (eg 70%) to categorise/move images into the ‘whiteBackground’ (for images with mean >70%) and ‘otherBackground’ (for images with mean <70%) folders?
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Categorising Images By Background

Post by FUrn »

fmw42 wrote: 2019-04-23T16:00:02-07:00 How do decide visually which to pad and which to trim?
If they have white background, there is no need to explicitly make this decision. Once each image is trimmed and then given a 12% border, the end outcome is that each chair (in these example images) takes up the Sam proportion of the canvas, regardless of the image resolution. Those that were originally quite ‘small’ chairs, in that there was a lot of white background, now appear the same size as those that originally filled the whole canvas. I hope that answers your question...
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Categorising Images By Background

Post by fmw42 »

Not really.
The issue with taking the average colour of each edge is that this approach would work for images that need additional background, and not those for which I need to reduce the background (i.e. trim it to in essence make the image contents take up more of the canvas
What exactly are you questioning here as the "issue"? How do you decide which need additional background and which need padding. Both could have a white background. So it might depend upon the size of the image. What do you do for near solid color backgrounds such as gray? How do you decide whether to trim or pad -- by size? Is not size the only issue? Some images that real-world background cannot be trimmed or padded meaningfully!
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Categorising Images By Background

Post by FUrn »

I’m worried I won’t use the correct technical terms, but if you look at the original images I posted the 3rd image (with two chairs) would need trimming as the chairs appear considerably smaller than the chairs in the other images. Conversely, if you imagine an image with the chair going all the way to the canvas edge, that would require padding. Given some images will require trimming and others padding, would finding the average edge colour still be of use? To be on the cautious side, I’m tempted to ignore images with non-white backgrounds and only amend those with white backgrounds. Obviously I’d prefer, in an ideal world, to modify grey background images too, however perhaps focussing on white background images alone would strike the right balance between simplicity vs correctness (i.e. being cautious and doing something that I, as somewhat of a beginner, can replicate).
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Categorising Images By Background

Post by snibgo »

FUrn wrote:...how would I then use a percentage threshold (eg 70%) to categorise/move images into the ‘whiteBackground’ (for images with mean >70%) and ‘otherBackground’ (for images with mean <70%) folders?
A Windows BAT script could be something like this (untested):

Code: Select all

for %%F in (*.jpg) do (
  for /F "usebackq" %%L in (`magick ^
    %%F ^
    -fill Black +opaque White ^
    -format "ISWHITE=%[fx:mean>0.7?1:0] ^
    info:`) do set %%L
  if %ISWHITE%==1 (
    copy %%F whiteBackground\%%F
  ) else (
    copy %%F otherBackground\%%F
  )
)
This loops through all the jpg files in the current directory. For each one, it sets ISWHITE to 1 if more than 70% of pixels are white, otherwise 0. It uses that value to copy to the appropriate directory.

You use bash, not BAT, so you will need to translate.
snibgo's IM pages: im.snibgo.com
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Categorising Images By Background

Post by FUrn »

snibgo wrote: 2019-04-23T16:57:04-07:00

Code: Select all

for %%F in (*.jpg) do (
  for /F "usebackq" %%L in (`magick ^
    %%F ^
    -fill Black +opaque White ^
    -format "ISWHITE=%[fx:mean>0.7?1:0] ^
    info:`) do set %%L
  if %ISWHITE%==1 (
    copy %%F whiteBackground\%%F
  ) else (
    copy %%F otherBackground\%%F
  )
)
Thanks for this, @snibgo. I'm not too familiar with translating from BAT to Bash, and so thought I'd execute this as a BAT file via the Git Bash command line. However I'm getting a variety of errors, however much I try adjusting things ever so slightly. Errors include:
  • else was unexpected at this time - at the ) else ( point in the code
  • ( was unexpected at this time - after the if ==1 (
  • the syntax of the command is incorrect - with reference to a (
Any help you can give to get me round this would be great!

I'm also trying to understand the code you've drafted, and have a couple of questions if I may:
  • Why have you added a ` after the info:
  • The part I'm having most difficulty understanding is the second for command. How exactly does the part reading 'for /F "usebackq" %%L in...do set %%L' work? What is the purpose of the "usebackq"? I get in general that this line applies the IM code to set whether or not the image in question has >70% white pixels, but don't get the BAT syntax here.
Thanks once again, @snibgo.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Categorising Images By Background

Post by snibgo »

It was untested, so had some bugs. This works:

Code: Select all

for %%F in (*.jpg) do (
  for /F "usebackq" %%L in (`%IMG7%magick ^
    %%F ^
    -fill Black +opaque White ^
    -format "ISWHITE=%%[fx:mean>0.7?1:0]" ^
    info:`) do set %%L
  if !ISWHITE!==1 (
    copy %%F whiteBackground\%%F
  ) else (
    copy %%F otherBackground\%%F
  )
)
For help on "for" (or other Windows command) type "help for" at the Windows command prompt.

An equivalent bash script is:

Code: Select all

for FILENM in *.jpg
do
  echo $FILENM

  ISWHITE=`magick \
    $FILENM \
    -fill Black +opaque White \
    -format "%[fx:mean>0.7?1:0]" \
    info:`

  if [ $ISWHITE -eq 1 ]; then
    cp $FILENM whiteBackground/$FILENM
  else
    cp $FILENM otherBackground/$FILENM
  fi
done
snibgo's IM pages: im.snibgo.com
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Categorising Images By Background

Post by FUrn »

This is excellent, @snibgo, and worked like a charm! Thanks so much - you've saved me a *lot* of time :)
Post Reply