Graphics-HotMap
view release on metacpan or search on metacpan
lib/Graphics/HotMap.pm view on Meta::CPAN
zoneC => {
layerName => '40_anotherLayer',
coordonates => [2,10,3,12],
border => 1,
text => 'green',
textSize => 8,
textColor => 'white',
},
zoneD => {
layerName => '40_anotherLayer',
coordonates => [3,10,4,12],
border => 1,
text => 'cyan',
textSize => 8,
textColor => 'white',
},
},
points => {
'30_anotherLayer' => [
[8,5,46],
[10,9,22],
],
'10_back' => [
[13,1,50],
],
'40_anotherLayer' => [
[0,10,1],
[1,10,2],
[2,10,3],
[3,10,4],
],
},
);
# ..., and import/add it
$hotMap->addConfs(\%other);
# Run the interpolation and generate and image
$hotMap->genImage;
# Save the image a a PNG file
$hotMap->genImagePng('MyTest.png');
# print the text representation of the map
print $hotMap->toString('floor') if $hotMap->scale < 3;
=head1 DESCRIPTION
Generate thermographic images from a few know points. Others values are interpolated. Graphics::HotMap use PDL to work on matrix.
PDL can compute very very large matrix in a few seconds.
See L<http://kumy.org/HotMap/HotMap.png>
=head2 FUNCTIONS
=over 4
=cut
use Data::Dumper;
use Image::Magick;
use Math::Gradient qw(multi_array_gradient);
use PDL;
use PDL::NiceSlice;
use PDL::IO::Pic;
use POSIX qw(strftime);
use File::Temp qw/ :POSIX /;
use File::Temp qw/ tempfile tempdir /;
use constant {
PALETTE_SLICE => 35,
};
our $VERSION = '0.0001';
=item new(<HASH>)
=for ref
Construct and return a new HotMap Object;
=for usage
Graphics::HotMap->new(
outfileGif => <File path>, # file to write GIF
outfilePng => <File path>, # file to write PNG
legend => [0|1], # activate lengend
legendNbGrad => <number>, # Number a graduation
cross => <bool>, # activate crossing of known values
crossValues => <bool>, # activate values printing whith cross
minValue => <number>, # minimum value
maxValue => <number>, # maximum value
font => <path to font file>,
fontSize => <number>, # font size
scale => <number>, # scale values and coordonates
sizeX => <number>, # X size
sizeY => <number>, # Y size
);
=for exemple
my $hotMap = Graphics::HotMap->new(
sizeX => 10,
sizeY => 10,
minValue => 1,
maxvalue => 50,
);
=cut
sub new {
my ($class, %params) = (@_);
my $self={};
$self->{_outfileGif} = $params{outfileGif} || undef;
$self->{_outfilePng} = $params{outfilePng} || undef;
$self->{_legend} = $params{legend} || 0;
$self->{_legendNbGrad} = $params{legendNbGrad} || 7;
$self->{_crossMark} = $params{cross} || 0;
$self->{_crossMarkTemp}= $params{crossTemp} || 0;
#$self->{_minValue} = $params{minValue} || 0;
lib/Graphics/HotMap.pm view on Meta::CPAN
foreach my $layer (sort keys %{$self->{_knownPoints}}) {
my ($d0,$d1) = whichND $self->{_knownPoints}{$layer};
my $nbValues = nelem($d0);
for (0..$nbValues-1) {
next unless (
defined $self->{_layers}{$layer}{visibility} &&
$self->{_layers}{$layer}{visibility}
);
$self->_drawMark(
$im,
$d0(($_)),
$d1(($_)),
$self->{_knownPoints}{$layer}->at($d0(($_)),$d1(($_))),
$self->{_gradient}{$self->{_layers}{$layer}{gradientName}}{unit}
);
}
}
}
=for comment
Internal function for writing timestamp on the image
=cut
sub _drawTime {
my $self = shift;
my $im = shift;
my ($time, $x, $y) = @{$self->{_horodatage}};
return unless $time;
$self->addText ( {
x => $x,
y => $y,
text => strftime ("%d-%m-%Y %H:%M:%S", localtime $time),
} );
}
=for comment
generate text on the image
=cut
sub _genText {
my $self = shift;
my ($im) = @_;
foreach my $text (@{$self->{_text}}) {
$self->_printText($im, $text);
}
}
=for comment
generate the image from the interpolated map.
=cut
sub _genPicture {
my $self = shift;
my $image = $self->{_im} = new Image::Magick();
# write a temporary image of the piddle
my $imag = byte $self->{_mapPoints};
my $tmpName = tmpnam().'.png';
#eval { $self->{_hotMap}->genImage };
#print STDERR "error: _genTemperatureImage: $@" if $@;
my $cptLoop = 0;
do {
eval {$imag->wpic($tmpName, { LUT => $self->{_gradient}{colors} }); };
++$cptLoop;
} while ($@ && $cptLoop < 10);
if ($cptLoop > 2) {
print "ARgh ! Function: _genPicture; nbErr for wpic:$cptLoop\n";
exit;
}
# read the temporary File in PerlMagick
my $status = $image->ReadImage($tmpName);
warn $status if $status;
unlink $tmpName;
# Flip the image
my $im = $image;
#my $im = $image->[0];
$im->Flip;
# Gen CrossMarks
$self->_genCrossMark($im) if $self->{_crossMark};
# Draw time on image
$self->_drawTime($im) if $self->{_horodatage}[0];
# Draw texts
$self->_genText($im);
# Gen legend in piddle
$self->_genLegende($im) if $self->{_legend};
}
=for comment
Really compute the interpolation from known points.
=cut
sub _pdlDegrad {
my $self = shift;
my ($input, $output, $sliceColors, $gradientName) = @_;
my ($d0,$d1) = whichND $input;
my $nbValues = nelem($d0);
my $norm = pdl->zeroes($input->dims);
$output .= 0;
my $t0r2;
my $t0r2inv;
if ($nbValues > 1) {
for (0..$nbValues-1) {
my $indice = $_;
$t0r2 = $input->rvals({ center=>[$d0($indice), $d1($indice)], squared=>1 } );
$t0r2->where($t0r2==0) .= -1;
lib/Graphics/HotMap.pm view on Meta::CPAN
$self->_genPicture;
}
=for comment
This function will write image to disk.
=cut
sub _saveImg {
my $self = shift;
my ($outfile, $im) = @_;
print $im->Write(filename=>$outfile); #, compression=>'JPEG', type => 'Palette');
}
=item genImagePng()
=for ref
Write a PNG image from the interpolated table.
=for exemple
$hotMap->genImagePng('<path_to_png'>);
=cut
sub genImagePng {
my $self = shift;
my $fileName = shift || $self->{_outfilePng} || die "No output PNG specified";
$self->_saveImg($fileName,$self->{_im});
return {
width => $self->{_im}->Get('width'),
height => $self->{_im}->Get('height'),
filesize => $self->{_im}->Get('filesize'),
mime => $self->{_im}->Get('mime'),
image => $self->{_im},
};
}
=item genImageGif()
=for ref
Add a GIF image to the annimation from the interpolated table.
=for exemple
$hotMap->genImageGif('<path_to_gif'>);
=cut
sub genImageGif {
my $self = shift;
my $fileName = shift || $self->{_outfileGif} || die "No output GIF specified";
my $image = shift;
my $im = $self->{_im};
unless (defined $image) {
$image = new Image::Magick(size => "$self->{_mapSize}{x}x$self->{_mapSize}{y}");
$image->Read($fileName);
}
$image->Set(magick=>'GIF', loop=> 100);
$im->Set(magick=>'GIF', delay=>100);
push (@$image, $im);
$self->_saveImg($fileName, $image);
return {
width => $image->Get('width'),
height => $image->Get('height'),
filesize => $image->Get('filesize'),
mime => $image->Get('mime'),
image => $image,
};
}
=back
=head1 SEE ALSO
PDL
Math::Gradient
=head1 AUTHOR
Mathieu Alorent (cpan@kumy.net)
=cut
1;
( run in 2.018 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )