Tuesday, June 21, 2016

30 Days of Compost + Panning Video + Removing 'bad' images




1. This is 2743 images taken over ~30 days.

2. A scan happens every 15 minutes, that means I should have ~2,880 images.

3. Sometimes the scanner jams halfway through a scan. This isn't horrible, but the resulting image has a streak of repeating pixels starting where the scanner jammed. This is particularly jarring when images are played back as a video.

4. I liked the effect of panning across the images (see earlier post), but wanted to clean things up + timestamp the images.
       
So two short scripts are run:
Clean Images:
#!/bin/bash
for file in *.jpg
do
        convert $file -crop 768x1+0+10 image_a.jpg
        convert $file -crop 768x1+0+30 image_b.jpg
        if [ $(compare -metric RMSE image_a.jpg image_b.jpg NULL: 2>&1 \ | sed 's/.*(//' | cut -c1-4 | cut -c 4-) -gt 0 ]

        then
                echo "$file keep"
        else
                echo "$file remove"
                mv $file brokenimages/
        fi
done
rm image*.jpg


Left image bad. Jammed about 3/5ths through the scan. Right image good!

For every jpg image in a directory we'll create two temporary images, a single row of 768 pixels located 10 and 30 pixels down from the top. We'll use imagemagick's compare tool to get a rough idea of how different they are, this feedback looks like:

350.361 (0.00534616) for images with little to no difference

2145.33 (0.0327357) for images with some difference

I'm using BASH, it doesn't like floating point numbers. We get lazy and grab the second number past the decimal point. If this number is > 0, we can assume we're dealing with two images with enough difference that it's good to keep. This could fail, but so far it's worked with ~3,000+ images. It's not particularly fast, taking approximately 3 seconds / image on a Pi 2 Model B. Running it retroactively isn't fun, but checking images as they are scanned (once every 15 minutes) is plenty fast.


Panning
In order to get the panning / scrolling affect, I crop each image down to 1920x1080 pixels starting at the top. With (almost) every image I shift the cropped area down 1 pixel. I like the idea that I can slowly pan through the entire length of the scanned area in the time it takes to run through each image, but I have more images than pixels height to move through:

2743 images = 2743 pixels to shift.
3484 = original image height.
-1080 to account for the video height
2404 = 3484-1080. Total number of pixels I need to shift down.

If I move down one pixel for each image, we'll be 339 pixels below the bottom of the scanner. I could try shifting partial pixels but that involves more work. Again laziness, so instead we just don't shift every 6th image. This isn't exact, but it gets us close to the bottom of the scanner area.

Is it noticeable in the video? : )

Cycling through all the images in a directory, we grab the date and time from the file name and set that aside as ndate & ntime. Using the imagemagick tool convert we crop a 1920x1080 chunk out of each 2480x3484 image starting at the top, shifted 280 pixels in from the left. We add a small 400x30px background bottom center and pop the $ndate and $ntime values as a text caption on top of this background.

Each image processed we increment the value $a by 1, if $a is < 6, we shift the cropped location down 1 px. If the value of $a is equal to 6, we don't shift the the image down and we reset the value of $a to 0.

This image is saved with the prefix "temp_" and a four digit number starting with 0000. Saving in this naming format makes it easy for us in the next step to wrap these images up in a nice mpeg video file.

#!/bin/bash
a=0
shift=0
count=0
for file in *.jpg;
do
        counter=$(printf %04d $count);
        ndate="${file:3:4}\/${file:7:2}\/${file:9:2}"
        ntime="${file:12:2}:${file:14:2}:${file:16:2}"
        convert $file -crop 1920x1080+280+$shift - | convert -background '#0008'   \
                -gravity center \
                -fill white     \
                -size 400x30    \
                -pointsize 24   \
                -kerning 2.5    \
                -font Courier   \
                caption:"${ndate} ${ntime}"     \
                -       \
                +swap   \
                -gravity south  \
                -composite      \
             "temp_$counter".jpg; 

if [ $a -eq 6 ];
then
        let shift=$shift+0
        a=0
else
        let shift=$shift+1
        let a=$a+1
fi

echo -e "$file\t$count\t$shift"
        count=$(($count+1))
done

And then we need to turn these images into a video file:
avconv -y -r 30 -i temp_%04d.jpg -r 30 -vcodec libx264 -crf 20 -g 15 CompostCam30Days.mp4

This probably took an hour to process on a ~6 year old Mac Laptop. It could be done on the raspberry pi, but the converting and timestamping of images would have taken longer.

Nothing too crazy here, all the hard work has already been done by ImageMagick and avconv.  But it's fun, and I should probably turn the compost : )

1 comment:

  1. Josh, i'm the publisher of ARES Magazine (Brazil). We'd like to talk about your project. Is that possible? Please: adriano@grappa.com.br The magazine: https://revistaares.com.br/english/

    ReplyDelete