#!/bin/bash
### Author: Benjamin Mitzkus
### This script generates random motion sequences where one or two objects
### move randomly on a background
## General Information:
## Vectors are always given as arrays in the notation a[0]=x, a[1]=y
ITERATION=${1}
# directory where the image patches are saved
OUTPUTDIR="output/${2}"
# subdirectory for occlusion patches
OCCOUTPUT=${OUTPUTDIR}/occlusion
# subdirectory for non-occlusion patches
NOOCCOUTPUT=${OUTPUTDIR}/motion
# directory where the image files are saved
IMAGEDIR="output/croppedImages"
# directory where the outline masks are saved
OUTLINEDIR="output/aloi_mask4_outline"
# list of image files
FILES=($(find ${IMAGEDIR} -name "*.png"))
# number of image files in $IMAGELIST
NUMFILES=${#FILES[@]}
# folder for temporary data, will be deleted on exit
TEMPDIR="tmp"
# size of the patches, always quadratic
PATCHSIZE=16
# number of frames for each sequence
NUMFRAMES=4
# boundaries for the velocity with which the images will move
MINVELOCITY=1.5 #Idea here: roughly sqrt(2) which means at least one pixel movement per frame
MAXVELOCITY=3
# seed to control pseudorandom number generation
SEED=0
SEED=$(awk "BEGIN{print ${SEED} + ($ITERATION*13)}")
### Help Functions
## random number generation
# Parameters: 1: return variable, 2: real or integer (r or i), 3: lower boundary, 4: upper boundary
function getRandomNumber {
local AWKSCRIPT=" { srand(${SEED}); print rand() } "
local rnd=`echo | awk "${AWKSCRIPT}"`
echo $rnd >> rnd.log
let SEED+=1
local lower=${3}
local upper=${4}
local ret
if [ ${2} == "i" ]
then
ret=$(awk "BEGIN{print ${rnd} * 1000000}")
ret=${ret%.*}
ret=$(awk "BEGIN{print ${ret}%(${upper}-(${lower}))+${lower}}")
elif [ ${2} == "r" ]
then
ret=$(awk "BEGIN{print (${rnd}*(${upper}-(${lower})))+${lower}}")
fi
eval "$1=${ret}" # return random number
}
## normalizing a vector
# Parameters: 1: return variable
function normalizeVector {
local vector; declare -a vector
local vectorname=$1[@]
vector=("${!vectorname}")
local length=$(awk "BEGIN{print sqrt((${vector[0]} * ${vector[0]}) + (${vector[1]} * ${vector[1]}))}")
if [ ${length} == 0 ];then
return 0 #avoid 0division here
fi
local x=$(awk "BEGIN{print ${vector[0]}/${length}}")
local y=$(awk "BEGIN{print ${vector[1]}/${length}}")
eval "${1}[0]=${x}"
eval "${1}[1]=${y}"
}
## searches $IMAGEDIR for .png files and choses one randomly
# Parameters: 1: return variable
function getRandomImagePath {
local RANDOMNUMBER
getRandomNumber RANDOMNUMBER i 1 ${NUMFILES}
eval "$1=${FILES[${RANDOMNUMBER}]}"
}
## finds the outline mask to a given image
# Parameters: 1: Image, 2: return variable
function findOutline {
local path; declare -a path
path=( $(echo ${1} | tr "/" "\n") )
local file
case "${path[2]}" in
aloi_red4_col)
file=${path[3]}_c1.png
;;
aloi_red4_ill)
file=${path[3]}_${path[4] : (-6)}
;;
aloi_red4_view)
local angle=$(echo ${path[4]} | cut -d"_" -f2)
if [ ${angle} == "r0.png" ]
then
file=${path[3]}_c1.png
else
file=${path[3]}_${angle}
fi
;;
esac
eval "${2}=${OUTLINEDIR}/${path[3]}/${file}"
}
## returns a random point on the white outline of a mask
# Parameters: 1: return array, 2: path to outline image
function findOutlinePoint {
local outlinepoints=($(convert ${2} txt:- | grep FFFFFF | sed "s/ //g" | cut -d":" -f1))
local numpoints=${#outlinepoints[@]}
local randomPoint
getRandomNumber randomPoint i 1 ${numpoints}
local outlineX=$(echo ${outlinepoints[${randomPoint}]} | cut -d"," -f1)
local outlineY=$(echo ${outlinepoints[${randomPoint}]} | cut -d"," -f2)
eval "${1}[0]=${outlineX}"
eval "${1}[1]=${outlineY}"
}
## calculates the center of a given image (integer, rounded down)
# Parameters: 1: return variable, 2: image
function calculateImageCenter {
local IMAGESIZE=$(identify ${2} | cut -d" " -f3)
local width=$(echo ${IMAGESIZE} | cut -d"x" -f1)
local height=$(echo ${IMAGESIZE} | cut -d"x" -f2)
local midX=$(awk "BEGIN{print int(${width}/2)}")
local midY=$(awk "BEGIN{print int(${height}/2)}")
eval "${1}[0]=${midX}"
eval "${1}[1]=${midY}"
}
## calculates the direction vector, images will move from the center to the outlinepoint
## with some random velocity between 0 and $MAXVELOCITY
# Parameters: 1: return variable, 2: image center, 3: outline point
function calculateMovement {
local centername=${2}[@]
local outlinename=${3}[@]
local imageCenter=("${!centername}")
local outlinePoint=("${!outlinename}")
local direction; declare -a direction
direction[0]=$(awk "BEGIN{print ${outlinePoint[0]} - ${imageCenter[0]}}")
direction[1]=$(awk "BEGIN{print ${outlinePoint[1]} - ${imageCenter[1]}}")
normalizeVector direction
local velocity
getRandomNumber velocity r ${MINVELOCITY} ${MAXVELOCITY}
local movement; declare -a movement
movement[0]=$(awk "BEGIN{print ${direction[0]} * ${velocity}}")
movement[1]=$(awk "BEGIN{print ${direction[1]} * ${velocity}}")
eval "${1}[0]=${movement[0]}"
eval "${1}[1]=${movement[1]}"
}
## finds a background patch with less than 10% transparent pixels
# Parameters: 1: return variable image path 2:return variable position of patch
function findBackgroundPatch {
local numPixels=$(awk "BEGIN{print ${PATCHSIZE}*${PATCHSIZE}}")
local maxTransparentPixels=$(awk "BEGIN{print int(${numPixels}*0.1)}")
local numTransparentPixels=${numPixels}
local transparentPixels; declare -a transparentPixels
while [ ${numTransparentPixels} -gt ${maxTransparentPixels} ]
do
local width=0
local height=0
local size
local image
local x
local y
while [ ${width} -lt ${PATCHSIZE} -o ${height} -lt ${PATCHSIZE} ]
do
getRandomImagePath image
size=$(identify ${image} | cut -d" " -f3)
width=$(echo ${size} | cut -d"x" -f1)
height=$(echo ${size} | cut -d"x" -f2)
done
getRandomNumber x i 0 $(awk "BEGIN{print ${width}-${PATCHSIZE} + 1}")
getRandomNumber y i 0 $(awk "BEGIN{print ${height}-${PATCHSIZE} + 1}")
transparentPixels=($(convert ${image} -crop "${PATCHSIZE}x${PATCHSIZE}+${x}+${y}" txt:- | grep "#......00"))
numTransparentPixels=${#transparentPixels[@]}
done
eval "${1}=${image}"
eval "${2}[0]=${x}"
eval "${2}[1]=${y}"
}
### Data structure management
## creating a temp folder which will be deleted on exit
function createTmpDir {
if [ -e ${TEMPDIR} ]
then
deleteTmpDir
fi
mkdir ${TEMPDIR}
}
function deleteTmpDir {
rm -r ${TEMPDIR}
}
## Manages the creation of all folders
function mkDirs {
createTmpDir
if [ ! -d ${OUTPUTDIR} ]
then
mkdir ${OUTPUTDIR}
mkdir ${OCCOUTPUT}
mkdir ${NOOCCOUTPUT}
fi
}
## creates a motion sequence where $NUMOBJECTS random objects move in random directions
## in $NUMFRAMES frames and overlap in some of them
# Parameters: 1: patchNumber
function createMotionSequence {
# get one or two random image paths
local IMAGE
getRandomImagePath IMAGE
local OUTLINE
findOutline ${IMAGE} OUTLINE
local OUTLINEPOINT; declare -a OUTLINEPOINT
findOutlinePoint OUTLINEPOINT ${OUTLINE}
local IMAGECENTER; declare -a IMAGECENTER
calculateImageCenter IMAGECENTER ${IMAGE}
local MOVEMENT; declare -a MOVEMENT
calculateMovement MOVEMENT IMAGECENTER OUTLINEPOINT
# calculate the point where the objects meet
local STARTPOINT; declare -a STARTPOINT
getRandomNumber STARTPOINT[0] i 0 $(awk "BEGIN{print int(${PATCHSIZE/4}) + 1}")
getRandomNumber STARTPOINT[1] i 0 $(awk "BEGIN{print int(${PATCHSIZE/4}) + 1}")
if [ $(echo "${MOVEMENT[0]}<0" | bc -l) ] #moving left, STARTPOINT should be in right half
then
STARTPOINT[0]=$(awk "BEGIN{print ${PATCHSIZE} - ${STARTPOINT[0]}}")
fi
if [ $(echo "${MOVEMENT[1]}<0" | bc -l) ] #moving up, STARTPOINT should be in lower half
then
STARTPOINT[1]=$(awk "BEGIN{print ${PATCHSIZE} - ${STARTPOINT[1]}}")
fi
local xOffset=$(awk "BEGIN{print ${STARTPOINT[0]} - ${OUTLINEPOINT[0]}}")
local yOffset=$(awk "BEGIN{print ${STARTPOINT[1]} - ${OUTLINEPOINT[1]}}")
local background="${TEMPDIR}/${1}background.png"
local size="${PATCHSIZE}x${PATCHSIZE}"
local backgroundPatch
local patchPos
findBackgroundPatch backgroundPatch patchPos
convert ${backgroundPatch} -crop "${PATCHSIZE}x${PATCHSIZE}+${patchPos[0]}+${patchPos[1]} " png:- | composite png:- -size ${size} xc:white ${background}
for frame in `seq 1 ${NUMFRAMES}`; do
local occFile="${TEMPDIR}/${1}occFrame${frame}.png"
local nooccFile="${TEMPDIR}/${1}nooccFrame${frame}.png"
local xPosition=$(awk "BEGIN{print ${xOffset} + (${frame} * ${MOVEMENT[0]})}")
local xPosition=$(echo ${xPosition} | awk '{printf "%.0f\n", $1}') # rounding to integer
local yPosition=$(awk "BEGIN{print ${yOffset} + (${frame} * ${MOVEMENT[1]})}")
local yPosition=$(echo ${yPosition} | awk '{printf "%.0f\n", $1}') # rounding to integer
if [ ${xPosition} -ge 0 ]
then
xPosition="+${xPosition}"
fi
if [ ${yPosition} -ge 0 ]
then
yPosition="+${yPosition}"
fi
composite -geometry "${xPosition}${yPosition}" ${IMAGE} ${background} png:- | convert :- -colorspace Gray ${occFile}
composite -geometry "${xPosition}${yPosition}" ${IMAGE} -size ${size} xc:white png:- | convert :- -colorspace Gray ${nooccFile}
done
local imageNr=$(echo ${IMAGE} | grep -o '[^/]*$' |cut -d"_" -f1)
local backgroundNr=$(echo ${backgroundPatch} | grep -o '[^/]*$' | cut -d"_" -f1)
local occOutputfile=${OCCOUTPUT}/${1}_${imageNr}_${backgroundNr}.png
local nooccOutputfile=${NOOCCOUTPUT}/${1}_${imageNr}.png
cp ${TEMPDIR}/${1}occFrame1.png ${occOutputfile}
cp ${TEMPDIR}/${1}nooccFrame1.png ${nooccOutputfile}
local i
for i in `seq 2 ${NUMFRAMES}`
do
convert ${occOutputfile} ${TEMPDIR}/${1}occFrame${i}.png +append ${occOutputfile}
convert ${nooccOutputfile} ${TEMPDIR}/${1}nooccFrame${i}.png +append ${nooccOutputfile}
done
}
### FUNCTION CALLS STARTING HERE ###
mkDirs
createMotionSequence ${ITERATION}
deleteTmpDir