Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- use List::Util qw(min max sum);
- use strict;
- use GD;
- use POSIX;
- use Data::Dumper;
- use File::Temp;
- sub parse_report {
- my ($report) = @_;
- my @result = ();
- open INPUT,"<",$report;
- for my $line (<INPUT>) {
- if ($line =~ m/t:([0-9.]{3,}).*select_out:0/) {
- push(@result,$1);
- }
- }
- return @result;
- }
- sub image_names {
- my ($dir,$code) = @_;
- opendir(INPUT,$dir);
- my @images = map { $dir . "/" . $_ } sort { $a <=> $b } grep { /\.png$/ } readdir(INPUT);
- closedir(INPUT);
- return @images;
- }
- sub load_imagedata {
- my ($filename) = @_;
- my $image = GD::Image->new($filename);
- my ($width,$height) = $image->getBounds();
- my @imagedata = ();
- for (my $x=0;$x<$width;$x++) {
- for (my $y=0;$y<$height;$y++) {
- my ($r,$g,$b) = $image->rgb($image->getPixel($x,$y));
- push(@imagedata,$r);
- }
- }
- my $minv = min @imagedata;
- my $maxv = max @imagedata;
- my $maxv_minv = $maxv - $minv;
- if ($maxv != $minv) {
- @imagedata = map { ($_ - $minv)/$maxv_minv } @imagedata;
- } else {
- @imagedata = map { 0 } @imagedata;
- }
- return @imagedata;
- }
- sub imagedata_diff {
- my ($imagedata1_ref,$imagedata2_ref) = @_;
- #my @imagedata1 = @$imagedata1_ref;
- #my @imagedata2 = @$imagedata2_ref;
- my $len = min(scalar(@$imagedata1_ref),scalar(@$imagedata2_ref));
- my @diff = map { abs($imagedata1_ref->[$_] - $imagedata2_ref->[$_]) } (0..$len-1);
- return sum(@diff) / scalar(@diff);
- }
- sub display_imagedata {
- my ($q,$imagedata1_ref) = @_;
- my $qpow = pow(10,$q);
- my @rounded = map { floor($_*$qpow)/$qpow } @$imagedata1_ref;
- print join(' ',@rounded) . "\n";
- }
- sub find_best_match {
- my ($index1,$index2min,$index2max,$imagedata1_ref,$imagedata2_ref) = @_;
- my $match_diff = 0.1;
- my $match_image;
- for my $index2 ($index2min..$index2max){
- #print $index2;
- if (defined $imagedata2_ref->[$index2]) {
- my $diff = imagedata_diff($imagedata1_ref->[$index1],$imagedata2_ref->[$index2]);
- if ($diff < $match_diff ) {
- $match_diff = $diff;
- $match_image = $index2;
- }
- #print "diff: " . $diff;
- } else {
- #print $index2 . " undefined\n";
- }
- }
- if (defined $match_image) {
- return ($match_image,$match_diff);
- }
- return (-1,-1);
- }
- sub timehms {
- my ($s) = @_;
- my $h = floor($s/3600);
- $s-=$h*3600;
- my $m=floor($s/60); $s-=$m*60;
- return sprintf("%02d:%02d:%05.2f",$h,$m,$s);
- };
- sub output_comparsiontable {
- my ($filename, $comparsiontable_ref,$d1,$f1,$d2,$f2,$v1,$v2) = @_;
- open OUTPUT,">",$filename;
- print OUTPUT "<html><head><style>table {border-collapse: collapse;} table td {border: 1px solid black; text-align: right;}</style></head><body>";
- if (length($v1)>0) {
- print OUTPUT '<p>' . join('</p><p>',$v1,$v2) . '</p>';
- }
- print OUTPUT '<p>' . join('</p><p>',$f1,$d1,$f2,$d2) . "</p>\n";
- print OUTPUT "<table>\n";
- for my $ref (@$comparsiontable_ref) {
- my @outp = ();
- if ($ref->[1] > -1) {
- @outp = ($ref->[0],$ref->[1],timehms($ref->[2]),timehms($ref->[3]),sprintf("%.2f",$ref->[2]-$ref->[3]),$ref->[4],$ref->[5],$ref->[6],$ref->[7],sprintf("%.3f",$ref->[8]));
- } else {
- @outp = ($ref->[0],'?',timehms($ref->[2]),'?','?',$ref->[4],'?',$ref->[6],$ref->[7],'?');
- }
- print OUTPUT '<tr><td>' . join('</td><td>',@outp) . "</td></tr>\n"; # if (not($filtration && $ref->[1] < 0));
- }
- print OUTPUT "</table>\n";
- print OUTPUT "</body></html>";
- close OUTPUT;
- }
- sub median
- {
- my @vals = sort {$a <=> $b} @_;
- my $len = @vals;
- if($len%2)
- {
- return $vals[int($len/2)];
- }
- else
- {
- return ($vals[int($len/2)-1] + $vals[int($len/2)])/2;
- }
- }
- sub extract_frames {
- my ($filename,$dir,$report,$image_size) = @_;
- my $divider = 10;
- `export FFREPORT=file=$report && ffmpeg -report -v 0 -i "$filename" -vsync 0 -f image2 -vf select='not(mod(n\\,$divider))' -s $image_size $dir/%d.png`;
- }
- sub parse_report {
- my ($report) = @_;
- my @result = ();
- open INPUT,"<",$report;
- for my $line (<INPUT>) {
- if ($line =~ m/t:([0-9.]{3,}).*select_out:0/) {
- push(@result,$1);
- }
- }
- return @result;
- }
- sub main_extractframes {
- my ($filename1,$filename2) = @ARGV;
- if (! -f $filename1) {
- print "$filename1 does not exist\n";
- #exit(-1);
- }
- if (! -f $filename2) {
- print "$filename2 does not exist\n";
- #exit(-1);
- }
- my $dir1 = File::Temp->newdir(CLEANUP => 0);
- my $dir2 = File::Temp->newdir(CLEANUP => 0);
- my $report1 = File::Temp->new(SUFFIX => '.log', UNLINK => 0);
- my $report2 = File::Temp->new(SUFFIX => '.log', UNLINK => 0);
- #print $dir1 . "\n" . $report . "\n";
- my $image_divider = 40;
- my $image_size = int(1920 / $image_divider) . "x" . int(1080 / $image_divider);
- print STDERR "Extracting frames from " . $filename1 . "\n";
- extract_frames($filename1,$dir1,$report1,$image_size);
- print STDERR "Extracting frames from " . $filename2 . "\n";
- extract_frames($filename2,$dir2,$report2,$image_size);
- print STDERR join("\n",$dir1,$report1,$dir2,$report2) . "\n";
- main_compareframes($dir1,$report1,$dir2,$report2,$filename1,$filename2);
- }
- sub gen_filename {
- my ($i,$filename) = @_;
- if (index($filename,"%")<0) {
- return (-1,"");
- }
- my $f = $filename;
- $f =~ s/%/$i/;
- while ( -f $f ) {
- $i++;
- $f = $filename;
- $f =~ s/%/$i/;
- }
- return ($i,$f);
- }
- sub main_compareframes {
- my ($dir1,$report1,$dir2,$report2) = @_;
- my $vid1 = "";
- my $vid2 = "";
- if (scalar(@_)>=6) {
- $vid1 = $_[4];
- $vid2 = $_[5];
- }
- #$dir1 = "tmp/nRYaFcFI9O"; #3420
- #$report1 = "tmp/Ueqc1FGMQS"; #3452
- #$dir2 = "tmp/QaZDpphSqx.log"; #3420
- #$report2 = "tmp/rcNTAS5d0U.log"; #3452
- #my @images1 = map { $dir1 . "/" . $_ . ".png" } (1..500);
- my @images1 = image_names($dir1);
- my @images2 = image_names($dir2);
- #@images1 = splice(@images1,0,100);
- #@images2 = splice(@images2,0,100);
- my @reportdata1 = parse_report($report1);
- my @reportdata2 = parse_report($report2);
- #print join("\n",@images1); exit(0);
- #my @images2 = map { $dir2 . "/" . $_ . ".png" } (1..500);
- #my @images = (@images1,@images2);
- print STDERR "Loading frames\n";
- my @imagedata1 = map { my @d = load_imagedata($_); \@d } @images1;
- my @imagedata2 = map { my @d = load_imagedata($_); \@d } @images2;
- print STDERR "Comparing frames\n";
- #display_imagedata(1,$imagedata1[5]);
- #display_imagedata(1,$imagedata2[5]);
- my @comparsiondata = (); #index1, index2, time1, time2, img1, img2, index2min, index2max, diff
- my $k = scalar(@images2)/scalar(@images1);
- my $image_range = 30;
- for my $index1 (0..scalar(@images1)-1) {
- print STDERR "." if (not($index1 % 50));
- #print $index1 . " " . $index1*$k . "\n" if ($index1 % 100 == 52);
- my $index2min = int($index1*$k-$image_range);
- my $index2max = int($index1*$k+$image_range);
- my ($index2,$diff) = find_best_match($index1,$index2min,$index2max,\@imagedata1,\@imagedata2);
- my $time1 = $reportdata1[$index1];
- my $img1 = '<img src="' . $images1[$index1] . '"/>';
- my $time2 = 0;
- my $img2 = '';
- if ($index2 > -1) {
- $time2 = $reportdata2[$index2];
- $img2 = '<img src="' . $images2[$index2] . '"/>';
- }
- my @comparsiondata_item = ($index1,$index2,$time1,$time2,$img1,$img2,$index2min,$index2max,$diff);
- push(@comparsiondata,\@comparsiondata_item);
- }
- print STDERR "\n";
- # эксплицитно копируем данные сравнения (одновременно отфильтровывая беспарные кадры)
- # чтобы применить к ним медианную фильтрацию и не испортить исходные данные
- my @comparsiondata_ = ();
- for my $ref (@comparsiondata) {
- if ($ref->[1] > -1) {
- my @row = @$ref;
- push(@comparsiondata_,\@row);
- }
- }
- # рассчет медианы в окне нужно вынести в функцию (размер окна, массив) -> (массив)
- my $median_halfsize = 10;
- my @median_window = ();
- push(@median_window,$comparsiondata_[$_]->[1] - $comparsiondata_[$_]->[0]) for (0..$median_halfsize-1);
- for (0..scalar(@comparsiondata_)-1) {
- my $i = $_+$median_halfsize;
- push(@median_window,$comparsiondata_[$i]->[1] - $comparsiondata_[$i]->[0]) if ($i<scalar(@comparsiondata_));
- shift(@median_window) if ($_>$median_halfsize);
- #print join(" ",@median_window) . "\n";
- my $index1 = $comparsiondata_[$_]->[0];
- my $index2 = int($index1 + median(@median_window));
- my $time2 = $reportdata2[$index2];
- my $img2 = '<img src="' . $images2[$index2] . '"/>';
- $comparsiondata_[$_]->[1] = $index2;
- $comparsiondata_[$_]->[3] = $time2;
- $comparsiondata_[$_]->[5] = $img2;
- $comparsiondata_[$_]->[8] = 0; #diff
- }
- my ($i1,$f1) = gen_filename(1,"resync_audio_report_raw_%.html");
- my ($i2,$f2) = gen_filename(1,"resync_audio_report_filtered_%.html");
- output_comparsiontable($f1,\@comparsiondata,$dir1,$report1,$dir2,$report2,$vid1,$vid2);
- output_comparsiontable($f2,\@comparsiondata_,$dir1,$report1,$dir2,$report2,$vid1,$vid2);
- `firefox "$f1"`;
- `firefox "$f2"`;
- }
- if (scalar(@ARGV) == 0) {
- print "to extract and compare frames: " . $0 . " video1.mkv video2.mkv\n";
- print "to compare frames " . $0 . " dir1 report1 dir2 report2\n";
- } elsif (scalar(@ARGV) == 2) {
- main_extractframes(@ARGV);
- } elsif (scalar(@ARGV) == 4) {
- main_compareframes(@ARGV);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement