Skip to content
Snippets Groups Projects
analyze.sh 7.2 KiB
Newer Older
#!/bin/bash

#
# Statistical helper functions for greyscale images.
#
# Requirements: ImageMagick's identify and convert
#
# If true, input files are assumed to be greyscale.
# If false, they are converted to greyscale before extracting statistics.
if [ "." == ".$ASSUME_GREY" ]; then
    ASSUME_GREY=true
fi

# TODO: Accept destination for identify-file as input

# Input: image
# Sample: foo.png
# Produces foo.identify if not already existing.
# Output: The name of the identity file
function im_identify() {
    local SRC="$1"
    local IDENTIFY=${SRC%%.*}.identify
    if [ -f "$IDENTIFY" ]; then
        echo "$IDENTIFY"
    if [ "false" == "$ASSUME_GREY" ]; then
    # We do the TIFF-conversion to force greyscale
        local TMP=`mktemp`.tif
        convert "$SRC" -colorspace gray "$TMP"
        identify -verbose "$TMP" > "$IDENTIFY"
        rm "$TMP"
    else
        identify -verbose "$SRC" > "$IDENTIFY"
    fi
    echo "$IDENTIFY"
}

# TODO: Accept destination for grey-stats-file as input

# Input: image
# Sample: foo.png
# Produces foo.grey with $PIXELS $UNIQUE $FIRST_COUNT $PERCENT_FIRST $FIRST_GREY $LAST_COUNT $PERCENT_LAST $LAST_GREY
# Output: $PIXELS $UNIQUE $FIRST_COUNT $PERCENT_FIRST $FIRST_GREY $LAST_COUNT $PERCENT_LAST $LAST_GREY $ZEROES $HOLES
function grey_stats() {
    local SRC="$1"
    if [ ! -f "$SRC" ]; then
        echo "grey_stats: The file $SRC does not exist in `pwd`"
        return
    fi

    local IDENTIFY=$(im_identify "$SRC")
    local GREY=${SRC%%.*}.grey
    local INFO=`cat "$IDENTIFY"`
    # TODO: No good as the histogram data might be much less than 256
    local VALUES=`cat "$IDENTIFY" | grep -A 256 Histogram`
    if [ ! "." == ".`echo "$VALUES" | grep Colormap`" ]; then
        local VALUES=`echo "$VALUES" | grep -B 256 Colormap`
    fi        
    local RAW_VALUES=`echo "$VALUES" | grep "[0-9]\\+: ("`

    local SAVEIFS=$IFS
    IFS=$(echo -en "\n")
    
    local UNIQUE=`echo $RAW_VALUES | wc -l`
    local FIRST_COUNT=`echo $RAW_VALUES | head -n 1 | grep -o " [0-9]\\+:" | grep -o "[0-9]\\+"`
    local FIRST_GREY=`echo $RAW_VALUES | head -n 1 | grep -o " ([0-9 ,]*)" | sed 's/ //g'`
    local LAST_COUNT=`echo $RAW_VALUES | tail -n 1 | grep -o " [0-9]\\+:" | grep -o "[0-9]\\+"`
    local LAST_GREY=`echo $RAW_VALUES | tail -n 1 | grep -o " ([0-9 ,]*)" | sed 's/ //g'`

    local ZEROES=$((256-UNIQUE))
    local SPAN=$((LAST_GREY-FIRST_GREY+1))
    local EDGE=$((256-SPAN))
    local HOLES=$((ZEROES-EDGE))

    local SPIKE_COUNT=`echo $RAW_VALUES | sort -n | tail -n 1 | grep -o " [0-9]\\+:" | grep -o "[0-9]\\+"`
    local SPIKE_GREY=`echo $RAW_VALUES | sort -n | tail -n 1 | grep -o " ([0-9 ,]*)" | sed 's/ //g'`

    local GEOMETRY=`echo $INFO | grep "Geometry: [0-9]\\+x[0-9]\\+" | grep -o "[0-9]\\+x[0-9]\\+"`
    local X=`echo $GEOMETRY | grep -o "[0-9]\\+x" | grep -o "[0-9]\\+"`
    local Y=`echo $GEOMETRY | grep -o "x[0-9]\\+" | grep -o "[0-9]\\+"`
    local PIXELS=`echo "$X*$Y" | bc`
    
    # http://stackoverflow.com/questions/8402181/how-do-i-get-bc1-to-print-the-leading-zero
    local PERCENT_FIRST=`echo "scale=2;x=$FIRST_COUNT*100/$PIXELS; if(x<1) print 0; x" | bc`
    local PERCENT_LAST=`echo "scale=2;x=$LAST_COUNT*100/$PIXELS; if(x<1) print 0; x" | bc`
    local SPIKE_PERCENT=`echo "scale=2;x=$SPIKE_COUNT*100/$PIXELS; if(x<1) print 0; x" | bc`
    
    echo "$PIXELS $UNIQUE $FIRST_COUNT $PERCENT_FIRST $FIRST_GREY $LAST_COUNT $PERCENT_LAST $LAST_GREY" > "$GREY"

    IFS=$SAVEIFS

    echo "$PIXELS $UNIQUE $FIRST_COUNT $PERCENT_FIRST $FIRST_GREY $LAST_COUNT $PERCENT_LAST $LAST_GREY $SPIKE_COUNT $SPIKE_PERCENT $SPIKE_GREY $ZEROES $HOLES"
# Produces a histogram over greyscale intensities in the given image
# Input: image height log
# Sample: foo.jpg 200 true
# Output: foo.png (256 x height pixels) with the histogram
function histogram() {
    local SRC="$1"
    local HEIGHT=$2
    local LOG=$3

    local IDENTIFY=`im_identify "$SRC"`
    local DEST=${SRC%%.*}.histogram.png
    # Convert      
    #   78085: (  0,  0,  0) #000000 black
    #    3410: (  1,  1,  1) #010101 rgb(1,1,1)
    # into
    # 0 78085
    # 1 3410
    if [ "." == ".`grep \"Colormap:\" \"$IDENTIFY\"`" ]; then
        GREYS=`cat "$IDENTIFY" | grep -A 256 "  Histogram:" | grep -o " \\+[0-9]\\+: ( *[0-9]\\+, *[0-9]\\+, *[0-9]\\+)" | sed 's/ \\+\\([0-9]\\+\\): ( *\\([0-9]\\+\\).\\+/\\2 \\1/g'`
     else
       GREYS=`cat "$IDENTIFY" | grep -A 9999 "  Histogram:" | grep -B 256 "Colormap:" | grep -o " \\+[0-9]\\+: ( *[0-9]\\+, *[0-9]\\+, *[0-9]\\+)" | sed 's/ \\+\\([0-9]\\+\\): ( *\\([0-9]\\+\\).\\+/\\2 \\1/g'`
    fi
    # Find lowest and highest for both intensity and count
    local MIN_GREY=255
    local MAX_GREY=0
    local MIN_COUNT=9999999
    local MAX_COUNT=0

    local SAVEIFS=$IFS
    IFS=$(echo -en "\n\b")
    while IFS= read -r L
    do
        local GREY=`echo "$L" | cut -d\  -f1`
        local COUNT=`echo "$L" | cut -d\  -f2`
        local TOTAL_COUNT=$((TOTAL_COUNT+COUNT))
        if [ $MIN_GREY -gt $GREY ]; then
            local MIN_GREY=$GREY
        fi
        if [ $MAX_GREY -lt $GREY ]; then
            local MAX_GREY=$GREY
        fi
        if [ $MIN_COUNT -gt $COUNT ]; then
            local MIN_COUNT=$COUNT
        fi
        if [ $MAX_COUNT -lt $COUNT ]; then
            local MAX_COUNT=$COUNT
        fi
    done <<< "$GREYS"
    echo "Grey: $MIN_GREY $MAX_GREY  count: $MIN_COUNT $MAX_COUNT $TOTAL_COUNT"

    # Let SCALE map all counts from 0 to 1
    if [ ".true" == ".$LOG" ]; then
        local SCALE=`echo "scale=10;1/l($MAX_COUNT)" | bc -l`
    else
        local SCALE=`echo "scale=10;1/$MAX_COUNT" | bc -l`
    fi

    # We create a PGM-file with the extracted greyscale statistics
    # as a histogram. The PGM is sideways because it is easier
    # http://netpbm.sourceforge.net/doc/pgm.html
    local HTMP=`mktemp`.pgm
    if [ "true" == "$LOG" ]; then
        local NONE=1
    else
        local NONE=0
    fi

    echo "P5 $HEIGHT 256 255" > $HTMP
    for G in `seq 0 255`; do
        local COUNT=`echo "$GREYS" | grep "^$G " | sed 's/[0-9]\\+ \\([0-9]\\+\\)/\\1/g'`
        if [ "." == ".$COUNT" ]; then
            local COUNT=$NONE
        fi
        if [ "true" == "$LOG" ]; then
            local PIXELS=`echo "scale=10;l($COUNT)/l(10)*$SCALE*$HEIGHT" | bc -l`
        else 
            local PIXELS=`echo "scale=10;$COUNT*$SCALE*$HEIGHT" | bc -l`
        fi
        # /1 due to funky bc scale not being applied if nothing is done
        local PIXELS=`echo "scale=0;$PIXELS/1" | bc -l`

        if [ 0 -lt $PIXELS ]; then
            for P in `seq 0 $PIXELS`; do
            done
        fi
        if [ $((HEIGHT-1)) -gt $PIXELS ]; then
            for P in `seq $((PIXELS+1)) $((HEIGHT-1)) `; do
            done
        fi

#        for P in `seq 0 $((HEIGHT-1))`; do
#            if [ $P -le $PIXELS ]; then
#                echo -n -e \\x0 >> $HTMP
#            else 
#                echo -n -e \\xff >> $HTMP
#            fi
#        done
#        echo "$G $COUNT $PIXELS"
    echo "convert -rotate 270 $HTMP $DEST"
    convert -rotate 270 $HTMP "$DEST"
    ls -l $HTMP
# grey_stats $1