
(j'en mettrais d'autres au fur et à mesure de leur arrivée)
Modérateurs : Carl, Papy.G, fneck
Code : Tout sélectionner
cd <dossier du script perl>
ln -s /usr/bin/ffmpeg.exe ./ffmpeg.exe
Code : Tout sélectionner
#/bin/perl
# Conversion video en gif 4 couls
#
# Samuel DEVULDER, Sept-Oct 2015.
#
# parametres
($W, $H) = (204, 153); # HR
$fps = 10;
$dither = "vac8";
($RED,$GRN,$BLU) = (2,4,1);
# fichier entree
$file = $ARGV[0];
$out = $file;
$out =~ s/\.[^\.]*$/.gif/;
exit if -e $out;
($x,$y, $aspect_ratio) = (160,100,"16:9");
open(IN, "./ffmpeg -i \"$file\" 2>&1 |");
while(<IN>) {
if(/, (\d+)x(\d+)/) {
($x,$y) = ($1, $2);
# 4:3
if(abs($x - 4/3*$y) < abs($x - 16/9*$y)) {
($w,$h,$aspect_ratio) = (133,100,"4:3");
}
}
}
close(IN);
$h = int(($w=$W)*$y/$x);
$w = int(($h=$H)*$x/$y) if $h>$H;
print $file," : ${x}x${y} ($aspect_ratio) -> ${w}x${h}\n";
# dossier temporaire
mkdir "tmp";
open(OUT,"| ./ffmpeg -i - -v 0 -r $fps -s ${w}x${h} -an tmp/img%05d.bmp");
open(IN, "<$file");
&init_magick;
$gif = Image::Magick->new(size=>"${w}x${h}");
$cpt = 1; my @c = (0)x8;
binmode(IN);
binmode(OUT);
while(1) {
$name = sprintf("tmp/img%05d.bmp", $cpt);
$expected_size = $h*(($w*3 + 3)&~3) + 54 if !$expected_size;
if($expected_size != -s $name) {
# image pas complete: on continue de nourrir ffmpeg
my $buf;
my $read = read(IN,$buf,4096);
last unless $read;
syswrite OUT, $buf, $read;
} else {
# image complete!
print STDERR int($cpt++/$fps),"s\r";
sleep(5) if ($cpt%1200)==0; # on fait une pause régulière pour ne pas surchauffer le processeur
# lecture de l'image
my $img = Image::Magick->new();
$img->Read($name);
unlink $name;
# on force la saturation (140%) pour avoir des couleurs plus franches
$img->Modulate(saturation=>140);
$img->Evaluate(operator=>'Multiply', value=>255/245);
my $tmp = Image::Magick->new(size=>"${W}x${H}");
$tmp->Read("xc:black");
$tmp->Composite(image=>$img, Operator=>"Over", x=>($W-$w)>>1, y=>($H-$h)>>1);
undef $img; $img = $tmp;
my $orig = $img->Clone();
# trammage
$img->Set(colorspace=>$LINEAR_SPACE);
$img->OrderedDither($dither);
if(0) {
# version R,G,B
$img=$img->Fx(expression=>"(i+j)%3==0?r:0", channel=>"Red");
$img=$img->Fx(expression=>"(i+j)%3==1?g:0", channel=>"Green");
$img=$img->Fx(expression=>"(i+j)%3==2?b:0", channel=>"Blue");
} else {
# détermination des 4 couleurs les plus fréquentes (histograme + passe-bas)
my $z = $orig;
if(!defined $gauss) {
$gauss = Image::Magick->new(size=>"${W}x${H}");
$gauss->Read("xc:black");
$gauss=$gauss->Fx(expression=>"exp(-8*(((i-$W/2)/$W)^2 + ((j-$H/2)/$H)^2))", channel=>"All");
$gauss->Write("gauss.png");
}
$z->Composite(image=>$gauss, Compose=>"Multiply", channel=>"All");
$z->Blur(sigma=>2);
$z->Set(colorspace=>$LINEAR_SPACE);
$z->OrderedDither($dither);
$z->Write("gauss.png");
my @h = $z->Histogram();
my @H = (0)x8;
for(my $i=$#h+1; ($i-=5)>=0;) {
$H[($h[$i]&$RED)|($h[$i+1]&$GRN)|($h[$i+2]&$BLU)] =
$h[$i+4];
}
my @sf;
for my $i (0..7) {
my $t = int($c[$i] = ($c[$i]*0 + 32*$H[$i])/32);
my $x = $t; $x |= $x>>1; $x |= $x>>2; $x |= $x>>4; $x |= $x>>8; $x |= $x>>16; ++$x;
my $y = $x>>4; $x -= $y?$y:1; $t &= $x;
$sf[$i]=$t*16 + ($i==0?8:$i);
}
@h = sort {$sf[$b]<=>$sf[$a]} (0..7);
# print "\n";
# for my $i (@h) {
# print $i, "=>", $sf[$i]>>4, " ",int($c[$i]), " (",$H[$i],")\n";
# }
# construction d'une palette avec ces 4 couleurs
my $k = join(',', @h[0..3]);
my $m = $pal{$k};
if(!defined $m) {
my(@px);
for my $c (@h[0..3]) {
push(@px, ($c&$RED)?255:0, ($c&$GRN)?255:0, ($c&$BLU)?255:0);
}
my $tmp = $ENV{'HOME'}."/.toto.pnm";
open(ZZ,">$tmp");
print ZZ "P6\n4 1\n255\n", pack('C*',@px),"\n";
close(ZZ);
$m = Image::Magick->new();
$m->Read($tmp);
unlink($tmp);
$pal{$k} = $m;
}
# remping de l'image tramée sur ces 4 couleurs
$img->Remap(image=>$m, 'dither-method'=>'none');
}
$img->Write("toto.png");
# ajout de l'image au gif animé
$img->Set(dispose=>"None");
$img->Set(delay=>int(100/$fps));
push(@$gif, $img);
# pas plus de 3600 imgs (6mins)
last if $cpt==4200;
}
}
close(OUT);
unlink(<$ENV{'HOME'}/img*.bmp>);
# ecriture du fichier gif
$gif->Set(dispose=>"None");
$gif->Set(Layers=>"optimize-trans");
$gif->Set(delay=>int(100/$fps));
$gif->Write($out);
sub init_magick {
# chargement image-magick la 1ere fois
my($home) = "tmp";
$ENV{'HOME'} = $home;
mkdir($home);
mkdir("$home/.magick");
open(THR, ">$home/.magick/thresholds.xml");
print THR <<EOF;
<thresholds>
<threshold map="2x2">
<description>2x2 dither matrix</description>
<levels width="2" height="2" divisor="5">
1 2
3 4
</levels>
</threshold>
<threshold map="3x3">
<description>3x3 dither matrix</description>
<levels width="3" height="3" divisor="10">
7 8 2
6 9 4
3 5 1
</levels>
</threshold>
<threshold map="5x3">
<description>5x3 dither matrix</description>
<levels width="3" height="5" divisor="16">
3 9 4
8 14 10
13 15 11
7 12 5
2 6 1
</levels>
</threshold>
<threshold map="vac8">
<description>void and cluster 65 niveaux</description>
<levels width="8" height="8" divisor="65">
35 57 19 55 7 51 4 21
29 6 41 27 37 17 59 45
61 15 53 12 62 25 33 9
23 39 31 49 2 47 13 43
3 52 8 22 36 58 20 56
38 18 60 46 30 5 42 28
63 26 34 11 64 16 54 10
14 48 1 44 24 40 32 50
</levels>
</threshold>
</thresholds>
EOF
close(THR);
eval 'use Image::Magick;';
# determination de l'espace RGB lineaire
my $img = Image::Magick->new(size=>"256x1", depth=>16);
$img->Read('gradient:black-white');
$img->Set(colorspace=>'RGB');
#$img->Set(colorspace=>"Gray") unless $coul;
my @px1 = $img->GetPixel(x=>128, y=>0);
$img->Read('gradient:black-white');
$img->Set(colorspace=>'sRGB');
#$img->Set(colorspace=>"Gray") unless $coul;
my @px2 = $img->GetPixel(x=>128, y=>0);
my $d1 = $px1[0]-0.5; $d1=-$d1 if $d1<0;
my $d2 = $px2[0]-0.5; $d2=-$d2 if $d2<0;
$LINEAR_SPACE = $d1>=$d2 ? "RGB" : "sRGB";
#print $px1[0], " ",$px2[0]," $LINEAR_SPACE\n";
}