Vous êtes sur la page 1sur 9

#############################################################################

#
#
#
TCS230/TCS3200/ColorPAL Color Match Software
#
#
(C) Copyright 2006, 2009 Bueno Systems, Inc.
#
#
Contact: propeller@phipi.com
#
#
#
# This program is free software; you can redistribute it and/or modify
#
# it under the terms of the GNU General Public License as published by
#
# the Free Software Foundation; either version 2 of the License, or
#
# (at your option) any later version.
#
#
#
# This program is distributed in the hope that it will be useful,
#
# but WITHOUT ANY WARRANTY; without even the implied warranty of
#
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#
# GNU General Public License for more details.
#
#
#
# You should have received a copy of the GNU General Public License
#
# along with this program; if not, write to the Free Software
#
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
#
#
#############################################################################
use
use
use
use
use
use
use
use
use
use
use

Win32::SerialPort qw(:STAT);
Win32::Registry;
Tk;
Tk::Canvas;
Tk::Photo;
Tk::Scale;
Tk::Table;
Tk::DialogBox;
Tk::ROText;
Tk::ToggleButton;
File::Basename;

require
require
require
require
require
require
require
require
require
$CMD_OFF
$CMD_RAW
$CMD_BAL
$CMD_PUT
$CMD_GET

Win32::API;
"utf8_heavy.pl";
"unicore/lib/SpacePer.pl";
"unicore/To/Lower.pl";
"unicore/To/Upper.pl";
"unicore/To/Fold.pl";
"unicore/lib/Digit.pl";
"unicore/lib/Word.pl";
"Encode/Unicode.pm";
=
=
=
=
=

chr(0x40);
chr(0x41);
chr(0x42);
chr(0x43);
chr(0x44);

$DLE = chr(0x10);
my $Registry;
$::HKEY_LOCAL_MACHINE->Open("HARDWARE\\DEVICEMAP\\SERIALCOMM", $Registry) or die
"Can't open data: $^E";
my @PortNames = ();
@RGB = ('#ff0000', '#00ff00', '#0000ff');
@CurrentBlack = (0, 0, 0);

$mw = Tk::MainWindow->new(-title => 'TCS3200/TCS230/ColorPAL Color Match v2.02')


;
$fraTop = $mw->Frame->pack(-side => 'top');
$fraSwatchPanel = $fraTop->Frame(
#
-background => LIGHTGRAY,
-height => 256,
-width => 128,
)->pack(-side => 'left');
$txtMsg = $fraSwatchPanel->Label(
-background => BLACK,
-foreground => YELLOW,
-textvariable => \$Message,
-relief => 'sunken',
-borderwidth => 2
)->pack(-side => 'top', -expand => 1, -fill => 'x', -padx => 2, -pady => 2);
$fraWB = $fraSwatchPanel->Frame()->pack(-side => 'top');
foreach (0..1) {
$btnWB[$_] = $fraWB->ToggleButton(
-width => 10,
-text => $_ ? 'Balanced' : 'Raw',
-ontrigger => 'press',
-latching => 1,
-togglegroup => \@btnWB,
-onbackground => CYAN,
-onaltbackground => YELLOW,
-onaltforeground => RED,
-command => \&PressWB,
-index => $_
)->pack(-side => 'left');
}
$fraWB = $fraSwatchPanel->Frame()->pack(-side => 'top');
$fraWB->ToggleButton(
-offforeground => 'WHITE',
-offbackground => '#999999',
-width => 10,
-text => 'Set White',
-command => \&DoWhiteBalance
)->pack(-side => 'left', -pady => 2);
$fraWB->ToggleButton(
-offforeground => 'BLACK',
-offbackground => '#999999',
-width => 10,
-text => 'Set Black',
-command => \&DoBlackBalance
)->pack(-side => 'left', -pady => 2);
$canBars = $fraSwatchPanel->Canvas(
-background => BLACK,
-width => 124,
-height => 54,
-relief => 'sunken',
-borderwidth => 2

)->pack(-side => 'top', -pady => 2);


