| WebService-Kaolabo documentation | Contained in the WebService-Kaolabo distribution. |
WebService::Kaolabo - This module call Kaolabo API (http://kaolabo.com/).
use WebService::Kaolabo;
$kaolab = WebService::Kaolabo->new({
target_file => 'sample.jpg',
apikey => 'hogefuga'
});
unless ( $kaolab->scale( xpixels => 50, ypixels => 50, type => 'max') ) {
warn "Failed scale $WebService::Kaolabo::errstr";
}
my $res = $kaolab->access();
if ( $res->is_success ) {
warn "Success ";
}
#$kaolab->unface_area();
for my $k ( @{$kaolab->face_area()} ){
$k->{area_number}
$k->{min_x};
$k->{min_y};
$k->{max_x};
$k->{max_y};
$k->{point};
}
my $face_data = $kaolab->face_data;
for my $f ( @{$face_data} ){
$f->{face_x};
$f->{face_y};
$f->{height};
$f->{width};
$f->{right_eye_y};
$f->{left_eye_y};
}
$kaolab->effect_face({type=>'box', color=>'#FF0000'});
$kaolab->write('output.jpg');
#my $imager = $kaolab->imager;
#$imager->write(type=>'jpeg', file=>'output.jpg');
The image file and api_key are passed. And Create new instance. The image should be JPEG.
Call The Kaolab API . The return value is a response object. See HTTP::Response.
Call Imager scale method. See scale in Imager::Transformations.
This method draws the line or box on the face.
The line is drawn on eyes.
$kaolab->effect_face({type=>'line', color=>'#FF0000'});
The box is drawn on faces.
$kaolab->effect_face({type=>'box', color=>'#FF0000'});
Write an image to a file.
The Imager instance is returned.
The image file is delimited to nine areas. Return face area.
Return no face area.
Return average width of all faces.
Return average height of all faces.
Error message.
warn "$WebService::Kaolabo::errstr";
Kaolab API http://kaolabo.com/webapi Kaolab http://kaolabo.com/
Akihito Takeda <takeda.akihito@gmail.com>
Copyright (c) 2008, Akihito Takeda <takeda.akihito@gmail.com>. All rights reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.
| WebService-Kaolabo documentation | Contained in the WebService-Kaolabo distribution. |
package WebService::Kaolabo; use warnings; use strict; use Carp; use version; our $VERSION = qv('0.0.3'); use LWP::UserAgent; use HTTP::Request; use Data::Average; use Imager; use File::Spec; our $errstr; use base qw(Class::Accessor); __PACKAGE__->mk_accessors( qw( socks_proxy proxy target_file convert_file uri apikey imager request_content response_xml face_data area face_area unface_area ave_face_width ave_face_height error)); sub new { my $self = shift->SUPER::new(@_); my $target_file = $self->target_file; $self->uri('https://kaolabo.com/api/detect?apikey=') unless ( $self->uri ); my $imager = Imager->new; if ( $target_file && $target_file !~ /(jpg|jpeg)$/ ) { $errstr = 'Target file is not jpeg'; return; } unless ( $imager->read( file => $target_file ) ) { $errstr = 'Cannot read target file ' . $imager->errstr(); return; } $self->area([]); $self->face_area([]); $self->unface_area([]); $self->imager($imager); $self; } sub scale { my $self = shift; my $imager = $self->imager; unless ( $imager ) { $errstr = 'Not found Imager object'; return; } unless ( @_ ) { $errstr = 'Not found scale param'; return; } my $imager_s = $imager->scale(@_); $self->imager($imager_s); return $imager_s; } sub write { my $self = shift; my $convert_file = shift; $convert_file ||= $self->convert_file; my $imager = $self->imager; $imager->write( file => $convert_file, jpegquality => 100 ) or die $imager->errstr; return; } sub access { my $self = shift; if ( $self->socks_proxy ) { if ( eval { require LWP::Protocol::https::SocksChain } ) { LWP::Protocol::implementor( https => 'LWP::Protocol::https::SocksChain' ); @LWP::Protocol::https::SocksChain::EXTRA_SOCK_OPTS = ( Chain_Len => 1, Debug => 0, Chain_File_Data => $self->socks_proxy, Random_Chain => 1, Auto_Save => 1, Restore_Type => 1 ); } } my $uri = $self->uri . $self->apikey; my $request_content; my $imager = $self->imager; $imager->write( type => 'jpeg', data => \$request_content ); my $request = HTTP::Request->new( 'POST' => $uri ); $request->header( 'Content-Type' => 'image/jpeg' ); $request->content($request_content) if ( $request_content ); my $ua = LWP::UserAgent->new; $ua->proxy( [ 'http', 'ftp' ], $self->proxy ) if ( $self->proxy ); my $response = $ua->request($request); unless ( $response->is_success ) { $errstr = 'Failed access ' . $response->status_line; } else { $self->response_xml( $response->content ); $self->_parser(); $self->_area_score(); } return $response; } sub _parser { my $self = shift; my $content = $self->response_xml(); my $face_data = []; my $ave_width = Data::Average->new; my $ave_height = Data::Average->new; while ( $content =~ s/<face(.+?)<\/face// ) { my $node = $1; my ( $height, $score, $width, $face_x, $face_y, $left_eye_x, $left_eye_y, $right_eye_x, $right_eye_y) = ( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); ( $height, $score, $width, $face_x, $face_y ) = ( $1, $2, $3, $4, $5 ) if ( $node =~ /height="(\d+)" score="(\d+)" width="(\d+)" x="(\d+)" y="(\d+)"/ ); ( $left_eye_x, $left_eye_y ) = ( $1, $2 ) if ( $node =~ /left\-eye x="(\d+)" y="(\d+)"/i ); ( $right_eye_x, $right_eye_y ) = ( $1, $2 ) if ( $node =~ /right\-eye x="(\d+)" y="(\d+)"/i ); my $center_x = $width / 2 + $face_x; my $center_y = $height / 2 + $face_y; # Maybe API bugs ?? if ( $left_eye_x == $right_eye_x ) { $right_eye_y = $right_eye_y<$left_eye_y?$right_eye_y:$left_eye_y; $left_eye_y = $right_eye_y<$left_eye_y?$right_eye_y:$left_eye_y; } $ave_width->add($width); $ave_height->add($height); push @{$face_data}, { height => $height, score => $score, width => $width, face_x => $face_x, face_y => $face_y, left_eye_x => $left_eye_x, left_eye_y => $left_eye_y, right_eye_x => $right_eye_x, right_eye_y => $right_eye_y, # left_eye_x => $left_eye_x, # left_eye_y => $left_eye_y, # right_eye_x => $right_eye_x, # right_eye_y => $right_eye_y, center_x => $center_x, center_y => $center_y, }; } $self->ave_face_width( $ave_width->avg ); $self->ave_face_height( $ave_height->avg ); $self->face_data($face_data); return; } sub _area_score { my $self = shift; my $w = $self->imager->getwidth(); my $h = $self->imager->getheight(); my $ddx = $w / 3; my $ddy = $h / 3; my @area; my $area_number = 0; for my $i ( 1 .. 3 ) { $area_number++; push @area, { area_number => $area_number, min_x => $ddx * ( $i - 1 ), min_y => 0, max_x => $ddx * $i, max_y => $ddy, point => 0 }; } for my $i ( 1 .. 3 ) { $area_number++; push @area, { area_number => $area_number, min_x => $ddx * ( $i - 1 ), min_y => $ddy, max_x => $ddx * $i, max_y => $ddy * 2, point => 0 }; } for my $i ( 1 .. 3 ) { $area_number++; push @area, { area_number => $area_number, min_x => $ddx * ( $i - 1 ), min_y => $ddy * 2, max_x => $ddx * $i, max_y => $ddy * 3, point => 0 }; } my $face_data = $self->face_data(); for my $f ( @{$face_data} ) { for my $a (@area) { if ( $a->{max_x} > $f->{center_x} && $a->{max_y} > $f->{center_y} ) { $a->{point}++; last; } } } $self->area( \@area ); my @unface_area = grep( { $_->{point} == 0 } @area ); $self->unface_area( \@unface_area ); my @face_area = grep( { $_->{point} != 0 } @area ); $self->face_area( \@face_area ); return; } sub effect_face { my $self = shift; my $args = shift; my $effect = $args->{type} || 'line'; my $color = $args->{color} || '#000000'; my $imager = $self->imager; my $face_data = $self->face_data || []; for my $f ( @{$face_data} ) { $imager->box( xmin => $f->{face_x}, ymin => $f->{face_y}, xmax => $f->{face_x} + $f->{width}, ymax => $f->{face_y} + $f->{height}, color => $color, filled => 1, ) if ( $effect eq "box" ); my $border_h = $f->{height} * 0.1; my $ymin = 0; my $ymax = 0; my $i = abs( $f->{right_eye_y} - $f->{left_eye_y} ); if ( $f->{left_eye_y} < $f->{right_eye_y} ) { $ymin = $f->{left_eye_y} - $border_h; $ymax = $f->{right_eye_y} + $border_h; } else { $ymin = $f->{right_eye_y} - $border_h; $ymax = $f->{left_eye_y} + $border_h; } $imager->box( xmin => $f->{face_x}, ymin => $ymin, xmax => $f->{face_x} + $f->{width}, ymax => $ymax, color => $color, filled => 1, ) if ( $effect eq "line" ); } return; } 1; __END__