[FFmpeg-devel] [PATCH] tools: add tiny_ssim
Michael Niedermayer
michaelni at gmx.at
Sun Mar 24 16:15:56 CET 2013
From: Loren Merritt <lorenm at u.washington.edu>
Taken from:
http://lists.mplayerhq.hu/pipermail/mencoder-users/2006-August/003801.html
Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
---
.gitignore | 1 +
Makefile | 2 +-
tests/Makefile | 2 +-
tests/tiny_ssim.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 149 insertions(+), 2 deletions(-)
create mode 100644 tests/tiny_ssim.c
diff --git a/.gitignore b/.gitignore
index 9b935c7..fd4ce20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,7 @@
/tests/data/
/tests/rotozoom
/tests/tiny_psnr
+/tests/tiny_ssim
/tests/videogen
/tests/vsynth1/
/tools/aviocat
diff --git a/Makefile b/Makefile
index 07821d1..d12a9a9 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ INSTPROGS = $(PROGS-yes:%=%$(PROGSSUF)$(EXESUF))
OBJS = cmdutils.o $(EXEOBJS)
OBJS-ffmpeg = ffmpeg_opt.o ffmpeg_filter.o
-TESTTOOLS = audiogen videogen rotozoom tiny_psnr base64
+TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64
HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options
TOOLS = qt-faststart trasher
TOOLS-$(CONFIG_ZLIB) += cws2fws
diff --git a/tests/Makefile b/tests/Makefile
index 73ee2d9..0f911e1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -147,7 +147,7 @@ $(FATE_EXTERN):
@echo "$@ requires external samples and SAMPLES not specified"; false
endif
-FATE_UTILS = base64 tiny_psnr
+FATE_UTILS = base64 tiny_psnr tiny_ssim
TOOL = ffmpeg
diff --git a/tests/tiny_ssim.c b/tests/tiny_ssim.c
new file mode 100644
index 0000000..56650e7
--- /dev/null
+++ b/tests/tiny_ssim.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2006 Loren Merritt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110 USA
+ */
+/*
+ * tiny_ssim.c
+ * Computes the Structural Similarity Metric between two rawYV12 video files.
+ * original algorithm:
+ * Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. Simoncelli,
+ * "Image quality assessment: From error visibility to structural similarity,"
+ * IEEE Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004.
+ *
+ * To improve speed, this implementation uses the standard approximation of
+ * overlapped 8x8 block sums, rather than the original gaussian weights.
+ */
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+double ssim_8x8( const uint8_t *pix1, int stride1,
+ const uint8_t *pix2, int stride2 )
+{
+ const int c1 = (int)(.01*.01*255*255*64 + .5);
+ const int c2 = (int)(.03*.03*255*255*64*63 + .5);
+ uint32_t s1=0, s2=0, ss=0, s12=0;
+ uint32_t vars;
+ int32_t covar;
+ int x, y;
+
+ for(y=0; y<8; y++)
+ for(x=0; x<8; x++)
+ {
+ int a = pix1[x+y*stride1];
+ int b = pix2[x+y*stride2];
+ s1 += a;
+ s2 += b;
+ ss += a*a;
+ ss += b*b;
+ s12 += a*b;
+ }
+
+ vars = ss*64 - s1*s1 - s2*s2;\
+ covar = s12*64 - s1*s2;\
+ return (double)(2*s1*s2 + c1) * (double)(2*covar + c2)\
+ / ((double)(s1*s1 + s2*s2 + c1) * (double)(vars + c2));
+}
+
+double ssim_plane( const uint8_t *pix1, const uint8_t *pix2, int width, int height )
+{
+ int x, y;
+ double sum = 0.0;
+ for( y = 0; y <= height-8; y += 4 )
+ for( x = 0; x <= width-8; x += 4 )
+ sum += ssim_8x8( pix1+x+y*width, width,
+ pix2+x+y*width, width );
+ return sum / ((width/4-1) * (height/4-1));
+}
+
+uint64_t ssd_plane( const uint8_t *pix1, const uint8_t *pix2, int size )
+{
+ uint64_t ssd = 0;
+ int i;
+ for( i=0; i<size; i++ )
+ {
+ int d = pix1[i] - pix2[i];
+ ssd += d*d;
+ }
+ return ssd;
+}
+
+double ssd_to_psnr( uint64_t ssd, uint64_t denom )
+{
+ return -10*log((double)ssd/(denom*255*255))/log(10);
+}
+
+int main(int argc, char* argv[])
+{
+ FILE *f[2];
+ uint8_t *buf[2], *plane[2][3];
+ uint64_t ssd[3] = {0,0,0};
+ double ssim[3] = {0,0,0};
+ int frame_size, w, h;
+ int frames, seek;
+ int i;
+
+ if( argc<4 || 2 != sscanf(argv[3], "%dx%d", &w, &h) )
+ {
+ printf("tiny_ssim <file1.yuv> <file2.yuv> <width>x<height> [<seek>]\n");
+ return -1;
+ }
+
+ f[0] = fopen(argv[1], "rb");
+ f[1] = fopen(argv[2], "rb");
+ sscanf(argv[3], "%dx%d", &w, &h);
+ frame_size = w*h*3/2;
+ for( i=0; i<2; i++ )
+ {
+ buf[i] = malloc(frame_size);
+ plane[i][0] = buf[i];
+ plane[i][1] = plane[i][0] + w*h;
+ plane[i][2] = plane[i][1] + w*h/4;
+ }
+ seek = argc<5 ? 0 : atoi(argv[4]);
+ fseek(f[seek<0], seek < 0 ? -seek : seek, SEEK_SET);
+
+ for( frames=0;; frames++ )
+ {
+ if( fread(buf[0], frame_size, 1, f[0]) != 1) break;
+ if( fread(buf[1], frame_size, 1, f[1]) != 1) break;
+ for( i=0; i<3; i++ )
+ {
+ ssd[i] += ssd_plane ( plane[0][i], plane[1][i], w*h>>2*!!i );
+ ssim[i] += ssim_plane( plane[0][i], plane[1][i], w>>!!i, h>>!!i );
+ }
+ }
+
+ if( !frames ) return 0;
+
+ printf( "PSNR Y:%.3f U:%.3f V:%.3f All:%.3f\n",
+ ssd_to_psnr( ssd[0], (uint64_t)frames*w*h ),
+ ssd_to_psnr( ssd[1], (uint64_t)frames*w*h/4 ),
+ ssd_to_psnr( ssd[2], (uint64_t)frames*w*h/4 ),
+ ssd_to_psnr( ssd[0] + ssd[1] + ssd[2], (uint64_t)frames*w*h*3/2 ) );
+ printf( "SSIM Y:%.5f U:%.5f V:%.5f All:%.5f\n",
+ ssim[0] / frames,
+ ssim[1] / frames,
+ ssim[2] / frames,
+ (ssim[0]*4 + ssim[1] + ssim[2]) / (frames*6) );
+
+ return 0;
+}
--
1.7.9.5
More information about the ffmpeg-devel
mailing list