[arrayfire] 91/284: moved diff, fast, gradient, harris, histogram to kernel namespace
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Sun Feb 7 18:59:22 UTC 2016
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to branch debian/experimental
in repository arrayfire.
commit 71298c69887f23b3f18354098b6cadd62968158b
Author: pradeep <pradeep at arrayfire.com>
Date: Sat Dec 19 00:43:53 2015 -0500
moved diff, fast, gradient, harris, histogram to kernel namespace
---
src/backend/cpu/diff.cpp | 75 +--------
src/backend/cpu/fast.cpp | 227 +-------------------------
src/backend/cpu/gradient.cpp | 69 +-------
src/backend/cpu/harris.cpp | 133 +--------------
src/backend/cpu/histogram.cpp | 32 +---
src/backend/cpu/kernel/diff.hpp | 91 +++++++++++
src/backend/cpu/{fast.cpp => kernel/fast.hpp} | 145 ++--------------
src/backend/cpu/kernel/gradient.hpp | 87 ++++++++++
src/backend/cpu/kernel/harris.hpp | 139 ++++++++++++++++
src/backend/cpu/kernel/histogram.hpp | 47 ++++++
10 files changed, 396 insertions(+), 649 deletions(-)
diff --git a/src/backend/cpu/diff.cpp b/src/backend/cpu/diff.cpp
index 8f9c0f1..3f639ca 100644
--- a/src/backend/cpu/diff.cpp
+++ b/src/backend/cpu/diff.cpp
@@ -9,62 +9,25 @@
#include <Array.hpp>
#include <diff.hpp>
-#include <stdexcept>
-#include <err_cpu.hpp>
#include <platform.hpp>
#include <async_queue.hpp>
+#include <kernel/diff.hpp>
namespace cpu
{
-unsigned getIdx(af::dim4 strides, af::dim4 offs, int i, int j = 0, int k = 0, int l = 0)
-{
- return (l * strides[3] +
- k * strides[2] +
- j * strides[1] +
- i);
-}
-
template<typename T>
Array<T> diff1(const Array<T> &in, const int dim)
{
in.eval();
- // Bool for dimension
- bool is_dim0 = dim == 0;
- bool is_dim1 = dim == 1;
- bool is_dim2 = dim == 2;
- bool is_dim3 = dim == 3;
// Decrement dimension of select dimension
af::dim4 dims = in.dims();
dims[dim]--;
- // Create output placeholder
Array<T> outArray = createEmptyArray<T>(dims);
- auto func = [=] (Array<T> outArray, Array<T> in) {
- // Get pointers to raw data
- const T *inPtr = in.get();
- T *outPtr = outArray.get();
-
- // TODO: Improve this
- for(dim_t l = 0; l < dims[3]; l++) {
- for(dim_t k = 0; k < dims[2]; k++) {
- for(dim_t j = 0; j < dims[1]; j++) {
- for(dim_t i = 0; i < dims[0]; i++) {
- // Operation: out[index] = in[index + 1 * dim_size] - in[index]
- int idx = getIdx(in.strides(), in.offsets(), i, j, k, l);
- int jdx = getIdx(in.strides(), in.offsets(),
- i + is_dim0, j + is_dim1,
- k + is_dim2, l + is_dim3);
- int odx = getIdx(outArray.strides(), outArray.offsets(), i, j, k, l);
- outPtr[odx] = inPtr[jdx] - inPtr[idx];
- }
- }
- }
- }
- };
- getQueue().enqueue(func, outArray, in);
+ getQueue().enqueue(kernel::diff1<T>, outArray, in, dim);
return outArray;
}
@@ -73,46 +36,14 @@ template<typename T>
Array<T> diff2(const Array<T> &in, const int dim)
{
in.eval();
- // Bool for dimension
- bool is_dim0 = dim == 0;
- bool is_dim1 = dim == 1;
- bool is_dim2 = dim == 2;
- bool is_dim3 = dim == 3;
// Decrement dimension of select dimension
af::dim4 dims = in.dims();
dims[dim] -= 2;
- // Create output placeholder
Array<T> outArray = createEmptyArray<T>(dims);
- auto func = [=] (Array<T> outArray, Array<T> in) {
- // Get pointers to raw data
- const T *inPtr = in.get();
- T *outPtr = outArray.get();
-
- // TODO: Improve this
- for(dim_t l = 0; l < dims[3]; l++) {
- for(dim_t k = 0; k < dims[2]; k++) {
- for(dim_t j = 0; j < dims[1]; j++) {
- for(dim_t i = 0; i < dims[0]; i++) {
- // Operation: out[index] = in[index + 1 * dim_size] - in[index]
- int idx = getIdx(in.strides(), in.offsets(), i, j, k, l);
- int jdx = getIdx(in.strides(), in.offsets(),
- i + is_dim0, j + is_dim1,
- k + is_dim2, l + is_dim3);
- int kdx = getIdx(in.strides(), in.offsets(),
- i + 2 * is_dim0, j + 2 * is_dim1,
- k + 2 * is_dim2, l + 2 * is_dim3);
- int odx = getIdx(outArray.strides(), outArray.offsets(), i, j, k, l);
- outPtr[odx] = inPtr[kdx] + inPtr[idx] - inPtr[jdx] - inPtr[jdx];
- }
- }
- }
- }
- };
-
- getQueue().enqueue(func, outArray, in);
+ getQueue().enqueue(kernel::diff2<T>, outArray, in, dim);
return outArray;
}
diff --git a/src/backend/cpu/fast.cpp b/src/backend/cpu/fast.cpp
index c8b0514..fe02387 100644
--- a/src/backend/cpu/fast.cpp
+++ b/src/backend/cpu/fast.cpp
@@ -16,234 +16,13 @@
#include <fast.hpp>
#include <platform.hpp>
#include <async_queue.hpp>
+#include <kernel/fast.hpp>
using af::dim4;
namespace cpu
{
-inline int clamp(int f, int a, int b)
-{
- return std::max(a, std::min(f, b));
-}
-
-inline int idx_y(int i)
-{
- if (i >= 8)
- return clamp(-(i-8-4), -3, 3);
-
- return clamp(i-4, -3, 3);
-}
-
-inline int idx_x(int i)
-{
- if (i < 12)
- return idx_y(i+4);
-
- return idx_y(i-12);
-}
-
-inline int idx(int y, int x, unsigned idim0)
-{
- return x * idim0 + y;
-}
-
-// test_greater()
-// Tests if a pixel x > p + thr
-inline int test_greater(float x, float p, float thr)
-{
- return (x >= p + thr);
-}
-
-// test_smaller()
-// Tests if a pixel x < p - thr
-inline int test_smaller(float x, float p, float thr)
-{
- return (x <= p - thr);
-}
-
-// test_pixel()
-// Returns -1 when x < p - thr
-// Returns 0 when x >= p - thr && x <= p + thr
-// Returns 1 when x > p + thr
-template<typename T>
-inline int test_pixel(const T* image, const float p, float thr, int y, int x, unsigned idim0)
-{
- return -test_smaller((float)image[idx(y,x,idim0)], p, thr) | test_greater((float)image[idx(y,x,idim0)], p, thr);
-}
-
-// abs_diff()
-// Returns absolute difference of x and y
-inline int abs_diff(int x, int y)
-{
- return abs(x - y);
-}
-inline unsigned abs_diff(unsigned x, unsigned y)
-{
- return (unsigned)abs((int)x - (int)y);
-}
-inline float abs_diff(float x, float y)
-{
- return fabs(x - y);
-}
-inline double abs_diff(double x, double y)
-{
- return fabs(x - y);
-}
-
-template<typename T>
-void locate_features(
- const Array<T> &in,
- Array<float> &score,
- Array<float> &x_out,
- Array<float> &y_out,
- Array<float> &score_out,
- unsigned* count,
- const float thr,
- const unsigned arc_length,
- const unsigned nonmax,
- const unsigned max_feat,
- const unsigned edge)
-{
- dim4 in_dims = in.dims();
- const T* in_ptr = in.get();
-
- for (int y = edge; y < (int)(in_dims[0] - edge); y++) {
- for (int x = edge; x < (int)(in_dims[1] - edge); x++) {
- float p = in_ptr[idx(y, x, in_dims[0])];
-
- // Start by testing opposite pixels of the circle that will result in
- // a non-kepoint
- int d;
- d = test_pixel<T>(in_ptr, p, thr, y-3, x, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y+3, x, in_dims[0]);
- if (d == 0)
- continue;
-
- d &= test_pixel<T>(in_ptr, p, thr, y-2, x+2, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y+2, x-2, in_dims[0]);
- d &= test_pixel<T>(in_ptr, p, thr, y , x+3, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y , x-3, in_dims[0]);
- d &= test_pixel<T>(in_ptr, p, thr, y+2, x+2, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y-2, x-2, in_dims[0]);
- if (d == 0)
- continue;
-
- d &= test_pixel<T>(in_ptr, p, thr, y-3, x+1, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y+3, x-1, in_dims[0]);
- d &= test_pixel<T>(in_ptr, p, thr, y-1, x+3, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y+1, x-3, in_dims[0]);
- d &= test_pixel<T>(in_ptr, p, thr, y+1, x+3, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y-1, x-3, in_dims[0]);
- d &= test_pixel<T>(in_ptr, p, thr, y+3, x+1, in_dims[0]) | test_pixel<T>(in_ptr, p, thr, y-3, x-1, in_dims[0]);
- if (d == 0)
- continue;
-
- int sum = 0;
-
- // Sum responses [-1, 0 or 1] of first arc_length pixels
- for (int i = 0; i < static_cast<int>(arc_length); i++)
- sum += test_pixel<T>(in_ptr, p, thr, y+idx_y(i), x+idx_x(i), in_dims[0]);
-
- // Test maximum and mininmum responses of first segment of arc_length
- // pixels
- int max_sum = 0, min_sum = 0;
- max_sum = std::max(max_sum, sum);
- min_sum = std::min(min_sum, sum);
-
- // Sum responses and test the remaining 16-arc_length pixels of the circle
- for (int i = arc_length; i < 16; i++) {
- sum -= test_pixel<T>(in_ptr, p, thr, y+idx_y(i-arc_length), x+idx_x(i-arc_length), in_dims[0]);
- sum += test_pixel<T>(in_ptr, p, thr, y+idx_y(i), x+idx_x(i), in_dims[0]);
- max_sum = std::max(max_sum, sum);
- min_sum = std::min(min_sum, sum);
- }
-
- // To completely test all possible segments, it's necessary to test
- // segments that include the top junction of the circle
- for (int i = 0; i < static_cast<int>(arc_length-1); i++) {
- sum -= test_pixel<T>(in_ptr, p, thr, y+idx_y(16-arc_length+i), x+idx_x(16-arc_length+i), in_dims[0]);
- sum += test_pixel<T>(in_ptr, p, thr, y+idx_y(i), x+idx_x(i), in_dims[0]);
- max_sum = std::max(max_sum, sum);
- min_sum = std::min(min_sum, sum);
- }
-
- float s_bright = 0, s_dark = 0;
- for (int i = 0; i < 16; i++) {
- float p_x = (float)in_ptr[idx(y+idx_y(i), x+idx_x(i), in_dims[0])];
-
- s_bright += test_greater(p_x, p, thr) * (abs_diff(p_x, p) - thr);
- s_dark += test_smaller(p_x, p, thr) * (abs_diff(p, p_x) - thr);
- }
-
- // If sum at some point was equal to (+-)arc_length, there is a segment
- // that for which all pixels are much brighter or much brighter than
- // central pixel p.
- if (max_sum == static_cast<int>(arc_length) || min_sum == -static_cast<int>(arc_length)) {
- unsigned j = *count;
- ++*count;
- if (j < max_feat) {
- float *x_out_ptr = x_out.get();
- float *y_out_ptr = y_out.get();
- float *score_out_ptr = score_out.get();
- x_out_ptr[j] = static_cast<float>(x);
- y_out_ptr[j] = static_cast<float>(y);
- score_out_ptr[j] = static_cast<float>(std::max(s_bright, s_dark));
- if (nonmax == 1) {
- float* score_ptr = score.get();
- score_ptr[idx(y, x, in_dims[0])] = std::max(s_bright, s_dark);
- }
- }
- }
- }
- }
-}
-
-void non_maximal(
- const Array<float> &score,
- const Array<float> &x_in,
- const Array<float> &y_in,
- Array<float> &x_out,
- Array<float> &y_out,
- Array<float> &score_out,
- unsigned* count,
- const unsigned total_feat,
- const unsigned edge)
-{
- const float *score_ptr = score.get();
- const float *x_in_ptr = x_in.get();
- const float *y_in_ptr = y_in.get();
-
- dim4 score_dims = score.dims();
-
- for (unsigned k = 0; k < total_feat; k++) {
- unsigned x = static_cast<unsigned>(round(x_in_ptr[k]));
- unsigned y = static_cast<unsigned>(round(y_in_ptr[k]));
-
- float v = score_ptr[y + score_dims[0] * x];
- float max_v;
- max_v = std::max(score_ptr[y-1 + score_dims[0] * (x-1)], score_ptr[y-1 + score_dims[0] * x]);
- max_v = std::max(max_v, score_ptr[y-1 + score_dims[0] * (x+1)]);
- max_v = std::max(max_v, score_ptr[y + score_dims[0] * (x-1)]);
- max_v = std::max(max_v, score_ptr[y + score_dims[0] * (x+1)]);
- max_v = std::max(max_v, score_ptr[y+1 + score_dims[0] * (x-1)]);
- max_v = std::max(max_v, score_ptr[y+1 + score_dims[0] * (x) ]);
- max_v = std::max(max_v, score_ptr[y+1 + score_dims[0] * (x+1)]);
-
- if (y >= score_dims[1] - edge - 1 || y <= edge + 1 ||
- x >= score_dims[0] - edge - 1 || x <= edge + 1)
- continue;
-
- // Stores keypoint to feat_out if it's response is maximum compared to
- // its 8-neighborhood
- if (v > max_v) {
- unsigned j = *count;
- ++*count;
-
- float *x_out_ptr = x_out.get();
- float *y_out_ptr = y_out.get();
- float *score_out_ptr = score_out.get();
-
- x_out_ptr[j] = static_cast<float>(x);
- y_out_ptr[j] = static_cast<float>(y);
- score_out_ptr[j] = static_cast<float>(v);
- }
- }
-}
-
template<typename T>
unsigned fast(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
const Array<T> &in, const float thr, const unsigned arc_length,
@@ -274,7 +53,7 @@ unsigned fast(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
// Feature counter
unsigned count = 0;
- locate_features<T>(in, V, x, y, score, &count, thr, arc_length,
+ kernel::locate_features<T>(in, V, x, y, score, &count, thr, arc_length,
nonmax, max_feat, edge);
// If more features than max_feat were detected, feat wasn't populated
@@ -293,7 +72,7 @@ unsigned fast(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
score_total = createEmptyArray<float>(feat_found_dims);
count = 0;
- non_maximal(V, x, y,
+ kernel::non_maximal(V, x, y,
x_total, y_total, score_total,
&count, feat_found, edge);
diff --git a/src/backend/cpu/gradient.cpp b/src/backend/cpu/gradient.cpp
index 06c15cf..d1a8b0d 100644
--- a/src/backend/cpu/gradient.cpp
+++ b/src/backend/cpu/gradient.cpp
@@ -14,6 +14,7 @@
#include <err_cpu.hpp>
#include <platform.hpp>
#include <async_queue.hpp>
+#include <kernel/gradient.hpp>
namespace cpu
{
@@ -25,73 +26,7 @@ void gradient(Array<T> &grad0, Array<T> &grad1, const Array<T> &in)
grad1.eval();
in.eval();
- auto func = [=] (Array<T> grad0, Array<T> grad1, const Array<T> in) {
- const af::dim4 dims = in.dims();
-
- T *d_grad0 = grad0.get();
- T *d_grad1 = grad1.get();
- const T *d_in = in.get();
-
- const af::dim4 inst = in.strides();
- const af::dim4 g0st = grad0.strides();
- const af::dim4 g1st = grad1.strides();
-
- T v5 = scalar<T>(0.5);
- T v1 = scalar<T>(1.0);
-
- for(dim_t idw = 0; idw < dims[3]; idw++) {
- const dim_t inW = idw * inst[3];
- const dim_t g0W = idw * g0st[3];
- const dim_t g1W = idw * g1st[3];
- for(dim_t idz = 0; idz < dims[2]; idz++) {
- const dim_t inZW = inW + idz * inst[2];
- const dim_t g0ZW = g0W + idz * g0st[2];
- const dim_t g1ZW = g1W + idz * g1st[2];
- dim_t xl, xr, yl,yr;
- T f0, f1;
- for(dim_t idy = 0; idy < dims[1]; idy++) {
- const dim_t inYZW = inZW + idy * inst[1];
- const dim_t g0YZW = g0ZW + idy * g0st[1];
- const dim_t g1YZW = g1ZW + idy * g1st[1];
- if(idy == 0) {
- yl = inYZW + inst[1];
- yr = inYZW;
- f1 = v1;
- } else if(idy == dims[1] - 1) {
- yl = inYZW;
- yr = inYZW - inst[1];
- f1 = v1;
- } else {
- yl = inYZW + inst[1];
- yr = inYZW - inst[1];
- f1 = v5;
- }
- for(dim_t idx = 0; idx < dims[0]; idx++) {
- const dim_t inMem = inYZW + idx;
- const dim_t g0Mem = g0YZW + idx;
- const dim_t g1Mem = g1YZW + idx;
- if(idx == 0) {
- xl = inMem + 1;
- xr = inMem;
- f0 = v1;
- } else if(idx == dims[0] - 1) {
- xl = inMem;
- xr = inMem - 1;
- f0 = v1;
- } else {
- xl = inMem + 1;
- xr = inMem - 1;
- f0 = v5;
- }
-
- d_grad0[g0Mem] = f0 * (d_in[xl] - d_in[xr]);
- d_grad1[g1Mem] = f1 * (d_in[yl + idx] - d_in[yr + idx]);
- }
- }
- }
- }
- };
- getQueue().enqueue(func, grad0, grad1, in);
+ getQueue().enqueue(kernel::gradient<T>, grad0, grad1, in);
}
#define INSTANTIATE(T) \
diff --git a/src/backend/cpu/harris.cpp b/src/backend/cpu/harris.cpp
index b57b940..e5ff906 100644
--- a/src/backend/cpu/harris.cpp
+++ b/src/backend/cpu/harris.cpp
@@ -12,7 +12,6 @@
#include <af/constants.h>
#include <ArrayInfo.hpp>
#include <Array.hpp>
-#include <err_cpu.hpp>
#include <handle.hpp>
#include <harris.hpp>
#include <convolve.hpp>
@@ -21,133 +20,13 @@
#include <cstring>
#include <platform.hpp>
#include <async_queue.hpp>
+#include <kernel/harris.hpp>
using af::dim4;
namespace cpu
{
-template<typename T>
-void gaussian1D(T* out, const int dim, double sigma=0.0)
-{
- if(!(sigma>0)) sigma = 0.25*dim;
-
- T sum = (T)0;
- for(int i=0;i<dim;i++)
- {
- int x = i-(dim-1)/2;
- T el = 1. / sqrt(2 * af::Pi * sigma*sigma) * exp(-((x*x)/(2*(sigma*sigma))));
- out[i] = el;
- sum += el;
- }
-
- for(int k=0;k<dim;k++)
- out[k] /= sum;
-}
-
-template<typename T>
-void second_order_deriv(Array<T> ixx, Array<T> ixy, Array<T> iyy,
- const unsigned in_len, const Array<T> ix, const Array<T> iy)
-{
- T* ixx_out = ixx.get();
- T* ixy_out = ixy.get();
- T* iyy_out = iyy.get();
- const T* ix_in = ix.get();
- const T* iy_in = iy.get();
- for (unsigned x = 0; x < in_len; x++) {
- ixx_out[x] = ix_in[x] * ix_in[x];
- ixy_out[x] = ix_in[x] * iy_in[x];
- iyy_out[x] = iy_in[x] * iy_in[x];
- }
-}
-
-template<typename T>
-void harris_responses(Array<T> resp, const unsigned idim0, const unsigned idim1,
- const Array<T> ixx, const Array<T> ixy, const Array<T> iyy,
- const float k_thr, const unsigned border_len)
-{
- T* resp_out = resp.get();
- const T* ixx_in = ixx.get();
- const T* ixy_in = ixy.get();
- const T* iyy_in = iyy.get();
- const unsigned r = border_len;
-
- for (unsigned x = r; x < idim1 - r; x++) {
- for (unsigned y = r; y < idim0 - r; y++) {
- const unsigned idx = x * idim0 + y;
-
- // Calculates matrix trace and determinant
- T tr = ixx_in[idx] + iyy_in[idx];
- T det = ixx_in[idx] * iyy_in[idx] - ixy_in[idx] * ixy_in[idx];
-
- // Calculates local Harris response
- resp_out[idx] = det - k_thr * (tr*tr);
- }
- }
-}
-
-template<typename T>
-void non_maximal(Array<float> xOut, Array<float> yOut, Array<float> respOut, unsigned* count,
- const unsigned idim0, const unsigned idim1, const Array<T> respIn,
- const float min_resp, const unsigned border_len, const unsigned max_corners)
-{
- float* x_out = xOut.get();
- float* y_out = yOut.get();
- float* resp_out = respOut.get();
- const T* resp_in = respIn.get();
- // Responses on the border don't have 8-neighbors to compare, discard them
- const unsigned r = border_len + 1;
-
- for (unsigned x = r; x < idim1 - r; x++) {
- for (unsigned y = r; y < idim0 - r; y++) {
- const T v = resp_in[x * idim0 + y];
-
- // Find maximum neighborhood response
- T max_v;
- max_v = max(resp_in[(x-1) * idim0 + y-1], resp_in[x * idim0 + y-1]);
- max_v = max(max_v, resp_in[(x+1) * idim0 + y-1]);
- max_v = max(max_v, resp_in[(x-1) * idim0 + y ]);
- max_v = max(max_v, resp_in[(x+1) * idim0 + y ]);
- max_v = max(max_v, resp_in[(x-1) * idim0 + y+1]);
- max_v = max(max_v, resp_in[(x) * idim0 + y+1]);
- max_v = max(max_v, resp_in[(x+1) * idim0 + y+1]);
-
- // Stores corner to {x,y,resp}_out if it's response is maximum compared
- // to its 8-neighborhood and greater or equal minimum response
- if (v > max_v && v >= (T)min_resp) {
- const unsigned idx = *count;
- *count += 1;
- if (idx < max_corners) {
- x_out[idx] = (float)x;
- y_out[idx] = (float)y;
- resp_out[idx] = (float)v;
- }
- }
- }
- }
-}
-
-static void keep_corners(Array<float> xOut, Array<float> yOut, Array<float> respOut,
- const Array<float> xIn, const Array<float> yIn,
- const Array<float> respIn, const Array<unsigned> respIdx,
- const unsigned n_corners)
-{
- float* x_out = xOut.get();
- float* y_out = yOut.get();
- float* resp_out = respOut.get();
- const float* x_in = xIn.get();
- const float* y_in = yIn.get();
- const float* resp_in = respIn.get();
- const uint* resp_idx = respIdx.get();
-
- // Keep only the first n_feat features
- for (unsigned f = 0; f < n_corners; f++) {
- x_out[f] = x_in[resp_idx[f]];
- y_out[f] = y_in[resp_idx[f]];
- resp_out[f] = resp_in[f];
- }
-}
-
template<typename T, typename convAccT>
unsigned harris(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out,
const Array<T> &in, const unsigned max_corners, const float min_response,
@@ -164,7 +43,7 @@ unsigned harris(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out
for (unsigned i = 0; i < filter_len; i++)
h_filter[i] = (T)1.f / (filter_len);
} else {
- gaussian1D<convAccT>(h_filter, (int)filter_len, sigma);
+ kernel::gaussian1D<convAccT>(h_filter, (int)filter_len, sigma);
}
Array<convAccT> filter = createDeviceDataArray<convAccT>(dim4(filter_len), (const void*)h_filter);
@@ -181,7 +60,7 @@ unsigned harris(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out
Array<T> iyy = createEmptyArray<T>(idims);
// Compute second-order derivatives
- getQueue().enqueue(second_order_deriv<T>, ixx, ixy, iyy, in.elements(), ix, iy);
+ getQueue().enqueue(kernel::second_order_deriv<T>, ixx, ixy, iyy, in.elements(), ix, iy);
// Convolve second-order derivatives with proper window filter
ixx = convolve2<T, convAccT, false>(ixx, filter, filter);
@@ -192,7 +71,7 @@ unsigned harris(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out
Array<T> responses = createEmptyArray<T>(dim4(in.elements()));
- getQueue().enqueue(harris_responses<T>, responses, idims[0], idims[1],
+ getQueue().enqueue(kernel::harris_responses<T>, responses, idims[0], idims[1],
ixx, ixy, iyy, k_thr, border_len);
Array<float> xCorners = createEmptyArray<float>(dim4(corner_lim));
@@ -204,7 +83,7 @@ unsigned harris(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out
// Performs non-maximal suppression
getQueue().sync();
unsigned corners_found = 0;
- non_maximal<T>(xCorners, yCorners, respCorners, &corners_found,
+ kernel::non_maximal<T>(xCorners, yCorners, respCorners, &corners_found,
idims[0], idims[1], responses, min_r, border_len, corner_lim);
const unsigned corners_out = (max_corners > 0) ?
@@ -226,7 +105,7 @@ unsigned harris(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out
resp_out = createEmptyArray<float>(dim4(corners_out));
// Keep only the corners with higher Harris responses
- getQueue().enqueue(keep_corners, x_out, y_out, resp_out, xCorners, yCorners,
+ getQueue().enqueue(kernel::keep_corners, x_out, y_out, resp_out, xCorners, yCorners,
harris_sorted, harris_idx, corners_out);
} else if (max_corners == 0 && corners_found < corner_lim) {
x_out = createEmptyArray<float>(dim4(corners_out));
diff --git a/src/backend/cpu/histogram.cpp b/src/backend/cpu/histogram.cpp
index 8fb3e43..7e20247 100644
--- a/src/backend/cpu/histogram.cpp
+++ b/src/backend/cpu/histogram.cpp
@@ -14,6 +14,7 @@
#include <histogram.hpp>
#include <platform.hpp>
#include <async_queue.hpp>
+#include <kernel/histogram.hpp>
using af::dim4;
@@ -21,7 +22,8 @@ namespace cpu
{
template<typename inType, typename outType, bool isLinear>
-Array<outType> histogram(const Array<inType> &in, const unsigned &nbins, const double &minval, const double &maxval)
+Array<outType> histogram(const Array<inType> &in,
+ const unsigned &nbins, const double &minval, const double &maxval)
{
in.eval();
@@ -30,32 +32,8 @@ Array<outType> histogram(const Array<inType> &in, const unsigned &nbins, const d
Array<outType> out = createValueArray<outType>(outDims, outType(0));
out.eval();
- auto func = [=](Array<outType> out, const Array<inType> in,
- const unsigned nbins, const double minval, const double maxval) {
- const float step = (maxval - minval)/(float)nbins;
- const dim4 inDims = in.dims();
- const dim4 iStrides = in.strides();
- const dim4 oStrides = out.strides();
- const dim_t nElems = inDims[0]*inDims[1];
-
- outType *outData = out.get();
- const inType* inData= in.get();
-
- for(dim_t b3 = 0; b3 < outDims[3]; b3++) {
- for(dim_t b2 = 0; b2 < outDims[2]; b2++) {
- for(dim_t i=0; i<nElems; i++) {
- int idx = isLinear ? i : ((i % inDims[0]) + (i / inDims[0])*iStrides[1]);
- int bin = (int)((inData[idx] - minval) / step);
- bin = std::max(bin, 0);
- bin = std::min(bin, (int)(nbins - 1));
- outData[bin]++;
- }
- inData += iStrides[2];
- outData += oStrides[2];
- }
- }
- };
- getQueue().enqueue(func, out, in, nbins, minval, maxval);
+ getQueue().enqueue(kernel::histogram<inType, outType, isLinear>,
+ out, in, nbins, minval, maxval);
return out;
}
diff --git a/src/backend/cpu/kernel/diff.hpp b/src/backend/cpu/kernel/diff.hpp
new file mode 100644
index 0000000..e0693b1
--- /dev/null
+++ b/src/backend/cpu/kernel/diff.hpp
@@ -0,0 +1,91 @@
+/*******************************************************
+ * Copyright (c) 2015, ArrayFire
+ * All rights reserved.
+ *
+ * This file is distributed under 3-clause BSD license.
+ * The complete license agreement can be obtained at:
+ * http://arrayfire.com/licenses/BSD-3-Clause
+ ********************************************************/
+
+#include <Array.hpp>
+
+namespace cpu
+{
+namespace kernel
+{
+
+unsigned getIdx(af::dim4 strides, af::dim4 offs, int i, int j = 0, int k = 0, int l = 0)
+{
+ return (l * strides[3] + k * strides[2] + j * strides[1] + i);
+}
+
+
+template<typename T>
+void diff1(Array<T> out, Array<T> const in, int const dim)
+{
+ af::dim4 dims = out.dims();
+ // Bool for dimension
+ bool is_dim0 = dim == 0;
+ bool is_dim1 = dim == 1;
+ bool is_dim2 = dim == 2;
+ bool is_dim3 = dim == 3;
+
+ // Get pointers to raw data
+ const T *inPtr = in.get();
+ T *outPtr = out.get();
+
+ // TODO: Improve this
+ for(dim_t l = 0; l < dims[3]; l++) {
+ for(dim_t k = 0; k < dims[2]; k++) {
+ for(dim_t j = 0; j < dims[1]; j++) {
+ for(dim_t i = 0; i < dims[0]; i++) {
+ // Operation: out[index] = in[index + 1 * dim_size] - in[index]
+ int idx = getIdx(in.strides(), in.offsets(), i, j, k, l);
+ int jdx = getIdx(in.strides(), in.offsets(),
+ i + is_dim0, j + is_dim1,
+ k + is_dim2, l + is_dim3);
+ int odx = getIdx(out.strides(), out.offsets(), i, j, k, l);
+ outPtr[odx] = inPtr[jdx] - inPtr[idx];
+ }
+ }
+ }
+ }
+}
+
+template<typename T>
+void diff2(Array<T> out, Array<T> const in, int const dim)
+{
+ af::dim4 dims = out.dims();
+ // Bool for dimension
+ bool is_dim0 = dim == 0;
+ bool is_dim1 = dim == 1;
+ bool is_dim2 = dim == 2;
+ bool is_dim3 = dim == 3;
+
+ // Get pointers to raw data
+ const T *inPtr = in.get();
+ T *outPtr = out.get();
+
+ // TODO: Improve this
+ for(dim_t l = 0; l < dims[3]; l++) {
+ for(dim_t k = 0; k < dims[2]; k++) {
+ for(dim_t j = 0; j < dims[1]; j++) {
+ for(dim_t i = 0; i < dims[0]; i++) {
+ // Operation: out[index] = in[index + 1 * dim_size] - in[index]
+ int idx = getIdx(in.strides(), in.offsets(), i, j, k, l);
+ int jdx = getIdx(in.strides(), in.offsets(),
+ i + is_dim0, j + is_dim1,
+ k + is_dim2, l + is_dim3);
+ int kdx = getIdx(in.strides(), in.offsets(),
+ i + 2 * is_dim0, j + 2 * is_dim1,
+ k + 2 * is_dim2, l + 2 * is_dim3);
+ int odx = getIdx(out.strides(), out.offsets(), i, j, k, l);
+ outPtr[odx] = inPtr[kdx] + inPtr[idx] - inPtr[jdx] - inPtr[jdx];
+ }
+ }
+ }
+ }
+}
+
+}
+}
diff --git a/src/backend/cpu/fast.cpp b/src/backend/cpu/kernel/fast.hpp
similarity index 64%
copy from src/backend/cpu/fast.cpp
copy to src/backend/cpu/kernel/fast.hpp
index c8b0514..a3971dd 100644
--- a/src/backend/cpu/fast.cpp
+++ b/src/backend/cpu/kernel/fast.hpp
@@ -1,5 +1,5 @@
/*******************************************************
- * Copyright (c) 2014, ArrayFire
+ * Copyright (c) 2015, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
@@ -7,20 +7,14 @@
* http://arrayfire.com/licenses/BSD-3-Clause
********************************************************/
-#include <af/dim4.hpp>
-#include <af/defines.h>
-#include <ArrayInfo.hpp>
#include <Array.hpp>
-#include <err_cpu.hpp>
-#include <handle.hpp>
-#include <fast.hpp>
-#include <platform.hpp>
-#include <async_queue.hpp>
-
-using af::dim4;
namespace cpu
{
+namespace kernel
+{
+
+using af::dim4;
inline int clamp(int f, int a, int b)
{
@@ -92,18 +86,11 @@ inline double abs_diff(double x, double y)
}
template<typename T>
-void locate_features(
- const Array<T> &in,
- Array<float> &score,
- Array<float> &x_out,
- Array<float> &y_out,
- Array<float> &score_out,
- unsigned* count,
- const float thr,
- const unsigned arc_length,
- const unsigned nonmax,
- const unsigned max_feat,
- const unsigned edge)
+void locate_features(const Array<T> &in, Array<float> &score,
+ Array<float> &x_out, Array<float> &y_out,
+ Array<float> &score_out, unsigned* count, const float thr,
+ const unsigned arc_length, const unsigned nonmax,
+ const unsigned max_feat, const unsigned edge)
{
dim4 in_dims = in.dims();
const T* in_ptr = in.get();
@@ -192,16 +179,9 @@ void locate_features(
}
}
-void non_maximal(
- const Array<float> &score,
- const Array<float> &x_in,
- const Array<float> &y_in,
- Array<float> &x_out,
- Array<float> &y_out,
- Array<float> &score_out,
- unsigned* count,
- const unsigned total_feat,
- const unsigned edge)
+void non_maximal(const Array<float> &score, const Array<float> &x_in, const Array<float> &y_in,
+ Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
+ unsigned* count, const unsigned total_feat, const unsigned edge)
{
const float *score_ptr = score.get();
const float *x_in_ptr = x_in.get();
@@ -244,104 +224,5 @@ void non_maximal(
}
}
-template<typename T>
-unsigned fast(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
- const Array<T> &in, const float thr, const unsigned arc_length,
- const bool nonmax, const float feature_ratio,
- const unsigned edge)
-{
- in.eval();
- getQueue().sync();
-
- dim4 in_dims = in.dims();
- const unsigned max_feat = ceil(in.elements() * feature_ratio);
-
- // Matrix containing scores for detected features, scores are stored in the
- // same coordinates as features, dimensions should be equal to in.
- Array<float> V = createEmptyArray<float>(dim4());
- if (nonmax == 1) {
- dim4 V_dims(in_dims[0], in_dims[1]);
- V = createValueArray<float>(V_dims, (float)0);
- V.eval();
- }
-
- // Arrays containing all features detected before non-maximal suppression.
- dim4 max_feat_dims(max_feat);
- Array<float> x = createEmptyArray<float>(max_feat_dims);
- Array<float> y = createEmptyArray<float>(max_feat_dims);
- Array<float> score = createEmptyArray<float>(max_feat_dims);
-
- // Feature counter
- unsigned count = 0;
-
- locate_features<T>(in, V, x, y, score, &count, thr, arc_length,
- nonmax, max_feat, edge);
-
- // If more features than max_feat were detected, feat wasn't populated
- // with them anyway, so the real number of features will be that of
- // max_feat and not count.
- unsigned feat_found = std::min(max_feat, count);
- dim4 feat_found_dims(feat_found);
-
- Array<float> x_total = createEmptyArray<float>(af::dim4());
- Array<float> y_total = createEmptyArray<float>(af::dim4());
- Array<float> score_total = createEmptyArray<float>(af::dim4());
-
- if (nonmax == 1) {
- x_total = createEmptyArray<float>(feat_found_dims);
- y_total = createEmptyArray<float>(feat_found_dims);
- score_total = createEmptyArray<float>(feat_found_dims);
-
- count = 0;
- non_maximal(V, x, y,
- x_total, y_total, score_total,
- &count, feat_found, edge);
-
- feat_found = std::min(max_feat, count);
- } else {
- x_total = x;
- y_total = y;
- score_total = score;
- }
-
- if (feat_found > 0) {
- feat_found_dims = dim4(feat_found);
-
- x_out = createEmptyArray<float>(feat_found_dims);
- y_out = createEmptyArray<float>(feat_found_dims);
- score_out = createEmptyArray<float>(feat_found_dims);
-
- float *x_total_ptr = x_total.get();
- float *y_total_ptr = y_total.get();
- float *score_total_ptr = score_total.get();
-
-
- float *x_out_ptr = x_out.get();
- float *y_out_ptr = y_out.get();
- float *score_out_ptr = score_out.get();
-
- for (size_t i = 0; i < feat_found; i++) {
- x_out_ptr[i] = x_total_ptr[i];
- y_out_ptr[i] = y_total_ptr[i];
- score_out_ptr[i] = score_total_ptr[i];
- }
- }
-
- return feat_found;
}
-
-#define INSTANTIATE(T) \
- template unsigned fast<T>(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out, \
- const Array<T> &in, const float thr, const unsigned arc_length, \
- const bool nonmax, const float feature_ratio, const unsigned edge);
-
-INSTANTIATE(float )
-INSTANTIATE(double)
-INSTANTIATE(char )
-INSTANTIATE(int )
-INSTANTIATE(uint )
-INSTANTIATE(uchar )
-INSTANTIATE(short )
-INSTANTIATE(ushort)
-
}
diff --git a/src/backend/cpu/kernel/gradient.hpp b/src/backend/cpu/kernel/gradient.hpp
new file mode 100644
index 0000000..c152fb3
--- /dev/null
+++ b/src/backend/cpu/kernel/gradient.hpp
@@ -0,0 +1,87 @@
+/*******************************************************
+ * Copyright (c) 2014, ArrayFire
+ * All rights reserved.
+ *
+ * This file is distributed under 3-clause BSD license.
+ * The complete license agreement can be obtained at:
+ * http://arrayfire.com/licenses/BSD-3-Clause
+ ********************************************************/
+
+#include <Array.hpp>
+
+namespace cpu
+{
+namespace kernel
+{
+
+template<typename T>
+void gradient(Array<T> grad0, Array<T> grad1, Array<T> const in)
+{
+ const af::dim4 dims = in.dims();
+
+ T *d_grad0 = grad0.get();
+ T *d_grad1 = grad1.get();
+ const T *d_in = in.get();
+
+ const af::dim4 inst = in.strides();
+ const af::dim4 g0st = grad0.strides();
+ const af::dim4 g1st = grad1.strides();
+
+ T v5 = scalar<T>(0.5);
+ T v1 = scalar<T>(1.0);
+
+ for(dim_t idw = 0; idw < dims[3]; idw++) {
+ const dim_t inW = idw * inst[3];
+ const dim_t g0W = idw * g0st[3];
+ const dim_t g1W = idw * g1st[3];
+ for(dim_t idz = 0; idz < dims[2]; idz++) {
+ const dim_t inZW = inW + idz * inst[2];
+ const dim_t g0ZW = g0W + idz * g0st[2];
+ const dim_t g1ZW = g1W + idz * g1st[2];
+ dim_t xl, xr, yl,yr;
+ T f0, f1;
+ for(dim_t idy = 0; idy < dims[1]; idy++) {
+ const dim_t inYZW = inZW + idy * inst[1];
+ const dim_t g0YZW = g0ZW + idy * g0st[1];
+ const dim_t g1YZW = g1ZW + idy * g1st[1];
+ if(idy == 0) {
+ yl = inYZW + inst[1];
+ yr = inYZW;
+ f1 = v1;
+ } else if(idy == dims[1] - 1) {
+ yl = inYZW;
+ yr = inYZW - inst[1];
+ f1 = v1;
+ } else {
+ yl = inYZW + inst[1];
+ yr = inYZW - inst[1];
+ f1 = v5;
+ }
+ for(dim_t idx = 0; idx < dims[0]; idx++) {
+ const dim_t inMem = inYZW + idx;
+ const dim_t g0Mem = g0YZW + idx;
+ const dim_t g1Mem = g1YZW + idx;
+ if(idx == 0) {
+ xl = inMem + 1;
+ xr = inMem;
+ f0 = v1;
+ } else if(idx == dims[0] - 1) {
+ xl = inMem;
+ xr = inMem - 1;
+ f0 = v1;
+ } else {
+ xl = inMem + 1;
+ xr = inMem - 1;
+ f0 = v5;
+ }
+
+ d_grad0[g0Mem] = f0 * (d_in[xl] - d_in[xr]);
+ d_grad1[g1Mem] = f1 * (d_in[yl + idx] - d_in[yr + idx]);
+ }
+ }
+ }
+ }
+}
+
+}
+}
diff --git a/src/backend/cpu/kernel/harris.hpp b/src/backend/cpu/kernel/harris.hpp
new file mode 100644
index 0000000..db6551b
--- /dev/null
+++ b/src/backend/cpu/kernel/harris.hpp
@@ -0,0 +1,139 @@
+/*******************************************************
+ * Copyright (c) 2015, ArrayFire
+ * All rights reserved.
+ *
+ * This file is distributed under 3-clause BSD license.
+ * The complete license agreement can be obtained at:
+ * http://arrayfire.com/licenses/BSD-3-Clause
+ ********************************************************/
+
+#include <Array.hpp>
+
+namespace cpu
+{
+namespace kernel
+{
+
+template<typename T>
+void gaussian1D(T* out, const int dim, double sigma=0.0)
+{
+ if(!(sigma>0)) sigma = 0.25*dim;
+
+ T sum = (T)0;
+ for(int i=0;i<dim;i++)
+ {
+ int x = i-(dim-1)/2;
+ T el = 1. / sqrt(2 * af::Pi * sigma*sigma) * exp(-((x*x)/(2*(sigma*sigma))));
+ out[i] = el;
+ sum += el;
+ }
+
+ for(int k=0;k<dim;k++)
+ out[k] /= sum;
+}
+
+template<typename T>
+void second_order_deriv(Array<T> ixx, Array<T> ixy, Array<T> iyy,
+ const unsigned in_len, const Array<T> ix, const Array<T> iy)
+{
+ T* ixx_out = ixx.get();
+ T* ixy_out = ixy.get();
+ T* iyy_out = iyy.get();
+ const T* ix_in = ix.get();
+ const T* iy_in = iy.get();
+ for (unsigned x = 0; x < in_len; x++) {
+ ixx_out[x] = ix_in[x] * ix_in[x];
+ ixy_out[x] = ix_in[x] * iy_in[x];
+ iyy_out[x] = iy_in[x] * iy_in[x];
+ }
+}
+
+template<typename T>
+void harris_responses(Array<T> resp, const unsigned idim0, const unsigned idim1,
+ const Array<T> ixx, const Array<T> ixy, const Array<T> iyy,
+ const float k_thr, const unsigned border_len)
+{
+ T* resp_out = resp.get();
+ const T* ixx_in = ixx.get();
+ const T* ixy_in = ixy.get();
+ const T* iyy_in = iyy.get();
+ const unsigned r = border_len;
+
+ for (unsigned x = r; x < idim1 - r; x++) {
+ for (unsigned y = r; y < idim0 - r; y++) {
+ const unsigned idx = x * idim0 + y;
+
+ // Calculates matrix trace and determinant
+ T tr = ixx_in[idx] + iyy_in[idx];
+ T det = ixx_in[idx] * iyy_in[idx] - ixy_in[idx] * ixy_in[idx];
+
+ // Calculates local Harris response
+ resp_out[idx] = det - k_thr * (tr*tr);
+ }
+ }
+}
+
+template<typename T>
+void non_maximal(Array<float> xOut, Array<float> yOut, Array<float> respOut, unsigned* count,
+ const unsigned idim0, const unsigned idim1, const Array<T> respIn,
+ const float min_resp, const unsigned border_len, const unsigned max_corners)
+{
+ float* x_out = xOut.get();
+ float* y_out = yOut.get();
+ float* resp_out = respOut.get();
+ const T* resp_in = respIn.get();
+ // Responses on the border don't have 8-neighbors to compare, discard them
+ const unsigned r = border_len + 1;
+
+ for (unsigned x = r; x < idim1 - r; x++) {
+ for (unsigned y = r; y < idim0 - r; y++) {
+ const T v = resp_in[x * idim0 + y];
+
+ // Find maximum neighborhood response
+ T max_v;
+ max_v = max(resp_in[(x-1) * idim0 + y-1], resp_in[x * idim0 + y-1]);
+ max_v = max(max_v, resp_in[(x+1) * idim0 + y-1]);
+ max_v = max(max_v, resp_in[(x-1) * idim0 + y ]);
+ max_v = max(max_v, resp_in[(x+1) * idim0 + y ]);
+ max_v = max(max_v, resp_in[(x-1) * idim0 + y+1]);
+ max_v = max(max_v, resp_in[(x) * idim0 + y+1]);
+ max_v = max(max_v, resp_in[(x+1) * idim0 + y+1]);
+
+ // Stores corner to {x,y,resp}_out if it's response is maximum compared
+ // to its 8-neighborhood and greater or equal minimum response
+ if (v > max_v && v >= (T)min_resp) {
+ const unsigned idx = *count;
+ *count += 1;
+ if (idx < max_corners) {
+ x_out[idx] = (float)x;
+ y_out[idx] = (float)y;
+ resp_out[idx] = (float)v;
+ }
+ }
+ }
+ }
+}
+
+static void keep_corners(Array<float> xOut, Array<float> yOut, Array<float> respOut,
+ const Array<float> xIn, const Array<float> yIn,
+ const Array<float> respIn, const Array<unsigned> respIdx,
+ const unsigned n_corners)
+{
+ float* x_out = xOut.get();
+ float* y_out = yOut.get();
+ float* resp_out = respOut.get();
+ const float* x_in = xIn.get();
+ const float* y_in = yIn.get();
+ const float* resp_in = respIn.get();
+ const uint* resp_idx = respIdx.get();
+
+ // Keep only the first n_feat features
+ for (unsigned f = 0; f < n_corners; f++) {
+ x_out[f] = x_in[resp_idx[f]];
+ y_out[f] = y_in[resp_idx[f]];
+ resp_out[f] = resp_in[f];
+ }
+}
+
+}
+}
diff --git a/src/backend/cpu/kernel/histogram.hpp b/src/backend/cpu/kernel/histogram.hpp
new file mode 100644
index 0000000..e26965a
--- /dev/null
+++ b/src/backend/cpu/kernel/histogram.hpp
@@ -0,0 +1,47 @@
+/*******************************************************
+ * Copyright (c) 2015, ArrayFire
+ * All rights reserved.
+ *
+ * This file is distributed under 3-clause BSD license.
+ * The complete license agreement can be obtained at:
+ * http://arrayfire.com/licenses/BSD-3-Clause
+ ********************************************************/
+
+#include <Array.hpp>
+
+namespace cpu
+{
+namespace kernel
+{
+
+template<typename inType, typename outType, bool isLinear>
+void histogram(Array<outType> out, Array<inType> const in,
+ unsigned const nbins, double const minval, double const maxval)
+{
+ dim4 const outDims = out.dims();
+ float const step = (maxval - minval)/(float)nbins;
+ dim4 const inDims = in.dims();
+ dim4 const iStrides = in.strides();
+ dim4 const oStrides = out.strides();
+ dim_t const nElems = inDims[0]*inDims[1];
+
+ outType *outData = out.get();
+ const inType* inData= in.get();
+
+ for(dim_t b3 = 0; b3 < outDims[3]; b3++) {
+ for(dim_t b2 = 0; b2 < outDims[2]; b2++) {
+ for(dim_t i=0; i<nElems; i++) {
+ int idx = isLinear ? i : ((i % inDims[0]) + (i / inDims[0])*iStrides[1]);
+ int bin = (int)((inData[idx] - minval) / step);
+ bin = std::max(bin, 0);
+ bin = std::min(bin, (int)(nbins - 1));
+ outData[bin]++;
+ }
+ inData += iStrides[2];
+ outData += oStrides[2];
+ }
+ }
+}
+
+}
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/arrayfire.git
More information about the debian-science-commits
mailing list