<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Oct 4, 2013 at 6:21 AM, Aarthi Thirumalai <span dir="ltr"><<a href="mailto:aarthi@multicorewareinc.com" target="_blank">aarthi@multicorewareinc.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"># HG changeset patch<br>
# User Aarthi Thirumalai<br>
# Date 1380885375 -19800<br>
# Fri Oct 04 16:46:15 2013 +0530<br>
# Node ID 92641f3d3195b8da2275cfc44b1921d8f81a54bc<br>
# Parent bf14f75b8cf99806c75cdc1a50b28b6cf265e3bd<br>
primitives: added C primitives to compute SSIM<br>
<br>
diff -r bf14f75b8cf9 -r 92641f3d3195 source/common/pixel.cpp<br>
--- a/source/common/pixel.cpp Fri Oct 04 01:39:22 2013 -0500<br>
+++ b/source/common/pixel.cpp Fri Oct 04 16:46:15 2013 +0530<br>
@@ -653,6 +653,85 @@<br>
}<br>
}<br>
<br>
+/* structural similarity metric */<br>
+template<class T1><br>
+void ssim_4x4x2_core(const pixel *pix1, intptr_t stride1, const pixel *pix2, intptr_t stride2, T1 sums[2][4])<br>
+{<br>
+ for (int z = 0; z < 2; z++)<br>
+ {<br>
+ T1 s1 = 0, s2 = 0, ss = 0, s12 = 0;<br>
+ for (int y = 0; y < 4; y++)<br>
+ {<br>
+ for (int x = 0; x < 4; x++)<br>
+ {<br>
+ T1 a = pix1[x + y * stride1];<br>
+ T1 b = pix2[x + y * stride2];<br>
+ s1 += a;<br>
+ s2 += b;<br>
+ ss += a * a;<br>
+ ss += b * b;<br>
+ s12 += a * b;<br>
+ }<br>
+ }<br>
+<br>
+ sums[z][0] = s1;<br>
+ sums[z][1] = s2;<br>
+ sums[z][2] = ss;<br>
+ sums[z][3] = s12;<br>
+ pix1 += 4;<br>
+ pix2 += 4;<br>
+ }<br>
+}<br>
+<br>
+template<class T1><br>
+float ssim_end_4(T1 sum0[5][4], T1 sum1[5][4], int width)<br>
+{<br>
+ float ssim = 0.0;<br>
+<br>
+ for (int i = 0; i < width; i++)<br>
+ {<br>
+ ssim += ssim_end_1(sum0[i][0] + sum0[i + 1][0] + sum1[i][0] + sum1[i + 1][0],<br>
+ sum0[i][1] + sum0[i + 1][1] + sum1[i][1] + sum1[i + 1][1],<br>
+ sum0[i][2] + sum0[i + 1][2] + sum1[i][2] + sum1[i + 1][2],<br>
+ sum0[i][3] + sum0[i + 1][3] + sum1[i][3] + sum1[i + 1][3]);<br>
+ }<br>
+<br>
+ return ssim;<br>
+}<br>
+<br>
+float ssim_end_1(int s1, int s2, int ss, int s12)<br>
+{<br>
+ static const uint32_t pixelMax = (1 << X265_DEPTH) - 1;<br>
+<br>
+ /* Maximum value for 10-bit is: ss*64 = (2^10-1)^2*16*4*64 = 4286582784, which will overflow in some cases.<br>
+ * s1*s1, s2*s2, and s1*s2 also obtain this value for edge cases: ((2^10-1)*16*4)^2 = 4286582784.<br>
+ * Maximum value for 9-bit is: ss*64 = (2^9-1)^2*16*4*64 = 1069551616, which will not overflow. */<br>
+<br>
+#if X265_DEPTH > 9<br>
+#define type int64_t<br>
+#else<br>
+#define type int32_t<br>
+#endif<br></blockquote><div><br></div><div>We keep cycling on this issue.</div><div><br></div><div>With HIGH_BIT_DEPTH=1, X265_DEPTH evaluates to g_bitDepth (a global variable)</div><div>With HIGH_BIT_DEPTH=0, X265_DEPTH evaluates to 8</div>
<div><br></div><div>So with high bit depth builds the bit depth is a runtime option (it could be 8, 10, or 12). For 8bpp builds the bit depth must be 8.</div><div><br></div><div>HIGH_BIT_DEPTH=0 builds will probably always use the uint32 version of this function. The HIGH_BIT_DEPTH=1 builds will have to choose between uint32 or float at runtime.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+<br>
+ static const type ssim_c1 = (type)(.01 * .01 * pixelMax * pixelMax * 64 + .5);<br>
+ static const type ssim_c2 = (type)(.03 * .03 * pixelMax * pixelMax * 64 * 63 + .5);<br>
+ type vars = ss * 64 - s1 * s1 - s2 * s2;<br>
+ type covar = s12 * 64 - s1 * s2;<br>
+ return (float)(2 * s1 * s2 + ssim_c1) * (float)(2 * covar + ssim_c2)<br>
+ / ((float)(s1 * s1 + s2 * s2 + ssim_c1) * (float)(vars + ssim_c2));<br>
+}<br>
+<br>
+float ssim_end_1(float s1, float s2, float ss, float s12)<br>
+{<br>
+ static const float pixelMax = (1 << X265_DEPTH) - 1;<br>
+ static const float ssim_c1 = (float)(.01 * .01 * pixelMax * pixelMax * 64);<br>
+ static const float ssim_c2 = (float)(.03 * .03 * pixelMax * pixelMax * 64 * 63);<br>
+ float vars = ss * 64 - s1 * s1 - s2 * s2;<br>
+ float covar = s12 * 64 - s1 * s2;<br>
+<br>
+ return (2 * s1 * s2 + ssim_c1) * (2 * covar + ssim_c2)<br>
+ / ((s1 * s1 + s2 * s2 + ssim_c1) * (vars + ssim_c2));<br>
+}<br>
} // end anonymous namespace<br>
<br>
namespace x265 {<br>
@@ -870,5 +949,10 @@<br>
p.scale1D_128to64 = scale1D_128to64;<br>
p.scale2D_64to32 = scale2D_64to32;<br>
p.frame_init_lowres_core = frame_init_lowres_core;<br>
+<br>
+ p.ssim_4x4x2_core_float = ssim_4x4x2_core<float>;<br>
+ p.ssim_4x4x2_core_int = ssim_4x4x2_core<int>;<br>
+ p.ssim_end4_float = ssim_end_4<float>;<br>
+ p.ssim_end4_int = ssim_end_4<int>;<br>
}<br>
}<br>
diff -r bf14f75b8cf9 -r 92641f3d3195 source/common/primitives.h<br>
--- a/source/common/primitives.h Fri Oct 04 01:39:22 2013 -0500<br>
+++ b/source/common/primitives.h Fri Oct 04 16:46:15 2013 +0530<br>
@@ -235,6 +235,10 @@<br>
typedef void (*scale_t)(pixel *dst, pixel *src, intptr_t stride);<br>
typedef void (*downscale_t)(pixel *src0, pixel *dstf, pixel *dsth, pixel *dstv, pixel *dstc,<br>
intptr_t src_stride, intptr_t dst_stride, int width, int height);<br>
+typedef void (*ssim_4x4x2_core_int_t)(const pixel *pix1, intptr_t stride1, const pixel *pix2, intptr_t stride2, int sums[2][4]);<br>
+typedef void (*ssim_4x4x2_core_float_t)(const pixel *pix1, intptr_t stride1, const pixel *pix2, intptr_t stride2, float sums[2][4]);<br>
+typedef float (*ssim_end4_int_t)(int sum0[5][4], int sum1[5][4], int width);<br>
+typedef float (*ssim_end4_float_t)(float sum0[5][4], float sum1[5][4], int width);<br>
<br>
/* Define a structure containing function pointers to optimized encoder<br>
* primitives. Each pointer can reference either an assembly routine,<br>
@@ -301,6 +305,13 @@<br>
scale_t scale1D_128to64;<br>
scale_t scale2D_64to32;<br>
downscale_t frame_init_lowres_core;<br>
+<br>
+/* If the pixel depth >15 , use the ssim_float primitives to prevent overflow, else<br>
+ * ssim_int primitves should be sufficient. */<br>
+ ssim_4x4x2_core_int_t ssim_4x4x2_core_int;<br>
+ ssim_4x4x2_core_float_t ssim_4x4x2_core_float;<br>
+ ssim_end4_int_t ssim_end4_int;<br>
+ ssim_end4_float_t ssim_end4_float;<br>
};<br>
<br>
/* This copy of the table is what gets used by the encoder.<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br>Steve Borho
</div></div>