imagemagick

How to apply brightness to a rectangular region with a feather


I need to batch process image files and know nothing about ImageMagick, but it is installed on my mac and I can use it. I have over 60 png files that are 256x256 pixels in size that I wish to brighten in a rectangular region with a feather applied to the edges of the region. Can this be done in ImageMagick, and how?

Here is the original image

enter image description here

Here is what I want in terms of brightness, but I am unable to demonstrate feather as I am not proficient in GiMP.

enter image description here

I want to use a feather of about 64 pixels. I want to brighten the rectangle with origin at 32,32 having width/height of 192x192 (ie 256 - 32 - 32), so 32,32,192x192.

I am using a Mac Mini M1 2020 running macOS Sonoma 14.5

% magick --version
Version: ImageMagick 7.0.10-0 Q16 x86_64 2020-03-08 https://imagemagick.org
Copyright: © 1999-2020 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(3.1) 
Delegates (built-in): bzlib freetype heic jng jp2 jpeg lcms ltdl lzma openexr png tiff webp xml zlib

EDIT

I've engaged ChatGPT to attempt to solve this issue. It produces a script that runs, but the results are far from intended. Here is the script and resulting image.

#!/bin/zsh

# Function to show usage
function show_usage {
    echo "Usage: $0 --brightness value [--region x,y,width,height] [--feather radius] input_file"
    echo "  --brightness value            Adjust brightness (value between -1 and 1)"
    echo "  --region x,y,width,height     Apply adjustment only to the specified rectangular region"
    echo "  --feather radius              Feather (blur) the edges of the region (radius in pixels)"
    echo "  input_file                    The image file to process"
    exit 1
}

# Check that arguments are provided
if [[ $# -lt 3 ]]; then
    show_usage
fi

# Parse arguments
REGION=""
FEATHER=0
while [[ $# -gt 0 ]]; do
    case "$1" in
        --brightness)
            BRIGHTNESS="$2"
            shift 2
            ;;
        --region)
            REGION="$2"
            shift 2
            ;;
        --feather)
            FEATHER="$2"
            shift 2
            ;;
        *)
            INPUT_FILE="$1"
            shift
            ;;
    esac
done

# Check if input file exists
if [[ ! -f "$INPUT_FILE" ]]; then
    echo "Input file does not exist: $INPUT_FILE"
    exit 1
fi

# Calculate the brightness adjustment percentage for ImageMagick
BRIGHTNESS_PERCENT=$(echo "scale=2; (1 + $BRIGHTNESS) * 100" | bc)

# Create an output filename
OUTPUT_FILE="${INPUT_FILE%.*}_brightness_feathered.${INPUT_FILE##*.}"

# If region is specified, apply brightness only to that region
if [[ -n "$REGION" ]]; then
    # Parse the region values
    IFS=',' read -r REGION_X REGION_Y REGION_WIDTH REGION_HEIGHT <<< "$REGION"

    echo "Applying brightness to region: ${REGION_X},${REGION_Y} ${REGION_WIDTH}x${REGION_HEIGHT}"
    echo "Feathering: ${FEATHER}px"

    magick "$INPUT_FILE" \
        \( +clone -crop "${REGION_WIDTH}x${REGION_HEIGHT}+${REGION_X}+${REGION_Y}" \
        -modulate "$BRIGHTNESS_PERCENT",100,100 -write mpr:region +delete \) \
        \( -size "${REGION_WIDTH}x${REGION_HEIGHT}" xc:black -fill white \
        -draw "rectangle 0,0 ${REGION_WIDTH},${REGION_HEIGHT}" \
        -blur 0x"$FEATHER" -write mpr:mask +delete \) \
        "$INPUT_FILE" -write mpr:original \
        \( mpr:region mpr:mask -compose DstIn -composite \) \
        -geometry +${REGION_X}+${REGION_Y} -compose Over -composite "$OUTPUT_FILE"

else
    # Apply brightness adjustment to the entire image
    magick "$INPUT_FILE" -modulate "$BRIGHTNESS_PERCENT",100,100 "$OUTPUT_FILE"
fi

# Output result
echo "Brightness adjusted image saved as: $OUTPUT_FILE"

enter image description here

I used the following command:

% script.sh --brightness 0.6 --region 64,64,224,224 --feather 10 sample-1.png

Solution

  • This should do what you want in Imagemagick.

    enter image description here

    infile=image.png
    wd=224
    ht=224
    xo=32
    yo=32
    brightness=0.6
    feather=10
    region="${wd}x${ht}+${xo}+${yo}"
    brightness_pct=$(echo "scale=2; (1 + $brightness) * 100" | bc)
    outfile="${infile%.*}_${brightness}_${feather}.${infile##*.}"
    echo "$region"
    echo "$brightness_pct"
    echo "$outfile"
    
    magick "$infile" +repage \
    \( +clone -crop "$region" -modulate "$brightness_pct",100,100 \) \
    \( -size "$region" xc:black -fill white -draw "rectangle 0,0 $wd,$ht" -blur 0x$feather \) \
    -geometry +${xo}+${yo} -compose Over -composite "$outfile"
    

    enter image description here

    You can add the rest of the script commands.

    ChatGPT added too much redundancy to the Imagemagick command, which messed up the command and you used different region origin from what you wanted. They used 64,64 and you actually said originally that you wanted 32,32.

    ADDITION

    Here is script with a for loop over all PNG images in a directory. Change the directory and other arguments as desired

    directory=/Users/fred/desktop/test
    wd=224
    ht=224
    xo=32
    yo=32
    brightness=0.6
    feather=10
    cd
    cd $directory
    for infile in *.png; do
    outfile="${infile%.*}_${brightness}_${feather}.${infile##*.}"
    region="${wd}x${ht}+${xo}+${yo}"
    brightness_pct=$(echo "scale=2; (1 + $brightness) * 100" | bc)
    im7 magick "$infile" +repage \
    \( +clone -crop "$region" -modulate "$brightness_pct",100,100 \) \
    \( -size "$region" xc:black -fill white -draw "rectangle 0,0 $wd,$ht" -blur 0x$feather \) \
    -geometry +${xo}+${yo} -compose Over -composite "$outfile"
    done