#!/usr/bin/perl # This software was produced by NIST, an agency of the U.S. government, # and by statute is not subject to copyright in the United States. Recipients # of this software assume all responsibilities associated with its operation, # modification and maintenance. use strict; # Check a TRECVID 2008 copy detection submission. # # # This script was tested on a Dell x86 workstation running Red Hat # Enterprise Linux (RHEL) 4. It probably does not run under Windows # without a POSIX environment such as Cygwin. # For non-RHEL4 systems, you may need to modify the paths below. my $errlog_dir = "."; my $MAX_ERRORS = 1000; my $results_file; # input file to be checked my $errlog; # file name of error log my $num_errors; # number of errors seen so far my $usage = "Usage: check_copydetection.pl \n"; $results_file = shift or die $usage; $errlog = $errlog_dir . "/" . $results_file . ".errlog"; open ERRLOG, ">$errlog" or error("Can't open error log for writing"); #-------------------------------------------------------------------------- my $refVideos = "./ref.videos"; my $refDurations = "./ref.durations"; my $slash = "/"; my $botValidQueryId = 0; my $topValidQueryId = 0;; my $requiredNumQueries = 0; my $lineNum = 0; my $line = ""; my %qIdHash = (); my %durations = (); my %videos = (); my %overlap = (); my @list = (); # open run file open RUN, "$results_file" or die "Can't open runfile \"$results_file\": $!\n"; # Derive run type from file name: GROUPID.RUNTYPE.runId # where RUNTYPE = a | v | m my $i = rindex($results_file,$slash); if ($i != -1) { $results_file = substr($results_file,$i); } my (undef,$runType,$webpageRunId) = split /\./,$results_file; # Read valid videoIds into a hash open VIDEOS, "$refVideos" or die "Can't open $refVideos file: $!\n"; while ($line=) { my ($fileName) = split /\s+/,$line; $videos{$fileName} = 1; } # Read ref video durations into a hash open DURATIONS, "$refDurations" or die "Can't open $refDurations file: $!\n"; while ($line=) { my (undef,$dur,$frames,$fileName,undef) = split /\s+/," $line"; $durations{$fileName} = $dur; #$durations{$fileName} = $frames/25; } # Set range of valid query IDs if ($runType eq "a") { $botValidQueryId = 3001; $topValidQueryId = 4407; $requiredNumQueries = 1407; } elsif ($runType eq "v") { $botValidQueryId = 1; $topValidQueryId = 2010; $requiredNumQueries = 2010; } elsif ($runType eq "m") { $botValidQueryId = 5001; $topValidQueryId = 19070; $requiredNumQueries = 14070; } my $runId = ""; my $opSys = ""; my $cpu = ""; my $memory = ""; while ($line = ) { $lineNum++; chomp $line; my (undef,$code,$rest) = split /\s+/," $line",3; if ($code eq "R") { my ($qId,$vId,$firstRefTime,$lastRefTime,$conf,$firstQueryTime) = split /\s+/,$rest; # valid queryId for this run type (v, a, m)? if ($qId > $topValidQueryId || $qId < $botValidQueryId) { &error("Line $lineNum: invalid query id ($qId) for this run type: $runType"); } # valid video file name? if (! exists $videos{$vId}) { &error("Line $lineNum: invalid video id: \"$vId\""); } # last ref time > first time ref? if ($lastRefTime <= $firstRefTime) { &error("Line $lineNum: last ref time ($lastRefTime) precedes first ref time ($firstRefTime)"); } # first ref time >= 0? if ($firstRefTime < 0) { &error("Line $lineNum: first ref time ($firstRefTime) < = 0"); } # first ref time <= end of video? if ($firstRefTime > $durations{$vId}) { &error("Line $lineNum: first ref time ($firstRefTime) beyond end of ref video ($durations{$vId})"); } # last ref time <= end of video? if ($lastRefTime > $durations{$vId}) { &error("Line $lineNum: last ref time ($lastRefTime) beyond end of ref video ($durations{$vId})"); } # Add result item to hash used to look for possible overlapping items if (!exists $overlap{"$qId $vId"}) { $overlap{"$qId $vId"} = (); } @list = [$firstRefTime, $lastRefTime]; push @{ $overlap{"$qId $vId"} }, @list; # first query ref <= end of query? } # Timing info: queryId elapsedQueyProcessingTimeInSeconds elsif ($code eq "T") { my ($qId,$time) = split /\s+/,$rest; # valid queryId for this run type (v, a, a+v)? if ($qId < $botValidQueryId || $qId > $topValidQueryId) { &error("Line $lineNum: invalid query id for this run type: $runType"); } else { $qIdHash{$qId} = 1; } } # runId: string elsif ($code eq "I") { $runId = $rest; chomp $rest; if ($runId !~ /\A[a-zA-Z0-9]+\Z/) { &error("Line $lineNum: run ID in file \"$runId\" is not just alphanumeric [a-z,A-Z,0-9]"); } if ($runId ne $webpageRunId) { &error("Line $lineNum: input run ID \"$webpageRunId\" does not match run ID in file \"$runId\""); } } # operating system: string elsif ($code eq "S") { $opSys = $rest; } # cpu: string elsif ($code eq "C") { $cpu = $rest; } # amount of memory: string elsif ($code eq "M") { $memory = $rest; } # unknown code else { &error("Line $lineNum: Unrecognized code \"$code\""); } } # Check runId present? if ($runId eq "") { &error("run id missing"); } # Check operating system present? if ($opSys eq "") { &error("operating system info missing"); } # Check cpu present? if ($cpu eq "") { &error("cpu type missing"); } # Check memory present? if ($memory eq "") { &error("memory size missing"); } # Check timing for all queries present? my $actualNumQueries = scalar keys %qIdHash; if ($actualNumQueries != $requiredNumQueries) { &error("missing/extra timing info for queries: timing for $requiredNumQueries queries required, $actualNumQueries submitted"); } # Check no overlapping result items my $i = 0; my $j = 0; my $maxI = 0; my $queryVideo = ""; foreach my $queryVideo (sort keys %overlap) { $maxI = scalar @{$overlap{$queryVideo}}; for ($i=0;$i<$maxI;$i++) { for ($j=$i+1;$j<$maxI;$j++) { if ( ((@{@{$overlap{$queryVideo}}[$i]}[0] >= @{@{$overlap{$queryVideo}}[$j]}[0]) && (@{@{$overlap{$queryVideo}}[$i]}[0] <= @{@{$overlap{$queryVideo}}[$j]}[1])) || ((@{@{$overlap{$queryVideo}}[$i]}[1] >= @{@{$overlap{$queryVideo}}[$j]}[0]) && (@{@{$overlap{$queryVideo}}[$i]}[1] <= @{@{$overlap{$queryVideo}}[$j]}[1])) ) { &error("Overlapping results items for Query $queryVideo: (@{@{$overlap{$queryVideo}}[$i]}) (@{@{$overlap{$queryVideo}}[$j]})"); } } } } #-------------------------------------------------------------------------- print ERRLOG "Finished processing $results_file\n"; close ERRLOG || die "Close failed for error log $errlog: $!\n"; if ($num_errors) { exit 255; } exit 0; # print error message, keeping track of total number of errors sub error { my $msg_string = pop(@_); print ERRLOG "$0 of $results_file: Error --- $msg_string\n"; $num_errors++; if ($num_errors > $MAX_ERRORS) { print ERRLOG "$0 of $results_file: Quit. Too many errors!\n"; close ERRLOG || die "Close failed for error log $errlog: $!\n"; exit 255; } }