Skip to content

Instantly share code, notes, and snippets.

@nicjansma
Created July 30, 2025 00:17
Show Gist options
  • Select an option

  • Save nicjansma/e67f4d134c3c4420e51246fe7a50837c to your computer and use it in GitHub Desktop.

Select an option

Save nicjansma/e67f4d134c3c4420e51246fe7a50837c to your computer and use it in GitHub Desktop.
compare-images-in-directories.sh - finds matching images in two sets of directories under a DSSIM similarity threshold
#!/bin/bash
# Enhanced version that can use dssim, ssim, or ImageMagick
# Usage: ./enhanced_compare.sh <directory1> <directory2> [threshold] [method]
DEFAULT_THRESHOLD=0.01
DEFAULT_METHOD="auto"
usage() {
echo "Usage: $0 <directory1> <directory2> [threshold] [method]"
echo "Methods: auto, dssim, imagemagick, perceptual"
echo " auto: automatically choose best available method"
echo " dssim: use dssim tool (most accurate)"
echo " imagemagick: use ImageMagick compare"
echo " perceptual: use perceptual hashing"
exit 1
}
# Function to check available similarity tools
detect_similarity_tools() {
local available_tools=()
if command -v dssim &> /dev/null; then
available_tools+=("dssim")
fi
if command -v compare &> /dev/null; then
available_tools+=("imagemagick")
fi
# Perceptual hashing is always available if ImageMagick is present
if command -v convert &> /dev/null; then
available_tools+=("perceptual")
fi
echo "${available_tools[@]}"
}
# Function to use dssim for comparison
compare_with_dssim() {
local img1="$1"
local img2="$2"
# dssim returns 0 for identical images, higher values for more different images
local result=$(dssim "$img1" "$img2" 2>/dev/null | awk '{print $1}')
echo "$result"
}
# Parse arguments
DIR1="$1"
DIR2="$2"
THRESHOLD="${3:-$DEFAULT_THRESHOLD}"
METHOD="${4:-$DEFAULT_METHOD}"
if [ $# -lt 2 ]; then
usage
fi
# Detect available tools
available_tools=($(detect_similarity_tools))
if [ ${#available_tools[@]} -eq 0 ]; then
echo "Error: No image comparison tools available."
echo "Please install one of: dssim, imagemagick"
exit 1
fi
# Choose method
if [ "$METHOD" = "auto" ]; then
if [[ " ${available_tools[@]} " =~ " dssim " ]]; then
METHOD="dssim"
elif [[ " ${available_tools[@]} " =~ " imagemagick " ]]; then
METHOD="imagemagick"
else
METHOD="perceptual"
fi
fi
echo "Using method: $METHOD"
echo "Available tools: ${available_tools[*]}"
echo "Comparing PNG images using perceptual similarity:"
echo " Directory 1: $DIR1"
echo " Directory 2: $DIR2"
echo " Similarity threshold: $THRESHOLD (lower = more strict)"
echo
# Create temporary directory
TEMP_DIR=$(mktemp -d)
cleanup() {
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
# Find all PNG files
PNG_FILES1=($(find "$DIR1" -type f -iname "*.png" | sort))
PNG_FILES2=($(find "$DIR2" -type f -iname "*.png" | sort))
if [ ${#PNG_FILES1[@]} -eq 0 ]; then
echo "No PNG files found in directory 1"
exit 0
fi
if [ ${#PNG_FILES2[@]} -eq 0 ]; then
echo "No PNG files found in directory 2"
exit 0
fi
echo "Found ${#PNG_FILES1[@]} PNG files in directory 1"
echo "Found ${#PNG_FILES2[@]} PNG files in directory 2"
echo "Starting comparison..."
echo
MATCHES=0
COMPARISONS=0
LOWESTTHRESHOLD=1.0
LOWESTTHRESHOLDMATCH1=""
LOWESTTHRESHOLDMATCH2=""
# Compare each image from dir1 with each image from dir2
for img1 in "${PNG_FILES1[@]}"; do
img1_name=$(basename "$img1")
echo "Processing: $img1_name"
for img2 in "${PNG_FILES2[@]}"; do
img2_name=$(basename "$img2")
((COMPARISONS++))
# Show progress for large comparisons
if [ $((COMPARISONS % 100)) -eq 0 ]; then
echo " ...completed $COMPARISONS comparisons"
fi
# Compare images
similarity=$(compare_with_dssim "$img1" "$img2")
# Check if similarity is below threshold (more similar)
if [ -n "$similarity" ]; then
# Use bc for floating point comparison if available, otherwise use awk
if command -v bc &> /dev/null; then
is_similar=$(echo "$similarity <= $THRESHOLD" | bc)
else
is_similar=$(awk -v sim="$similarity" -v thr="$THRESHOLD" 'BEGIN {print (sim <= thr) ? 1 : 0}')
fi
is_less_lowest=$(echo "$similarity <= $LOWESTTHRESHOLD" | bc)
if [ "$is_less_lowest" -eq 1 ]; then
LOWESTTHRESHOLD=$similarity
LOWESTTHRESHOLDMATCH1="$img1"
LOWESTTHRESHOLDMATCH2="$img2"
echo "New lowest threshold match found: $similarity"
echo " File 1: $img1"
echo " File 2: $img2"
fi
if [ "$is_similar" -eq 1 ]; then
echo ""
echo "*** SIMILAR IMAGES FOUND ***"
echo " File 1: $img1"
echo " File 2: $img2"
echo " Similarity score: $similarity (threshold: $THRESHOLD)"
# Additional info
info1=$(identify -format "%wx%h %b" "$img1" 2>/dev/null)
info2=$(identify -format "%wx%h %b" "$img2" 2>/dev/null)
echo " File 1 info: $info1"
echo " File 2 info: $info2"
echo ""
((MATCHES++))
fi
fi
done
done
echo ""
echo "=== SUMMARY ==="
echo "Total comparisons performed: $COMPARISONS"
echo "Similar image pairs found: $MATCHES"
echo "Similarity threshold used: $THRESHOLD"
echo "PNG files in directory 1: ${#PNG_FILES1[@]}"
echo "PNG files in directory 2: ${#PNG_FILES2[@]}"
echo "Lowest threshold match found: $LOWESTTHRESHOLD"
echo " File 1: $LOWESTTHRESHOLDMATCH1"
echo " File 2: $LOWESTTHRESHOLDMATCH2"
if [ $MATCHES -gt 0 ]; then
echo ""
echo "Similar images were found!"
exit 0
else
echo ""
echo "No similar images found with the current threshold."
echo "Try increasing the threshold (e.g., 0.1) for more lenient matching."
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment