package LCDOCR;
###########################################
# Mike Schilli, 2007 (m@perlmeister.com)
###########################################
use strict;
use Imager;
use Log::Log4perl qw(:easy);
use YAML qw(LoadFile);

###########################################
sub new {
###########################################
  my($class, %options) = @_;

  my $refd = LoadFile("/etc/fobs.yml")->
             {$options{name}};
  my $self = {
      name           => "RSA1",
      threshold      => 0.85,
      debug          => 0,
      digits         => $refd->{digits},
      %options,
  };
    # Adapt coordinates to real image
  my $stretch = ref_dist($self) /
                ref_dist($refd);
  for (qw(x_off y_off digit_width 
          digit_height digit_dist)) {     
      $self->{$_} = $refd->{$_} * $stretch;
  }

  $self->{angle} = atan2 (
    $self->{y2_ref}-$self->{y1_ref}, 
    $self->{x2_ref}-$self->{x1_ref});

  bless $self, $class;
}

###########################################
sub ref_dist {
###########################################
  my($h) = @_;
  return sqrt(
    ($h->{x2_ref} - $h->{x1_ref})**2 +
    ($h->{y2_ref} - $h->{y1_ref})**2)
}

###########################################
sub reco {
###########################################
  my($self) = @_;

  my @digits;
  my %seg_orient = qw(
          1 h 2 v 3 v 4 h 5 v 6 v 7 h);

  for (1..$self->{digits}) {
    my $coords    = $self->seg_coords($_);
    my $segstring = "";

    my $bkground = (
      xybrightness($self->{image},
                   @{$coords->{8}}) +
      xybrightness($self->{image},
                   @{$coords->{9}})
     ) / 2;

     for my $c (1..7) {
       my($x, $y) = @{$coords->{$c}};

       if(pixel_dark($self->{image}, $x, 
                     $y, $bkground,
                     $self->{debug}, $c, 
                     $seg_orient{$c}, 
                     $self->{threshold})) {
         $segstring .= "$c";
       }

       if($self->{debug}) {
         my $red = Imager::Color->new(
                                255, 0, 0);
         $self->{image}->circle(
          color=>$red, r=>1, x=>$x, y=>$y);
       }
     }

     my $digit = seg2digit($segstring);
     push @digits, 
          defined $digit ? $digit : "X";
    }

    return \@digits;
}

###########################################
sub seg_coords {
###########################################
  my($self, $digit) = @_;

  my $x = $self->{x_off} + 
        ($digit-1) * $self->{digit_dist};
  my $y = $self->{y_off};
  my $w = $self->{digit_width};
  my $h = $self->{digit_height};
  my $r = sub { [ $self->rotate(@_) ] };

  return {
    1 => $r->($x,        $y),
    2 => $r->($x + $w/2, $y + $h/4),
    3 => $r->($x + $w/2, $y + 3*$h/4),
    4 => $r->($x,        $y + $h),
    5 => $r->($x - $w/2, $y + 3*$h/4),
    6 => $r->($x - $w/2, $y + $h/4),
    7 => $r->($x,        $y + $h/2),
    # ref points
    8 => $r->($x,        $y + $h/4),
    9 => $r->($x,        $y + 3*$h/4),
  };
}

###########################################
sub seg2digit {
###########################################
  my %h = (
    "23"     => 1, "12457"   => 2,
    "12347"  => 3, "2367"    => 4,
    "13467"  => 5, "134567"  => 6,
    "123"    => 7, "1234567" => 8,
    "123467" => 9, "123456"  => 0,
    );
  return $h{$_[0]};
}

###########################################
sub rotate {
###########################################
    my($self, $xd, $yd) = @_;

    my $r  = sqrt($xd*$xd + $yd*$yd);

    my $phi = atan2($yd,$xd);
    $phi += $self->{angle};
    
    my $xd_rot = $r * cos($phi);
    my $yd_rot = $r * sin($phi); 
    my $x_abs  = $self->{x1_ref} + $xd_rot;
    my $y_abs  = $self->{y1_ref} + $yd_rot;

    return($x_abs, $y_abs);
}

use Inline C => <<'EOT' => WITH => 'Imager';

int pixel_dark(Imager im, int x, int y, 
               int threshold, int debug, 
               int seg, char *direction, 
               float percent) {
  i_color val;
  int br, i, j, dark=0, min=-1;
  int imin=0, imax=1, jmin=0, jmax=1;
  float rel;

  if(direction == 'h') {
      jmin = -1; jmax =  2;
  } else {
      imin = -1; imax =  2;
  }

  for(i=imin; i<imax; i++) {
      for(j=jmin; j<jmax; j++) {
          i_gpix(im, x+i, y+j, &val);
          br = brightness(&val);
          if(min == -1 || min > br)
              min = br;
      }
  }

  rel = 1.0*min/threshold;
  if(rel < percent)
    dark = 1;

  if(debug) {
    printf("TH[%d]: %d (%d %.1f%%: %d)\n", 
     seg, min, threshold, rel*100.0, dark);
  }
  return dark;
}

int brightness(i_color *val) {
    return((val->channel[0] + 
            val->channel[1] + 
            val->channel[2])/3);
}

int xybrightness(Imager im, int x, int y) {
    i_color val;
    i_gpix(im, x, y, &val);
    return brightness(&val);
}

EOT

1;
