game capture prototype
authorShiar <shiar@shiar.org>
Fri, 1 Feb 2008 03:35:18 +0000 (04:35 +0100)
committerShiar <shiar@shiar.org>
Thu, 7 Feb 2008 20:15:49 +0000 (21:15 +0100)
Parses game screenshots (either by display capture or reading image files).
Writes animated gif of minimap area, and tries to parse the game status
texts (player stats and replay time). Character parsing is done as a match
of total color value per pixel column (cannot distinguish between certain
digits), but at least it's a working setup.

capture [new file with mode: 0644]

diff --git a/capture b/capture
new file mode 100644 (file)
index 0000000..91304aa
--- /dev/null
+++ b/capture
@@ -0,0 +1,144 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+use Image::Magick;
+use constant {DEBUG => 0};
+
+our $VERSION = '1.00';
+
+my @digitchar = (0..9, ':', ' ');
+my @digittime = (
+       [744, 372, 372, 744], # 0
+       [186, 1116], # 1
+       [558, 558, 558, 558], # 2
+       [372, 372, 558, 558], # 3
+       [372, 372, 1116, 186], # 4
+       [558, 558, 558, -558], # 5
+       [744, 558, 558, 558], # 6
+       [255, 640, 1025, 895, 539], ## 7
+       [1020, 648, 510, 648, 1020], ## 8
+       [558, 558, 558, 744], # 9
+       [372], ## /
+       [], # -
+);
+my @digitgreen = (
+       [1344, 393, 255, 393, 1344], # 0
+       [255, 409, 1530], # 1
+       [863, 709, 664, 799, 648], # 2
+       [579, 393, 510, 648, 1089], # 3
+       [640, 709, 709, 1530, 255], # 4
+       [523, 895, 510, 770, 1150], # 5
+       [1344, 786, 648, 648, 1089], # 6
+       [255, 640, 1025, 895, 539], # 7
+       [1020, 648, 510, 648, 1020], # 8
+       [903, 648, 510, 648, 1344], # 9
+       [199, 887, 709], ## /
+
+#      [1344, 417, 263, 393, 1344, 32], # 0
+#      [255, 417, 1530, 40], # 1
+#      [863, 725, 680, 807, 656, 16], # 2
+#      [579, 401, 518, 656, 1089, 24], # 3
+#      [640, 717, 725, 1530, 287, 8], # 4
+#      [523, 903, 526, 778, 1158, 24], ## 5
+#      [1344, 786, 656, 656, 1097, 24], ## 6
+#      [255, 648, 1033, 911, 547, 8], # 7
+#      [1028, 656, 526, 664, 1028, 24], # 8
+#      [903, 656, 526, 656, 1344, 32], # 9
+#      [199, 887, 725, 16], ## /
+
+       [], # -
+);
+
+my %colorgreen = (
+#      8 => [8, 8],
+       69 => [0, 0],
+       130 => [8, 8],
+       154 => [33, 33],
+       255 => [16, 24],
+);
+
+sub getrect2 {
+       my ($digit, $valid, $data, $w, $h, $x1, $x2) = @_;
+
+       my ($str, @char);
+       my $count = -1;
+       for my $x ($x1 .. $x2) {
+               my $colval = 0;
+               for my $y (0 .. $h - 1) {
+                       my @val;
+                       push @val => $data->[($x + $y*$w) * 3 + $_] >> 8 for 0 .. 2;
+printf("  [%s]\n", join ', ', @val) if DEBUG >= 2;
+                       my $match = $valid->{$val[1]} or next;
+                       $val[0] == $match->[0] and $val[2] == $match->[1] or next;
+print "  ok\n" if DEBUG >= 2;
+                       $colval += $val[1];
+               }
+
+               if ($colval > 0 and ($count < 0 or $count++ < 6)) {
+                       push @char => $colval;
+               } elsif (@char) {
+printf " %d: [%s], # %d\n", $x, join(', ', @char), $count if DEBUG >= 1;
+                       my @matches;
+                       for my $match (@$digit) {
+                               if (scalar @$match == scalar @char) {
+                                       my $offset = 0;
+                                       $offset += abs $char[$_] - $match->[$_] for 0 .. $#char;
+                                       push @matches => $offset;
+                               } else {
+                                       push @matches => -1;
+                               }
+                       }
+                       undef @char;
+                       $count = 0;
+
+                       my $best;
+                       $matches[$_] == 0 and $best = $_ for 0 .. $#matches;
+                       if (not defined $best) {
+                               my @best;
+                               $matches[$_] > 0 and push @best, $_
+                                       for sort {$matches[$a] <=> $matches[$b]} 0 .. $#matches;
+printf "candidates: (%s)\n", join ', ', map {"$_ ($matches[$_])"} @best;
+                               $best = shift @best;
+                       }
+                       $str .= defined $best ? $best eq '' ? '' : $digitchar[$best] : '?';
+               }
+       }
+       return $str;
+}
+
+my $map = Image::Magick->new(128, 128);
+my $curtime = 0;
+
+for my $i ($ARGV[0] .. $ARGV[1]) {
+       my $image = Image::Magick->new;
+       my $err = $image->Read(sprintf 's%05d.png', $i);
+       $err and die $err;
+       my @pixels = $image->GetPixels(map=>'RGB', x=>452, width=>187, y=>6, height=>6);
+       my $min = getrect2(\@digitgreen, \%colorgreen, \@pixels, 187, 6, 0, 39);
+       my $gas = getrect2(\@digitgreen, \%colorgreen, \@pixels, 187, 6, 68, 107);
+       my $unit = getrect2(\@digitgreen, \%colorgreen, \@pixels, 187, 6, 136, 181);
+       my ($unitcur, $unitmax) = split /:/, $unit, 2;
+
+       @pixels = $image->GetPixels(map=>'RGB', x=>587, width=>34, y=>396, height=>6);
+       my $time = getrect2(\@digittime, {186 => [189, 239]}, \@pixels, 34, 6, 0, 33);
+       my $sec;
+       $time =~ /^(\d\d):(\d\d)$/ and $sec = $1*60 + $2;
+
+       printf "%d:\t%s\t%s\t%s\t%s\t%s\n", $i, $sec, $min, $gas, $unitcur, $unitmax;
+       $image->Crop(width=>128, height=>128, x=>6, y=>348);
+#      $image->Set(delay => $sec > $curtime ? ($sec - $curtime) / 5 : 10);
+       $image->Set(10);
+       push @$map => $image;
+       $curtime = $sec;
+}
+
+my $err = $map->Write('map.gif');
+$err and die $err;
+#print $map->Layers(method => 'optimize');
+
+print "\n";
+print "\n";
+