Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Webcam Auto-Screensaver

by ailivac (Sexton)
on Sep 17, 2006 at 21:14 UTC ( [id://573441]=CUFP: print w/replies, xml ) Need Help??

This core of this program takes an set of three images, two references and one test, and classifies the test image as more similar to reference A or reference B. It then uses a loop to poll for new images (from an HTTP server) in real time and run commands when the images changes between the two states. A fun application of this is to monitor a webcam and turn the screensaver on and off depending on whether or not you're sitting in front of your computer. First, a module to summarize an image. This samples pixels at regular intervals and stores the values in an array or arrays:
# ImgSum.pm package ImgSum; use strict; use warnings; use Image::Magick; sub summary { my ($imgf, $res) = @_; my $img = new Image::Magick; $img->Read($imgf); my ($w, $h) = $img->Get(qw/rows columns/); my @sum; my $i = 0; for (my $y = 0; $y < $h; $y += $res) { for (my $x = 0; $x < $w; $x += $res) { my $px = $img->Get("pixel[$x,$y]"); my $rgb = [split/,/, $px]; $sum[$i++] = $rgb; } } return \@sum; } 1;
Next, a script to summarize an image file and store it for later use:
#!/usr/bin/perl # sum.pl use strict; use warnings; use ImgSum; use Data::Dumper; use Storable; my ($img, $res, $out) = @ARGV; # $res is the sampling resolution my $sum = ImgSum::summary($img, $res); store($sum, $out);
The next module takes two image summaries and calculates the average difference between them. It's an incredibly simple algorithm that has numerous shortcomings, but it works in simple situations.
# SumDif.pm package SumDiff; use strict; use warnings; use Data::Dumper; sub mean { my $tt = 0; my $s = 0; while (defined($_ = shift)) { $tt += $_; $s++; } return $tt/$s; } sub diffmap { my ($s1, $s2) = @_; my @diff; foreach my $i(0..$#$s1) { my $c1 = $s1->[$i]; my $c2 = $s2->[$i]; my @d = map { abs($c2->[$_] - $c1->[$_]) } (0..$#$c1); $diff[$i] = mean(@d); } return \@diff; } sub diffavg { return mean(@{diffmap(@_)}); } 1;
Finally, watch.pl downloads images and compares them with two references and runs a command whenever the current image changes from being more like one reference to being more like the other. You can use a program like spook to serve images captured from a webcam.
#!/usr/bin/perl # watch.pl use strict; use warnings; use ImgSum; use LWP::Simple; use SumDiff; use Storable; my @refs = map {retrieve($_)} ('sum-r0.dat', 'sum-r1.dat'); sub min { my $mni = 0; for my $i(0..$#_) { if ($_[$i] < $_[$mni]) { $mni = $i } } return $mni; } sub getclass { my $test = shift; my @diffs; for my $i(0..$#refs) { my $diff = SumDiff::diffavg($refs[$i], $test); $diffs[$i] = $diff; print "Difference to $i: $diff\n"; } return min(@diffs); } my $lc = 1; while (sleep 2) { my $stat = getstore('http://localhost:45005/webcam.jpg', 'current. +jpg'); print "HTTP status: $stat\n"; my $sum = ImgSum::summary('current.jpg', 4); my $cl = getclass($sum); print "Likely class: $cl\n"; if ($lc != $cl) { system('xscreensaver-command ' . ($cl?'-deactivate':'-activate')); $lc = $cl; } }
To use it:
( take a picture of the empty room, save it as ref0.jpg ) $ ./sum.pl ref0.jpg 4 sum-r0.dat ( take a picture of yourself, call it ref1.jpg ) $ ./sum.pl ref1.jpg 4 sum-r1.dat $ ./watch.pl
Now walk in front of and away from the camera slowly and your screensaver will turn on and off.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://573441]
Approved by chargrill
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (7)
As of 2024-04-18 14:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found