[SOLVED] Trim around highest detail region while keeping the AR

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
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

[SOLVED] Trim around highest detail region while keeping the AR

Post by guido.pettinari »

Update August 2019
The problem was solved thanks to the contributions of Fred & snibgo! There is now a script on Github that achieves my original need, and a little bit more => https://github.com/coccoinomane/trim-ratio 🙂

Original thread

Hello!

As this is my first post, I wish to thank you for keeping this forums alive with incredibly useful tips and suggestions! And also please forgive me if my question is naive.

QUESTION:

Is there a way to crop around the highest detail region of an image while keeping the same aspect ratio and leaving some background around it?

Potential issues:

1. My background is a photographic grey limbo, so it's not 100% uniform.
2. Some photos depict objects which are very eccentric (see example 3).

I have already tried without success with the smarttrim and smartcrop scripts from the amazing Fred's scripts (http://www.fmwconcepts.com/imagemagick/index.php).

EXAMPLE 1:

Before:
Image

After:
Image

EXAMPLE 2:

Before:
Image

After:
Image

EXAMPLE 3:

The following two pictures should not be affected because they fully fit at least one dimension of the canvas:
Image
Image

CONTEXT:

Think of 1000 square photos of differently sized products all on a gray background; these are actual photographs using a grey limbo as background.
The script should automatically enlarge the product leaving a minimal (configurable) gray background top and bottom of the product.
This would be a life saver because products all have different sizes, but the photographer took the photos using the same perspective and zoom.

Thank you,
Guido Pettinari
Last edited by guido.pettinari on 2019-08-09T09:29:25-07:00, edited 3 times in total.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Enlarge hightest detail region

Post by snibgo »

What version of IM, on what platform?

You say you want to "enlarge" a region, but your examples show no enlargement. Instead, they seem to crop most of the gray background.

Your example 3 "should not be affected because they fully fit at least one dimension of the canvas". Perhaps you mean that the object is already close to one or more image edges, so not much can be trimmed from those edges. Is that correct?
snibgo's IM pages: im.snibgo.com
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

Re: Enlarge hightest detail region

Post by guido.pettinari »

Hi snibgo, thank you for your quick reply!

I am using IM 7.0.8-56 on a Mac 10.14, but if needed I can switch versions of both IM and OS.
snibgo wrote: 2019-07-28T09:31:17-07:00 You say you want to "enlarge" a region, but your examples show no enlargement. Instead, they seem to crop most of the gray background.
Yes, what I really meant is to crop the background, not to enlarge the object: I am sorry for using the wrong term!
I am going to change the thread title.
snibgo wrote: 2019-07-28T09:31:17-07:00 Your example 3 "should not be affected because they fully fit at least one dimension of the canvas". Perhaps you mean that the object is already close to one or more image edges, so not much can be trimmed from those edges. Is that correct?
Yes, 100% correct! There's no need to trim those images where the object is already close to one or more edges.
This case could be addressed by a parameter to specify a minimum number of background pixels to keep in the vertical dimension...

Please let me know if you need any other information :-)
Thanks,
Guido
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop around highest detail region while keeping the AR

Post by fmw42 »

If you have good contrast between the foreground and background just use

Code: Select all

magick input -fuzz XX% -trim +repage output
See XX between 0 and 100 with as small a value that will trim the background as desired.
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

Re: Crop around highest detail region while keeping the AR

Post by guido.pettinari »

fmw42 wrote: 2019-07-28T12:36:22-07:00 If you have good contrast between the foreground and background just use

Code: Select all

magick input -fuzz XX% -trim +repage output
See XX between 0 and 100 with as small a value that will trim the background as desired.
Thank you very much Fred for your reply!

I have tried many different values of fuzz XX%.
At 7%, the background in the vertical dimension is already trimmed almost completely:

Image

I start seeing some horizontal trimming only if I use fuzz values bigger than 10%; this is 15%:

Image

I think this behaviour is due to the presence of the horizontal shadow in the pictures:

Image

The shadow introduces an asimmetry which forces the trim algorithm to trim more on the vertical dimension than it does on the horizontal dimension.
This is the same issue I encountered when using the smarttrim script, even if I used -h and -w parameters.

Alas, the images are for a catalogue and they should keep the same aspect ratio.

I probably need am algorithm that determines how much to crop ignoring shadows and making sure the aspect ratio stays the same.

I understand this is probably too much to ask to the Users form... if the moderators agree, I am happy to move my thread to the "Paid" section of the forum.

Thank you very much,
Guido
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Crop around highest detail region while keeping the AR

Post by snibgo »

It seems to me that one of Fred's scripts almost does the job, but needs some extra processing at the end.

Those scripts will find the object's bounding rectangle. But then, the requirement is to:

1. expand the rectangle, to get a certain padding on the four sides (smarttrim "pad");

