Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/torch/image.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Agapiou <jagapiou@google.com>2015-11-02 21:13:45 +0300
committerJohn Agapiou <jagapiou@google.com>2015-11-03 18:27:39 +0300
commitba54371234e1f2b1d7a1360f5b02a747d0585f27 (patch)
treefbf76b799c08824cff7d53e61ab9c4a7e0eb76ea
parentd97d20dbbd836a7801804c667fc1e5c56b2e90f2 (diff)
Fix bug with image.scale 'bicubic' and ByteTensors.
Bicubic interpolation and scaling do not work for ByteTensors due to issues with numerical precision. * Add unit tests for ByteTensor scaling. * Update scaling to use existing cubic interpolation method. * Update cubic interpolation to use double precision Temporary variables. * Add function to handle casting from `double` to `real`.
-rwxr-xr-xgeneric/image.c48
-rw-r--r--test/test_scale.lua45
2 files changed, 67 insertions, 26 deletions
diff --git a/generic/image.c b/generic/image.c
index 89ba31f..d63e751 100755
--- a/generic/image.c
+++ b/generic/image.c
@@ -15,6 +15,16 @@
#define M_PI 3.14159265358979323846
#endif
+
+static inline real image_(FromDouble)(double x) {
+ #ifdef TH_REAL_IS_BYTE
+ if( x <= 0 ) return 0;
+ if( x >= 255 ) return 255;
+ #endif
+ return x;
+}
+
+
static void image_(Main_op_validate)( lua_State *L, THTensor *Tsrc, THTensor *Tdst){
long src_depth = 1;
@@ -117,6 +127,19 @@ static void image_(Main_scaleLinear_rowcol)(THTensor *Tsrc,
}
}
+
+static inline real image_(Main_cubicInterpolate)(double p0, double p1,
+ double p2, double p3,
+ double x) {
+ double a0 = p1;
+ double a1 = p2 - p0;
+ double a2 = 2 * p0 - 5 * p1 + 4 * p2 - p3;
+ double a3 = 3 * (p1 - p2) + p3 - p0;
+ double v = a0 + 0.5 * x * (a1 + x * (a2 + x * a3));
+ return image_(FromDouble)(v);
+}
+
+
static void image_(Main_scaleCubic_rowcol)(THTensor *Tsrc,
THTensor *Tdst,
long src_start,
@@ -147,28 +170,22 @@ static void image_(Main_scaleCubic_rowcol)(THTensor *Tsrc,
long dst_pos = dst_start + di*dst_stride;
si_f = di * scale; si_i = (long)si_f; si_f -= si_i;
- real p0;
- real p1 = src[ src_start + si_i * src_stride ];
- real p2 = src[ src_start + (si_i + 1) * src_stride ];
- real p3;
+ double p0;
+ double p1 = src[ src_start + si_i * src_stride ];
+ double p2 = src[ src_start + (si_i + 1) * src_stride ];
+ double p3;
if (si_i > 0) {
p0 = src[ src_start + (si_i - 1) * src_stride ];
} else {
- p0 = 2*p1 - p2;
+ p0 = 2 * p1 - p2;
}
if (si_i + 2 < src_len) {
p3 = src[ src_start + (si_i + 2) * src_stride ];
} else {
- p3 = 2*p2 - p1;
+ p3 = 2 * p2 - p1;
}
- real a0 = p1;
- real a1 = -(real)1/(real)2*p0 + (real)1/(real)2*p2;
- real a2 = p0 - (real)5/(real)2*p1 + (real)2*p2 - (real)1/(real)2*p3;
- real a3 = -(real)1/(real)2*p0 + (real)3/(real)2*p1 - (real)3/(real)2*p2 +
- (real)1/(real)2*p3;
-
- dst[dst_pos] = a0 + si_f * (a1 + si_f * (a2 + a3 * si_f));
+ dst[dst_pos] = image_(Main_cubicInterpolate)(p0, p1, p2, p3, si_f);
}
dst[ dst_start + (dst_len - 1) * dst_stride ] =
@@ -1637,11 +1654,6 @@ int image_(Main_flip)(lua_State *L) {
return 0;
}
-static inline real image_(Main_cubicInterpolate)(real p0, real p1, real p2, real p3, real x)
-{
- return p1 + 0.5 * x * (p2 - p0 + x * (2 * p0 - 5 * p1 + 4 * p2 - p3 + x * (3 * (p1 - p2) + p3 - p0)));
-}
-
static inline void image_(Main_bicubicInterpolate)(
real* src, long* is, long* size, real ix, real iy,
real* dst, long *os,
diff --git a/test/test_scale.lua b/test/test_scale.lua
index f2225a7..02f3410 100644
--- a/test/test_scale.lua
+++ b/test/test_scale.lua
@@ -14,35 +14,64 @@ local function outerProduct(x)
end
+local function assertTensorEq(actual, expected)
+ if torch.type(expected) == 'torch.ByteTensor' then
+ local areEqual = torch.eq(actual, expected):all()
+ tester:assert(areEqual)
+ else
+ tester:assertTensorEq(actual, expected, 1e-5)
+ end
+end
+
+
function tests.bilinearUpscale()
local im = outerProduct{1, 2, 4, 2}
local expected = outerProduct{1, 1.5, 2, 3, 4, 3, 2}
- local actual = image.scale(im, expected:size(1), expected:size(2), 'bilinear')
- tester:assertTensorEq(actual, expected, 1e-5)
+ local actual = image.scale(im, expected:size(2), expected:size(1), 'bilinear')
+ assertTensorEq(actual, expected)
end
function tests.bilinearDownscale()
local im = outerProduct{1, 2, 4, 2}
local expected = outerProduct{1.25, 3, 2.5}
- local actual = image.scale(im, expected:size(1), expected:size(2), 'bilinear')
- tester:assertTensorEq(actual, expected, 1e-5)
+ local actual = image.scale(im, expected:size(2), expected:size(1), 'bilinear')
+ assertTensorEq(actual, expected)
end
function tests.bicubicUpscale()
local im = outerProduct{1, 2, 4, 2}
local expected = outerProduct{1, 1.4375, 2, 3.1875, 4, 3.25, 2}
- local actual = image.scale(im, expected:size(1), expected:size(2), 'bicubic')
- tester:assertTensorEq(actual, expected, 1e-5)
+ local actual = image.scale(im, expected:size(2), expected:size(1), 'bicubic')
+ assertTensorEq(actual, expected)
end
function tests.bicubicDownscale()
local im = outerProduct{1, 2, 4, 2}
local expected = outerProduct{1, 3.1875, 2}
- local actual = image.scale(im, expected:size(1), expected:size(2), 'bicubic')
- tester:assertTensorEq(actual, expected, 1e-5)
+ local actual = image.scale(im, expected:size(2), expected:size(1), 'bicubic')
+ assertTensorEq(actual, expected)
+end
+
+
+function tests.bicubicUpscale_ByteTensor()
+ local im = torch.ByteTensor{{0, 1, 32}}
+ local expected = torch.ByteTensor{{0, 0, 9, 32}}
+ local actual = image.scale(im, expected:size(2), expected:size(1), 'bicubic')
+ assertTensorEq(actual, expected)
+end
+
+
+function tests.bilinearUpscale_ByteTensor()
+ local im = torch.ByteTensor{{1, 2},
+ {2, 3}}
+ local expected = torch.ByteTensor{{1, 1, 2},
+ {1, 1, 2},
+ {2, 2, 3}}
+ local actual = image.scale(im, expected:size(2), expected:size(1))
+ assertTensorEq(actual, expected)
end