foreach (0..2) {
$canBar[$_] = $canBars->createRectangle(
0, $_ * 18 + 4, -128, $_ * 18 + 21,
-fill => $RGB[$_]
);
$txtBar[$_] = $canBars->createText(
65,$_ * 18 + 13,
-text => '',
-font => 'Arial 11 bold',
-fill => WHITE,
-justify => 'right'
)
}
$fraSwatch = $fraSwatchPanel->Frame(
-background => BLACK,
-height => 40,
-width => 128,
-relief => 'sunken',
-borderwidth => 2,
)->pack(-side => 'top');
$fraSwatchPanel->Scale(
-orient => 'horizontal',
-label => 'Gamma Correction',
-length => 128,
-width => 15,
-sliderlength => 15,
-from => 1,
-to => 100,
-troughcolor => BLACK,
-variable => \$CurrentGamma,
-command => \&SetGamma
)->pack(-side => 'top');
$CurrentGamma = 35;
$fraSwatchPanel->Label(
-text => "Copyright 2002, 2009\nBueno Systems, Inc.",
)->pack;
$fraButtons = $fraTop->Frame(
-width => 260,
-height => 260
)->pack(-side => 'left');
foreach my $y (0..9) {
foreach my $x (0..9) {
my $i = $y * 10 + $x;
$lblColor[$i] = $fraButtons->Label(
-takefocus => 1,
-relief => 'raised',
-borderwidth => 1,
-text => $i,
)->place(-x => $x * 26, -y => $y * 26, -width => 26, -height =>
26);
$lblColor[$i]->bind('<Button-1>' => eval("sub {DefineColor($i, "
.'@CurrentRGB)}'));

$lblColor[$i]->bind('<Button-3>' => eval("sub {UndefineColor($i)


}"));
}
}
$fraBot = $mw->Frame->pack(-side => 'top');
$canDist = $fraBot->Canvas(
-background => BLACK,
-height => 210,
-width => 390
)->pack;
foreach (0..99) {
$txtDist[$_] = $canDist->createText(
500, 0,
-text => $_,
-fill => WHITE,
-font => 'Arial 7 bold',
-justify => 'right'
)
}
$mw->update;
OpenPort();
$Message = '';
$UpdateID = $mw->repeat(50, \&Update);
$mw->repeat(250, \&FlashSelected);
$btnWB[0]->TurnOn;
MainLoop();
sub OpenPort {
my %coms;
$Registry->GetValues(\%coms);
@PortNames = grep {m/^COM\d+$/} (map {$coms{$_}->[2]} keys %coms);
foreach my $dev ((@PortNames) x 2, undef) {
unless (defined $dev) {
$mw->messageBox(
-title => 'Serial I/O Error',
-message => 'Unable to locate color sensor outpu
t on any serial port.',
-type => 'OK'
);
exit
}
$Message = "Scanning $dev.";
$txtMsg->update;
unless ($Port = new Win32::SerialPort("\\\\.\\$dev")
and $Port->baudrate(9600)
and $Port->parity('none')
and $Port->databits(8)
and $Port->stopbits(2)
and $Port->buffers(4096,4096)
and $Port->binary(1)
and $Port->write_settings)
{
next

}
Win32::Sleep 1000;
my (undef, $n, undef, $err) = ($Port->status);
if ($err) {
$Port->reset_error;
}
if ($n) {
my $stream = $Port->input;
last if $stream =~ m/R\d+ G\d+ B\d+\r/
}
$Port->close
}
return
}
sub Update {
my $nxt;
$Port->error_msg(1);
my (undef, $n, undef, $err) = ($Port->status);
if ($err) {
$Port->reset_error;
}
if ($n) {
$QuiteTimes = 0;
$stream .= $Port->input;
while ($stream =~ m/(R\d+ G\d+ B\d+)\r/osg) {
$lastRGB = $1;
$nxt = pos($stream);
}
$stream = substr($stream, $nxt) if defined $nxt;
if ($lastRGB && defined $WBMode) {
@color = ($lastRGB =~ m/R(\d+) G(\d+) B(\d+)/);
@CurrentRaw = @color;
if ($WBMode eq $CMD_BAL && defined @CurrentWhite && defi
ned @CurrentBlack) {
@CurrentRGB = map {int(($CurrentRaw[$_] - $Curre
ntBlack[$_]) * 255 / ($CurrentWhite[$_] - $CurrentBlack[$_]))} (0 .. 2)
} else {
@CurrentRGB = @CurrentRaw
}
my $status = grep {$_ > 255} @CurrentRGB;
$Message = $status ? 'Saturated' : '';
foreach my $i (0..2) {
$canBars->itemconfigure($txtBar[$i], -text => $C
urrentRGB[$i]);
$canBars->coords($canBar[$i], 0, $i * 18 + 4, $C
urrentRGB[$i] / 2, $i * 18 + 21)
}
@CurrentRGB = map {$_ > 255 ? 255 : $_} @CurrentRGB;
$fraSwatch->configure(-background => ScreenColor(@Curren
tRGB));
&BestMatch
}
} else {
PutMsg($WBMode) if $QuiteTimes++ > 30
}
}
sub PutMsg {
PutCmd(shift);

map {PutDat(chr($_))} @_;


}
sub PutCmd {
$Port->write($DLE.$_[0]);
}
sub PutDat {
my $parm = $_[0];
if ($parm eq $DLE) {
$Port->write($DLE.$DLE);
} else {
$Port->write($parm);
}
}
sub SetGamma {
foreach (grep defined, @DefinedColor) {
my ($n, @rgb) = @$_;
$lblColor[$n]->configure(-background => ScreenColor(@rgb))
}
}
sub ScreenColor {
my @rgb = GammaCorrect(@_);
do {$rgb[$_] = 0 if $rgb[$_] < 0} foreach (0 .. 2);
return sprintf('#%2.2X%2.2X%2.2X', @rgb)
}
sub GammaCorrect {
my $max = (sort {$b <=> $a} @_)[0];
my $gammaf = ($max / 255) ** ($CurrentGamma / 100) * 255 / ($max or 1);
return map {$gammaf * $_} @_
}
sub RGBtoYCC {
my @rgb = map {$_ / 255} @_;
my ($r, $g, $b) = @rgb;
my $y = 0.299 * $r + 0.587 * $g + 0.114 * $b;
my $c1 = $b - $y;
my $c2 = $r - $y;
$y = int(255 * $y);
$c1 = int(111.40 * $c1) + 156;
$c2 = int(135.64 * $c2) + 137;
return ($y, $c1, $c2)
}
sub RGBtoYUV {
my @rgb = @_;
my ($r, $g, $b) = @_;
my $y = int(0.299 * $r + 0.587 * $g + 0.144 * $b);
my $u = int(0.492 * ($b - $y) * 128 / 112 + 128);
my $v = int(0.877 * ($r - $y) * 128 / 157 + 128);
return ($y, $u, $v)
}
sub DefineColor {
if ($WBMode eq $CMD_RAW) {
$mw->messageBox(-message => "Can't assign a raw color. Use 'Bala
nced' mode.", -type => 'ok')

} else {
my $no = shift;
my @rgb = @_;
$lblColor[$no]->configure(
-relief => 'sunken',
-background => ScreenColor(@rgb),
);
$DefinedColor[$no] = [$no, @rgb];
&BestMatch
}
}
sub UndefineColor {
my $no = shift;
$lblColor[$no]->configure(-relief => 'raised', -background => GRAY);
$canDist->coords($txtDist[$no], 500,0);
undef $DefinedColor[$no];
&BestMatch;
}
sub FlashSelected {
if (defined $PrevSelected) {
$lblColor[$PrevSelected]->configure(-foreground => BLACK);
}
if (defined $Selected) {
$lblColor[$Selected]->configure(-foreground => $Flash ? BLACK :
YELLOW);
$Flash = not $Flash;
}
$PrevSelected = $Selected
}
sub BestMatch {
my $nBest;
my $distBest = 1e38;
my @Defined = grep defined, @DefinedColor;
foreach (@Defined) {
my ($n, @rgb) = @$_;
my $distMax = 0;
foreach my $i (0..2) {
$dist = abs($rgb[$i] - $CurrentRGB[$i]);
$distMax = $dist if $dist > $distMax
}
$canDist->coords($txtDist[$n], $distMax * 2 + 10, $n * 2 + 10);
if ($distMax < $distBest) {$nBest = $n; $distBest = $distMax}
}
return $Selected = $nBest
}
sub PressWB {
my ($on, $i) = @_;
if ($on) {
if ($i && !defined @CurrentWhite) {
$mw->messageBox(-message => '"White" is undefined. Set w
hite first.', -type => 'ok');
$btnWB[0]->TurnOn;
return
} elsif ($i && !defined @CurrentBlack) {
$mw->messageBox(-message => '"Black" is undefined. Set b
lack first.', -type => 'ok');

$btnWB[0]->TurnOn;
return
}
$WBMode = $i ? $CMD_BAL : $CMD_RAW
}
}
sub DoWhiteBalance {
@CurrentWhite = @CurrentRaw;
$btnWB[1]->TurnOn if defined @CurrentBlack
}
sub DoBlackBalance {
@CurrentBlack = @CurrentRaw;
$btnWB[1]->TurnOn if defined @CurrentWhite
}
sub StoreColors {
PutMsg($CMD_OFF);
$mw->afterCancel($UpdateID);
$Message = '';
$txtMsg->update;
foreach my $no (0..99) {
if (defined $DefinedColor[$no]) {
PutMsg($CMD_PUT, 0x80 + $no, @{$DefinedColor[$no]}[1..3]
);
} else {
PutMsg($CMD_PUT, $no, 0, 0, 0)
}
my $c;
do {
$c = $Port->input
} until $c =~ m/\x43/;
if ($no & 1) {
$Message .= '|';
$txtMsg->update
}
}
PutMsg($WBMode);
$UpdateID = $mw->repeat(50, \&Update);
#
$Message = ''
}
sub RetrieveColors {
PutMsg($CMD_OFF);
$mw->afterCancel($UpdateID);
$Message = '';
$txtMsg->update;
foreach my $no (0..99) {
PutMsg($CMD_GET, $no);
my $c = '';
do {
$c .= $Port->input
} until $c =~ m/\x10\x44(((\x10\x10)|[^\x10]){4})/;
$c = $1;
$c =~ s/\x10\x10/\x10/;
my ($def, @rgb) = map ord, split(//, $c);
if ($def & 0x80) {
DefineColor($no, @rgb);
} else {

UndefineColor($no)
}
if ($no & 1) {
$Message .= '|';
$txtMsg->update
}
}
PutMsg($WBMode);
$UpdateID = $mw->repeat(50, \&Update);
}

Vous aimerez peut-être aussi