2. also expand the rectangle to retain the aspect ratio of the input image;

3. if this expansion would go beyond the input image boundaries, don't do any trimming at all.
snibgo's IM pages: im.snibgo.com
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop around highest detail region while keeping the AR

Post by fmw42 »

With the slow change in background, your images are very conducive to using -canny edge detection to find the crop values. Here is some code for IM 7 that I used on my Mac (unix syntax). Change the blur 5 value to adjust the amount of pad that you want.

I clone the image, do canny edge detection on the clone. Then I crop the canny edge image and get the crop values from %@ and save in %[crop]. Then I delete the canny image and use the crop values on the input image.

Code: Select all

infile="_POD0009-before.jpg"
infile="_POD0377-before.jpg"
infile="_POD0029.jpg"
infile="_POD1444.jpg"
name=`im7 magick "$infile" -format "%t" info:`
im7 magick "$infile" \
\( -clone 0 -canny 0x1+10%+30% -blur 5x65000 -set option:crop "%@" +delete \) \
-crop "%[crop]" +repage ${name}_crop.jpg
Image

Image

Image

Image
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

Re: Crop around highest detail region while keeping the AR

Post by guido.pettinari »

Thank you very much snibgo and Fred, your help is very much appreciated!

If I am not mistaken, Fred's snippet is step 0 in the process outlined by snibgo: find the object's bounding rectangle.

This is super helpful because now I can do step 1, that is, pad the bounding rectangle.

My doubt is how to add padding using the background from the input image, which I need because I have to keep to shadow in the final image.

I think I can achieve this in three steps:

1. Extract the crop parameters from Fred's command, which I think are contained in %[crop] and should look like WIDTHxHEIGHT+XX+YY.
2. Adjust the crop parameters by adding pixels to the 4 sides up to a desired size, while maintaining the aspect ratio.
3. Crop again the original image using the crop parameters thus obtained.

I will try to concoct an IM script and report back to the forum... wish me good luck! 😅

Best wishes,
Guido
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop around highest detail region while keeping the AR

Post by fmw42 »

In my code the padding simply adjusts the crop values and is done already by the -blur 5x65000. Just increase the 5 to make more padding. By adjusting the crop values, you get more input image around your object, not padding with some simple color.
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

Re: Crop around highest detail region while keeping the AR

Post by guido.pettinari »

Hello!

Thanks Fred for the suggestion :-)

I wrote down a Bash script called trim-ratio which trims an image around the highest detail region without changing its aspect ratio.
The complications were 1) to maintain the same AR and 2) to control how much is trimmed.
I ended up manipulating the crop parameters in bash using bc, rather than in ImageMagick.
I hope this approach will make it easier in the future to improve the script.

The script requires bash with the bc library, and it is run like this:

Code: Select all

./trim-ratio.sh <input image> [<padding (default 0px)>] [<output folder (default current folder)>] [<blur (default 5px)>]
The main limitations I can think of are:
  • The padding strategy is quite simple: padding is added uniformly in the four dimensions, no matter where the highest detail region is.
  • I have tested the script only on square AR.
  • In general, I am not an expert of IM, so I am sure there will be many ways in which the script can be impoved.
The script and a basic documentation can be found on Github => https://github.com/coccoinomane/trim-ratio.
I have included examples in the following folders:
I copy the script here for convenience, but please refer to the Github link if for the most up-to-date version:

Code: Select all

#! /usr/bin/env bash

# Trim an image around the highest detail region without
# changing its aspect ratio.
#
# Optionally specify how many pixels to pad around the
# highest detail region; the padding will be taken
# from the actual image.
#
# Useful to trim background around the subject, while
# keeping the same AR and having control on how much
# is trimmed.
#
# Requires bash with the bc arithmetical library.
#
# TODO
# * Implement different padding strategy; at the moment
# the padding is uniform in the four dimensions no matter
# where the highest detail region is.
# * Test on AR different from a square
#
# THANKS TO:
# - Fred (fmw42) and Snibgo from ImageMagick forums
#   (https://imagemagick.org/discourse-server/viewtopic.php?f=1&t=36443)

# Parse arguments
image="$1"
pad=${2-0}
out_folder=${3-.}
blur=${4-5}

# Get of image info
name=$(magick "$image" -format "%t" info:)
W=$(magick "$image" -format "%[w]" info: )
H=$(magick "$image" -format "%[h]" info: )
AR=$(magick "$image" -format "%[fx:w/h]" info: )

# Output images
trimmed_image="${out_folder}/${name}_blur${blur}_trim.jpg"
padded_image="${out_folder}/${name}_blur${blur}_pad${pad}.jpg"

echo "Processing image ${name} with size ${W}x${H} and AR=${AR}..."

