Error handling for missing CIEDE dependencies
authorLuc Trudeau <luc@trud.ca>
Tue, 6 Jun 2017 14:57:11 +0000 (10:57 -0400)
committerLuc Trudeau <luc@trud.ca>
Wed, 7 Jun 2017 15:27:47 +0000 (11:27 -0400)
rd_collect will ignore CIEDE2000 when the python packages are missing.
An error message is shown to the user indicating which dependencies are
required.

tools/bd_rate.sh
tools/dump_ciede2000.py
tools/matlab/bd_rate.m
tools/rd_average.sh
tools/rd_collect.sh

index 683883f..0f1f968 100755 (executable)
@@ -20,6 +20,20 @@ if [ ! -f "$BJONTEGAARD" ]; then
   exit 1
 fi
 
+IFS=' ' read -r VALUES <<< "$(head -n 1 $1)"
+VALUES=($VALUES)
+NUM_VALUES_1=${#VALUES[@]}
+IFS=' ' read -r VALUES <<< "$(head -n 1 $2)"
+VALUES=($VALUES)
+NUM_VALUES_2=${#VALUES[@]}
+
+CIEDE_ROW=8
+
+if [ $NUM_VALUES_1 != $NUM_VALUES_2 ]; then
+  echo "Number of metrics in out files don't match"
+  exit 1
+fi
+
 N1=$(cat $1 | wc -l)
 N2=$(cat $2 | wc -l)
 AREA1=$(cut -d\  -f 2 $1 | xargs | sed 's/ /,/g')
@@ -34,8 +48,6 @@ SSIM1=$(cut -d\  -f 6 $1 | xargs | sed 's/ /,/g')
 SSIM2=$(cut -d\  -f 6 $2 | xargs | sed 's/ /,/g')
 FASTSSIM1=$(cut -d\  -f 7 $1 | xargs | sed 's/ /,/g')
 FASTSSIM2=$(cut -d\  -f 7 $2 | xargs | sed 's/ /,/g')
-CIEDE1=$(cut -d\  -f 8 $1 | xargs | sed 's/ /,/g')
-CIEDE2=$(cut -d\  -f 8 $2 | xargs | sed 's/ /,/g')
 
 PSNR_RATE=$($BJONTEGAARD 0 $N1 $AREA1 $SIZE1 $PSNR1 $N2 $AREA2 $SIZE2 $PSNR2)
 PSNR_DSNR=$($BJONTEGAARD 1 $N1 $AREA1 $SIZE1 $PSNR1 $N2 $AREA2 $SIZE2 $PSNR2)
@@ -45,12 +57,17 @@ SSIM_RATE=$($BJONTEGAARD 0 $N1 $AREA1 $SIZE1 $SSIM1 $N2 $AREA2 $SIZE2 $SSIM2)
 SSIM_DSNR=$($BJONTEGAARD 1 $N1 $AREA1 $SIZE1 $SSIM1 $N2 $AREA2 $SIZE2 $SSIM2)
 FASTSSIM_RATE=$($BJONTEGAARD 0 $N1 $AREA1 $SIZE1 $FASTSSIM1 $N2 $AREA2 $SIZE2 $FASTSSIM2)
 FASTSSIM_DSNR=$($BJONTEGAARD 1 $N1 $AREA1 $SIZE1 $FASTSSIM1 $N2 $AREA2 $SIZE2 $FASTSSIM2)
-CIEDE_RATE=$($BJONTEGAARD 0 $N1 $AREA1 $SIZE1 $CIEDE1 $N2 $AREA2 $SIZE2 $CIEDE2)
-CIEDE_DSNR=$($BJONTEGAARD 1 $N1 $AREA1 $SIZE1 $CIEDE1 $N2 $AREA2 $SIZE2 $CIEDE2)
 
 echo "           RATE (%) DSNR (dB)"
 echo "    PSNR" $(echo $PSNR_RATE     | cut -d\  -f 3) $(echo $PSNR_DSNR     | cut -d\  -f 3)
 echo " PSNRHVS" $(echo $PSNRHVS_RATE  | cut -d\  -f 3) $(echo $PSNRHVS_DSNR  | cut -d\  -f 3)
 echo "    SSIM" $(echo $SSIM_RATE     | cut -d\  -f 3) $(echo $SSIM_DSNR     | cut -d\  -f 3)
 echo "FASTSSIM" $(echo $FASTSSIM_RATE | cut -d\  -f 3) $(echo $FASTSSIM_DSNR | cut -d\  -f 3)
-echo "   CIEDE" $(echo $CIEDE_RATE    | cut -d\  -f 3) $(echo $CIEDE_DSNR    | cut -d\  -f 3)
+
+if [ $NUM_VALUES_1 -ge $CIEDE_ROW ]; then
+  CIEDE1=$(cut -d\  -f 8 $1 | xargs | sed 's/ /,/g')
+  CIEDE2=$(cut -d\  -f 8 $2 | xargs | sed 's/ /,/g')
+  CIEDE_RATE=$($BJONTEGAARD 0 $N1 $AREA1 $SIZE1 $CIEDE1 $N2 $AREA2 $SIZE2 $CIEDE2)
+  CIEDE_DSNR=$($BJONTEGAARD 1 $N1 $AREA1 $SIZE1 $CIEDE1 $N2 $AREA2 $SIZE2 $CIEDE2)
+  echo "   CIEDE" $(echo $CIEDE_RATE    | cut -d\  -f 3) $(echo $CIEDE_DSNR    | cut -d\  -f 3)
+fi
index 22ba728..388882c 100755 (executable)
@@ -1,4 +1,5 @@
 #!/usr/bin/env python
+
 from collections import deque
 import sys
 import numpy as np
@@ -14,6 +15,10 @@ yuv2rgb = np.array([
 box2 = np.ones((2, 2))
 
 
+def usage():
+    print("Usage: %s <video1> <video2>\n"
+            "    <video1> and <video2> must be YUV4MPEG files.\n\n" %  __file__);
+
 def decode_y4m_buffer(frame):
     W, H = frame.headers['W'], frame.headers['H']
     Wdiv2, Hdiv2 = W // 2, H // 2
@@ -78,6 +83,10 @@ class Reader(y4m.Reader):
         return pixels
 
 def main(args):
+    if len(args) != 3:
+        usage()
+        sys.exit(0)
+
     OPENING = 'Opening %s...'
     BLOCK_SIZE = 4 * 1024 * 1024
     ref_parser = Reader(process_ref)
index 8923e1e..e705ef0 100755 (executable)
@@ -3,6 +3,8 @@
 warning("off","Octave:nested-functions-coerced");
 warning("on","Octave:missing-semicolon");
 
+CIEDE_ROW = 8;
+
 args=argv();
 
 if size(args,1)!=2
@@ -70,6 +72,13 @@ endswitch
 rd1=load("-ascii",args{1});
 rd2=load("-ascii",args{2});
 
+[~, num_val_1] = size(rd1);
+[~, num_val_2] = size(rd2);
+if num_val_1 ~= num_val_2
+  printf("Number of metrics does not match.")
+  return
+end
+
 rd1=flipud(sortrows(rd1,1));
 rd2=flipud(sortrows(rd2,1));
 
@@ -79,16 +88,29 @@ rate2=rd2(:,3)*8./rd2(:,2);
 pin = program_invocation_name;
 chdir(pin(1:(length(pin)-length(program_name))));
 
-[psnr_rate,psnr_dsnr]=bjontegaard([rate1,rd1(:,4)],[rate2,rd2(:,4)],t,min_bpp,max_bpp);
-[psnrhvs_rate,psnrhvs_dsnr]=bjontegaard([rate1,rd1(:,5)],[rate2,rd2(:,5)],t,min_bpp,max_bpp);
-[ssim_rate,ssim_dsnr]=bjontegaard([rate1,rd1(:,6)],[rate2,rd2(:,6)],t,min_bpp,max_bpp);
-[fastssim_rate,fastssim_dsnr]=bjontegaard([rate1,rd1(:,7)],[rate2,rd2(:,7)],t,min_bpp,max_bpp);
-[ciede_rate,ciede_dsnr]=bjontegaard([rate1,rd1(:,8)],[rate2,rd2(:,8)],t,min_bpp,max_bpp);
+[psnr_rate,psnr_dsnr]=bjontegaard([rate1,rd1(:,4)],[rate2,rd2(:,4)],t,...
+ min_bpp,max_bpp);
+[psnrhvs_rate,psnrhvs_dsnr]=bjontegaard([rate1,rd1(:,5)],[rate2,rd2(:,5)],...
+ t,min_bpp,max_bpp);
+[ssim_rate,ssim_dsnr]=bjontegaard([rate1,rd1(:,6)],[rate2,rd2(:,6)],t,...
+ min_bpp,max_bpp);
+[fastssim_rate,fastssim_dsnr]=bjontegaard([rate1,rd1(:,7)],[rate2,rd2(:,7)]...
+ ,t,min_bpp,max_bpp);
 
-if (strcmpi(REPORT, "awcy"))
-  printf("    PSNR | PSNR HVS |    SSIM | MS SSIM | CIEDE 2000\n")
-  printf("%8.4f |%9.4f |%8.4f |%8.4f |%11.4f\n", psnr_rate, psnrhvs_rate, ...
-   ssim_rate, fastssim_rate, ciede_rate)
+if num_val_1 >= 8
+  [ciede_rate,ciede_dsnr]=bjontegaard([rate1,rd1(:,8)],[rate2,rd2(:,8)],t,...
+   min_bpp,max_bpp);
+endif
+
+if (strcmpi(REPORT,"awcy"))
+  header = "    PSNR | PSNR HVS |    SSIM | MS SSIM";
+  values = sprintf("%8.4f |%9.4f |%8.4f |%8.4f",psnr_rate,psnrhvs_rate,...
+   ssim_rate,fastssim_rate);
+  if num_val_1 >= CIEDE_ROW
+    header = sprintf("%s | CIEDE 2000",header);
+    values = sprintf("%s |%11.4f", values,ciede_rate);
+  endif
+  printf("%s\n%s\n",header,values)
 else
   if ((min_bpp != 0) || (max_bpp != Inf))
     printf("          DSNR (dB)\n");
@@ -96,13 +118,17 @@ else
     printf(" PSNRHVS %0.5f\n",psnrhvs_dsnr);
     printf("    SSIM %0.5f\n",ssim_dsnr);
     printf("FASTSSIM %0.5f\n",fastssim_dsnr);
-    printf("   CIEDE %0.5f\n",ciede_dsnr);
+    if num_val_1 >= CIEDE_ROW
+      printf("   CIEDE %0.5f\n",ciede_dsnr);
+    endif
   else
     printf("           RATE (%%)  DSNR (dB)\n");
     printf("    PSNR %0.5f  %0.5f\n",psnr_rate,psnr_dsnr);
     printf(" PSNRHVS %0.5f  %0.5f\n",psnrhvs_rate,psnrhvs_dsnr);
     printf("    SSIM %0.5f  %0.5f\n",ssim_rate,ssim_dsnr);
     printf("FASTSSIM %0.5f  %0.5f\n",fastssim_rate,fastssim_dsnr);
-    printf("   CIEDE %0.5f  %0.5f\n",ciede_rate,ciede_dsnr);
+    if num_val_1 >= CIEDE_ROW
+      printf("   CIEDE %0.5f  %0.5f\n",ciede_rate,ciede_dsnr);
+    endif
   endif
 endif
index bc8af81..a3c1dc6 100755 (executable)
@@ -16,4 +16,19 @@ if [ -e "$TOTAL" ]; then
   exit 1
 fi
 
-awk '{size[$1]+=$2;bytes[$1]+=$3;psnr[$1]+=$2*$4;psnrhvs[$1]+=$2*$5;ssim[$1]+=$2*$6;fastssim[$1]+=$2*$7;ciede[$1]+=$2*$8;}END{for(i in size)print i,size[i],bytes[i],psnr[i]/size[i],psnrhvs[i]/size[i],ssim[i]/size[i],fastssim[i]/size[i],ciede[i]/size[i];}' $@ | sort -n > $TOTAL
+IFS=' ' read -r VALUES <<< "$(head -n 1 $1)"
+VALUES=($VALUES)
+NUM_VALUES=${#VALUES[@]}
+CIEDE_ROW=8
+
+AWK_SUM='size[$1]+=$2;bytes[$1]+=$3;psnr[$1]+=$2*$4;psnrhvs[$1]+=$2*$5;ssim[$1]+=$2*$6;fastssim[$1]+=$2*$7;'
+AWK_DIV='psnr[i]/size[i],psnrhvs[i]/size[i],ssim[i]/size[i],fastssim[i]/size[i]'
+
+if [ $NUM_VALUES -ge $CIEDE_ROW ]; then
+  AWK_SUM+='ciede[$1]+=$2*$8;'
+  AWK_DIV+=',ciede[i]/size[i]'
+fi
+
+AWK_CMD="{$AWK_SUM}END{for(i in size)print i,size[i],bytes[i],$AWK_DIV;}"
+
+awk "$AWK_CMD" $@ | sort -n > $TOTAL
index 80c3054..c0822f2 100755 (executable)
@@ -380,6 +380,19 @@ if [ ! -x "$DUMP_FASTSSIM" ]; then
   exit 1
 fi
 
+set +e
+temp=$($DUMP_CIEDE)
+if [ $? -ne 0 ]; then
+  echo "Warning Python dependencies not found. CIEDE2000 will not be computed."
+  echo "Required Python dependencies are: numpy, skimage and y4m."
+  if [ "$(uname -s)" = "Darwin" ]; then
+    DUMP_CIEDE=/usr/bin/true
+  else
+    DUMP_CIEDE=/bin/true
+  fi
+fi
+set -e
+
 if [ -z "$CORES" ]; then
   if [ "$(uname -s)" = "Darwin" ]; then
     CORES=$(sysctl -n hw.ncpu)