# Get rectangle bounding highest definition area, and store its parts
bounding_rectangle=$(magick "$image" -canny 0x1+10%+30% -blur "${blur}"x65000 -format "%@" info:)
echo "  bounding rectangle = $bounding_rectangle" 
WB=$(echo "$bounding_rectangle" | sed -E -e 's/^([[:digit:]]+).*/\1/')
HB=$(echo "$bounding_rectangle" | sed -E -e 's/^.*x([[:digit:]]+)\+.*/\1/')
xB=$(echo "$bounding_rectangle" | sed -E -e 's/^.*\+([[:digit:]]+)\+.*/\1/')
yB=$(echo "$bounding_rectangle" | sed -E -e 's/^.*\+([[:digit:]]+)$/\1/')
[[ $bounding_rectangle = ${WB}x${HB}+${xB}+${yB} ]] || { echo "Error extracting crop dimensions"; exit; }

# Exit if nothing can be trimmed
(( WB == W && HB == H )) && { echo "Nothing to trim, will exit"; exit; }

# Output image with bounding rectangle
magick "$image" -crop "$bounding_rectangle" +repage "$trimmed_image"

# Compute available space in the 4 directions
ST=$yB
SB=$((H-HB-ST))
SL=$xB
SR=$((W-WB-SL))
echo "  available space: top=${ST}, bottom=${SB}, left=${SL}, right=${SR}"

# Initialize parameters of new crop area
WT=$WB
HT=$HB
xT=$xB
yT=$yB

# Recover aspect ratio
if (( $(echo "$WB > $AR*$HB" | bc) )); then
    echo "  forcing aspect ratio to $AR"
    HT="$(echo "$WB/$AR" | bc)"
    yT="$(echo "$yB+($HB-$HT)/2" | bc)"
    echo "    height changed from $HB to $HT"
    echo "    vertical position (y) changed from $yB to $yT"
else
    echo "  forcing aspect ratio to $AR"
    WT="$(echo "$AR*$HT" | bc)"
    xT="$(echo "$xB+($WB-$WT)/2" | bc)"
    echo "    width changed from $WB to $WT"
    echo "    horizontal position changed from $xB to $xT"
fi

# Add padding
if (( pad > 0 )); then
    WT="$(echo "$WT+$pad" | bc)"
    xT="$(echo "$xT-($pad)/2" | bc)"
    HT="$(echo "$HT+$pad" | bc)"
    yT="$(echo "$yT-($pad)/2" | bc)"
fi

# Round to integer
WT="$(echo "($WT+0.5)/1" | bc)" # round to int
HT="$(echo "($HT+0.5)/1" | bc)" # round to int
xT="$(echo "($xT+0.5)/1" | bc)" # round to int
yT="$(echo "($yT+0.5)/1" | bc)" # round to int

# Output final image
padded_rectangle="${WT}x${HT}+${xT}+${yT}"
echo "  final rectangle = $padded_rectangle"
echo "  writing to $padded_image"
magick "$image" -crop "$padded_rectangle" +repage "$padded_image"

Please let me know if you have any suggestion to improve the script.

Thank you,
Guido
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Crop around highest detail region while keeping the AR

Post by snibgo »

wrote:name=$(magick "$image" -format "%t" info:)
W=$(magick "$image" -format "%[w]" info: )
H=$(magick "$image" -format "%[h]" info: )
AR=$(magick "$image" -format "%[fx:w/h]" info: )
These can be combined into one, so you don't need to run magick and read the image four times:

Code: Select all

declare $(magick toes.png -format 'name=%t\nW=%w\nH=%h\nAR=%[fx:w/h]' info:)
snibgo's IM pages: im.snibgo.com
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

Re: Crop around highest detail region while keeping the AR

Post by guido.pettinari »

Thanks snibgo!
That snippet is handy.

By the way, I have found a bug: when I adapt the image to the original AR, I should be checking whether there's enough space in both directions, rather than just adding half of the pixels to each direction.
I will fix it in the weekend :-)
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

Re: Crop around highest detail region while keeping the AR

Post by guido.pettinari »

I updated the script so that now it works also with non-square AR + it always keeps the AR in the zero padding case.
Details about the script at https://github.com/coccoinomane/trim-ratio, latest zip here => https://github.com/coccoinomane/trim-ra ... e/v1.1.zip

There still is a bug whereby non-centred objects (such as this one https://github.com/coccoinomane/trim-ra ... m_left.png) will not be padded correctly.

I'll try to fix it over the weekend.
guido.pettinari
Posts: 8
Joined: 2019-07-28T07:33:19-07:00
Authentication code: 1152

Re: Crop around highest detail region while keeping the AR

Post by guido.pettinari »

I confirm that the remaining (known) bugs have been corrected, and that I have succesfully used the script on my products :-)

Thank you again Fred and snibgo for helping me out on this!

Have a nice day,
Guido
Post Reply