[arrayfire] 161/408: SUSAN Corner Detector
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Mon Sep 21 19:11:46 UTC 2015
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to branch debian/sid
in repository arrayfire.
commit de9ba747ba17ef4ade0e306e8561259ce5336c2f
Author: pradeep <pradeep at arrayfire.com>
Date: Tue Jul 21 16:52:36 2015 -0400
SUSAN Corner Detector
* API documentation
* CPU backend implementation
* Example for SUSAN detector
* Basic unit tests for SUSAN detector
* Test data commit # update to use SUSAN test data
---
docs/details/vision.dox | 31 +++++++
examples/computer_vision/susan.cpp | 89 +++++++++++++++++++
include/af/vision.h | 44 ++++++++++
src/api/c/susan.cpp | 70 +++++++++++++++
src/api/cpp/susan.cpp | 25 ++++++
src/backend/cpu/susan.cpp | 171 +++++++++++++++++++++++++++++++++++++
src/backend/cpu/susan.hpp | 24 ++++++
src/backend/cuda/susan.cu | 40 +++++++++
src/backend/cuda/susan.hpp | 24 ++++++
src/backend/opencl/susan.cpp | 40 +++++++++
src/backend/opencl/susan.hpp | 24 ++++++
test/data | 2 +-
test/susan.cpp | 125 +++++++++++++++++++++++++++
13 files changed, 708 insertions(+), 1 deletion(-)
diff --git a/docs/details/vision.dox b/docs/details/vision.dox
index 68f13cf..d381068 100644
--- a/docs/details/vision.dox
+++ b/docs/details/vision.dox
@@ -30,6 +30,37 @@ local maximas and have a high positive response.
=======================================================================
+\defgroup cv_func_susan susan
+\ingroup featdetect_mat
+
+\brief SUSAN corner detector
+
+SUSAN is an acronym standing for *Smallest Univalue Segment Assimilating Nucleus*. This method
+places a circular disc over the pixel to be tested (a.k.a nucleus) to compute the corner measure
+of that corresponding pixel. The region covered by the circular disc is **M**, and a pixel in this
+region is represented by \f$\vec{m} \in M\f$ where \f$\vec{m}_0\f$ is the nucleus. Every pixel in the region
+is compared to the nucleus using the following comparison function:
+
+\f$ c(\vec{m}) = e^{-{(({I(\vec{m}) - I(\vec{m}_0))} / t})^6}\f$
+
+where *t* is radius of the region, *I* is the brightness of the pixel.
+
+Response of SUSAN operator is given by the following equation:
+
+\f$ R(M) = \begin{cases} g - n(M) \quad \text{if } n(M) < g\\ 0 \quad \text{otherwise},\\ \end{cases}\f$
+
+where \f$ n(M) = \sum\nolimits_{\vec{m} \in M} c(\vec{m})\f$, g is named the *geometric threshold* and n is the number
+of pixels in the mask which are within **t** of the nucleus.
+
+Importance of the parameters, **t** and **g** is explained below:
+
+- *t* determines how similar points have to be to the nucleusbefore they are considered to
+ be a part of the univalue segment
+- g determines the minimum size of the univalue segment. For a large enough *g*, SUSAN operator becomes
+ an edge dectector.
+
+=======================================================================
+
\defgroup cv_func_orb orb
\ingroup featdescriptor_mat
diff --git a/examples/computer_vision/susan.cpp b/examples/computer_vision/susan.cpp
new file mode 100644
index 0000000..3cafe71
--- /dev/null
+++ b/examples/computer_vision/susan.cpp
@@ -0,0 +1,89 @@
+/*******************************************************
+ * 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 <cstdio>
+#include <arrayfire.h>
+#include <cstdlib>
+
+using namespace af;
+
+static void susan_demo(bool console)
+{
+ // Load image
+ array img_color;
+ if (console)
+ img_color = loadImage(ASSETS_DIR "/examples/images/square.png", true);
+ else
+ img_color = loadImage(ASSETS_DIR "/examples/images/man.jpg", true);
+ // Convert the image from RGB to gray-scale
+ array img = colorSpace(img_color, AF_GRAY, AF_RGB);
+ // For visualization in ArrayFire, color images must be in the [0.0f-1.0f] interval
+ img_color /= 255.f;
+
+ features feat = susan(img, 3, 32.0f, 10, 0.05f, 3);
+
+ if (feat.getNumFeatures() > 0) {
+ printf("Found features, proceeding ahead\n");
+ } else {
+ printf("No features found, exiting\n");
+ return;
+ }
+
+ float* h_x = feat.getX().host<float>();
+ float* h_y = feat.getY().host<float>();
+
+ // Draw draw_len x draw_len crosshairs where the corners are
+ const int draw_len = 3;
+ for (size_t f = 0; f < feat.getNumFeatures(); f++) {
+ int x = h_x[f];
+ int y = h_y[f];
+ img_color(y, seq(x-draw_len, x+draw_len), 0) = 0.f;
+ img_color(y, seq(x-draw_len, x+draw_len), 1) = 1.f;
+ img_color(y, seq(x-draw_len, x+draw_len), 2) = 0.f;
+
+ // Draw vertical line of (draw_len * 2 + 1) pixels centered on the corner
+ // Set only the first channel to 1 (green lines)
+ img_color(seq(y-draw_len, y+draw_len), x, 0) = 0.f;
+ img_color(seq(y-draw_len, y+draw_len), x, 1) = 1.f;
+ img_color(seq(y-draw_len, y+draw_len), x, 2) = 0.f;
+ }
+
+ printf("Features found: %lu\n", feat.getNumFeatures());
+
+ if (!console) {
+ af::Window wnd("FAST Feature Detector");
+
+ // Previews color image with green crosshairs
+ while(!wnd.close())
+ wnd.image(img_color);
+ } else {
+ af_print(feat.getX());
+ af_print(feat.getY());
+ af_print(feat.getScore());
+ }
+}
+
+int main(int argc, char** argv)
+{
+ int device = argc > 1 ? atoi(argv[1]) : 0;
+ bool console = argc > 2 ? argv[2][0] == '-' : false;
+
+ try {
+ af::setDevice(device);
+ af::info();
+ std::cout << "** ArrayFire FAST Feature Detector Demo **" << std::endl << std::endl;
+ susan_demo(console);
+
+ } catch (af::exception& ae) {
+ std::cerr << ae.what() << std::endl;
+ throw;
+ }
+
+ return 0;
+}
diff --git a/include/af/vision.h b/include/af/vision.h
index 5c2e0aa..de2b045 100644
--- a/include/af/vision.h
+++ b/include/af/vision.h
@@ -166,6 +166,29 @@ AFAPI void nearestNeighbour(array& idx, array& dist,
*/
AFAPI array matchTemplate(const array &searchImg, const array &templateImg, const matchType mType=AF_SAD);
+
+/**
+ C++ Interface for SUSAN corner detector
+
+ \param[in] in is input grayscale/intensity image
+ \param[in] radius Nuclei radius for each pixel neighborhood
+ \param[in] diff_thr intensity difference threshold
+ \param[in] geom_thr geometric threshold a.k.a **t** from equations in description
+ \param[in] feature_ratio is maximum number of features that will be returned by the function
+ \param[in] edge indicates how many pixels width area should be skipped for corner detection
+ \return If SUSAN corner detection is successfull returns an object of Features class, composed of arrays for x and y
+ coordinates, score, orientation and size of selected features, otherwise exception is thrown.
+
+ \note If \p in is a 3d array, a batch operation will be performed.
+
+ \ingroup cv_func_susan
+*/
+AFAPI features susan(const array& in,
+ const unsigned radius=3,
+ const float diff_thr=32.0f,
+ const float geom_thr=10.0f,
+ const float feature_ratio=0.05f,
+ const unsigned edge=3);
}
#endif
@@ -325,6 +348,27 @@ extern "C" {
*/
AFAPI af_err af_match_template(af_array *out, const af_array search_img, const af_array template_img, const af_match_type m_type);
+ /**
+ C Interface for SUSAN corner detector
+
+ \param[out] out is af_features struct composed of arrays for x and y
+ coordinates, score, orientation and size of selected features
+ \param[in] in is input grayscale/intensity image
+ \param[in] radius Nuclei radius for each pixel neighborhood
+ \param[in] diff_thr intensity difference threshold a.k.a **t** from equations in description
+ \param[in] geom_thr geometric threshold
+ \param[in] feature_ratio is maximum number of features that will be returned by the function
+ \param[in] edge indicates how many pixels width area should be skipped for corner detection
+ \return \ref AF_SUCCESS if SUSAN corner detection is successfull, otherwise an appropriate
+ error code is returned.
+
+ \note If \p in is a 3d array, a batch operation will be performed.
+
+ \ingroup cv_func_susan
+ */
+ AFAPI af_err af_susan(af_features* out, const af_array in, const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/api/c/susan.cpp b/src/api/c/susan.cpp
new file mode 100644
index 0000000..2b042ea
--- /dev/null
+++ b/src/api/c/susan.cpp
@@ -0,0 +1,70 @@
+/*******************************************************
+ * 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 <af/dim4.hpp>
+#include <af/defines.h>
+#include <af/features.h>
+#include <af/vision.h>
+#include <handle.hpp>
+#include <err_common.hpp>
+#include <backend.hpp>
+#include <features.hpp>
+#include <susan.hpp>
+
+using af::dim4;
+using namespace detail;
+
+template<typename T>
+static af_features susan(af_array const &in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge)
+{
+ Array<float> x = createEmptyArray<float>(dim4());
+ Array<float> y = createEmptyArray<float>(dim4());
+ Array<float> score = createEmptyArray<float>(dim4());
+
+ af_features_t feat;
+ feat.n = susan<T>(x, y, score,
+ getArray<T>(in), radius, diff_thr, geom_thr,
+ feature_ratio, edge);
+
+ Array<float> orientation = createValueArray<float>(feat.n, 0.0);
+ Array<float> size = createValueArray<float>(feat.n, 1.0);
+
+ feat.x = getHandle(x);
+ feat.y = getHandle(y);
+ feat.score = getHandle(score);
+ feat.orientation = getHandle(orientation);
+ feat.size = getHandle(size);
+
+ return getFeaturesHandle(feat);
+}
+
+af_err af_susan(af_features* out, const af_array in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge)
+{
+ try {
+ ArrayInfo info = getInfo(in);
+ af::dim4 dims = info.dims();
+ af_dtype type = info.getType();
+ switch(type) {
+ case f32: *out = susan<float >(in, radius, diff_thr, geom_thr, feature_ratio, edge); break;
+ case f64: *out = susan<double>(in, radius, diff_thr, geom_thr, feature_ratio, edge); break;
+ case b8 : *out = susan<char >(in, radius, diff_thr, geom_thr, feature_ratio, edge); break;
+ case s32: *out = susan<int >(in, radius, diff_thr, geom_thr, feature_ratio, edge); break;
+ case u32: *out = susan<uint >(in, radius, diff_thr, geom_thr, feature_ratio, edge); break;
+ case u8 : *out = susan<uchar >(in, radius, diff_thr, geom_thr, feature_ratio, edge); break;
+ default : TYPE_ERROR(1, type);
+ }
+ }
+ CATCHALL;
+
+ return AF_SUCCESS;
+}
diff --git a/src/api/cpp/susan.cpp b/src/api/cpp/susan.cpp
new file mode 100644
index 0000000..1711b7b
--- /dev/null
+++ b/src/api/cpp/susan.cpp
@@ -0,0 +1,25 @@
+/*******************************************************
+ * 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 <af/vision.h>
+#include <af/array.h>
+#include "error.hpp"
+
+namespace af
+{
+
+features susan(const array& in, const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge)
+{
+ af_features temp;
+ AF_THROW(af_susan(&temp, in.get(), radius, diff_thr, geom_thr, feature_ratio, edge));
+ return features(temp);
+}
+
+}
diff --git a/src/backend/cpu/susan.cpp b/src/backend/cpu/susan.cpp
new file mode 100644
index 0000000..c2d504d
--- /dev/null
+++ b/src/backend/cpu/susan.cpp
@@ -0,0 +1,171 @@
+/*******************************************************
+ * 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 <af/features.h>
+#include <Array.hpp>
+#include <cmath>
+#include <sort_index.hpp>
+#include <math.hpp>
+
+using af::features;
+
+namespace cpu
+{
+
+template<typename T>
+void susan_responses(T* resp_out, const T* in,
+ const unsigned idim0, const unsigned idim1,
+ const int radius, const float t, const float g,
+ const unsigned border_len)
+{
+ const unsigned r = border_len;
+ const int rSqrd = radius*radius;
+
+ for (unsigned x = r; x < idim1 - r; ++x) {
+ for (unsigned y = r; y < idim0 - r; ++y) {
+ const unsigned idx = x * idim0 + y;
+ T m_0 = in[idx];
+ float nM = 0.0f;
+
+ for (int i=-radius; i<=radius; ++i) {
+ for (int j=-radius; j<=radius; ++j) {
+ if (i*i + j*j < rSqrd) {
+ int p = x + i;
+ int q = y + j;
+ T m = in[p * idim0 + q];
+ float exp_pow = std::pow((m - m_0)/t, 6.0);
+ float cM = std::exp(-exp_pow);
+ nM += cM;
+ }
+ }
+ }
+
+ resp_out[idx] = nM < g ? g - nM : T(0);
+ }
+ }
+}
+
+template<typename T>
+void non_maximal(float* x_out, float* y_out, float* resp_out,
+ unsigned* count, const unsigned idim0, const unsigned idim1,
+ const T* resp_in, const unsigned border_len, const unsigned max_corners)
+{
+ // 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) {
+ 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(float* x_out, float* y_out, float* resp_out,
+ const float* x_in, const float* y_in,
+ const float* resp_in, const unsigned* resp_idx,
+ const unsigned n_corners)
+{
+ // 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>
+unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &resp_out,
+ const Array<T> &in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge)
+{
+ dim4 idims = in.dims();
+
+ const unsigned corner_lim = in.elements() * feature_ratio;
+ float* x_corners = memAlloc<float>(corner_lim);
+ float* y_corners = memAlloc<float>(corner_lim);
+ float* resp_corners = memAlloc<float>(corner_lim);
+
+ T* resp = memAlloc<T>(in.elements());
+ unsigned corners_found = 0;
+
+ susan_responses<T>(resp, in.get(), idims[0], idims[1], radius, diff_thr, geom_thr, edge);
+
+ non_maximal<T>(x_corners, y_corners, resp_corners, &corners_found,
+ idims[0], idims[1], resp, edge, corner_lim);
+
+ memFree(resp);
+
+ const unsigned corners_out = min(corners_found, corner_lim);
+ if (corners_out == 0)
+ return 0;
+
+ if (corners_found > corners_out) {
+ Array<float> susan_responses = createDeviceDataArray<float>(dim4(corners_found), (void*)resp_corners);
+ Array<float> susan_sorted = createEmptyArray<float>(dim4(corners_found));
+ Array<unsigned> susan_idx = createEmptyArray<unsigned>(dim4(corners_found));
+
+ // Sort susan responses
+ sort_index<float, false>(susan_sorted, susan_idx, susan_responses, 0);
+
+ x_out = createEmptyArray<float>(dim4(corners_out));
+ y_out = createEmptyArray<float>(dim4(corners_out));
+ resp_out = createEmptyArray<float>(dim4(corners_out));
+
+ // Keep only the corners with higher SUSAN responses
+ keep_corners(x_out.get(), y_out.get(), resp_out.get(),
+ x_corners, y_corners, susan_sorted.get(), susan_idx.get(),
+ corners_out);
+
+ memFree(x_corners);
+ memFree(y_corners);
+ } else {
+ x_out = createDeviceDataArray<float>(dim4(corners_out), (void*)x_corners);
+ y_out = createDeviceDataArray<float>(dim4(corners_out), (void*)y_corners);
+ resp_out = createDeviceDataArray<float>(dim4(corners_out), (void*)resp_corners);
+ }
+
+ return corners_out;
+}
+
+#define INSTANTIATE(T) \
+template unsigned susan<T>(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out, \
+ const Array<T> &in, const unsigned radius, const float diff_thr, \
+ const float geom_thr, const float feature_ratio, const unsigned edge);
+
+INSTANTIATE(float )
+INSTANTIATE(double)
+INSTANTIATE(char )
+INSTANTIATE(int )
+INSTANTIATE(uint )
+INSTANTIATE(uchar )
+
+}
diff --git a/src/backend/cpu/susan.hpp b/src/backend/cpu/susan.hpp
new file mode 100644
index 0000000..2e57711
--- /dev/null
+++ b/src/backend/cpu/susan.hpp
@@ -0,0 +1,24 @@
+/*******************************************************
+ * 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 <af/features.h>
+#include <Array.hpp>
+
+using af::features;
+
+namespace cpu
+{
+
+template<typename T>
+unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
+ const Array<T> &in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge);
+
+}
diff --git a/src/backend/cuda/susan.cu b/src/backend/cuda/susan.cu
new file mode 100644
index 0000000..81d126a
--- /dev/null
+++ b/src/backend/cuda/susan.cu
@@ -0,0 +1,40 @@
+/*******************************************************
+ * 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 <af/features.h>
+#include <Array.hpp>
+#include <err_cuda.hpp>
+
+using af::features;
+
+namespace cuda
+{
+
+template<typename T>
+unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
+ const Array<T> &in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge)
+{
+ CUDA_NOT_SUPPORTED();
+}
+
+#define INSTANTIATE(T) \
+template unsigned susan<T>(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out, \
+ const Array<T> &in, const unsigned radius, const float diff_thr, \
+ const float geom_thr, const float feature_ratio, const unsigned edge);
+
+INSTANTIATE(float )
+INSTANTIATE(double)
+INSTANTIATE(char )
+INSTANTIATE(int )
+INSTANTIATE(uint )
+INSTANTIATE(uchar )
+
+}
diff --git a/src/backend/cuda/susan.hpp b/src/backend/cuda/susan.hpp
new file mode 100644
index 0000000..86977f8
--- /dev/null
+++ b/src/backend/cuda/susan.hpp
@@ -0,0 +1,24 @@
+/*******************************************************
+ * 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 <af/features.h>
+#include <Array.hpp>
+
+using af::features;
+
+namespace cuda
+{
+
+template<typename T>
+unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
+ const Array<T> &in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge);
+
+}
diff --git a/src/backend/opencl/susan.cpp b/src/backend/opencl/susan.cpp
new file mode 100644
index 0000000..1c3db1c
--- /dev/null
+++ b/src/backend/opencl/susan.cpp
@@ -0,0 +1,40 @@
+/*******************************************************
+ * 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 <af/features.h>
+#include <Array.hpp>
+#include <err_opencl.hpp>
+
+using af::features;
+
+namespace opencl
+{
+
+template<typename T>
+unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
+ const Array<T> &in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge)
+{
+ OPENCL_NOT_SUPPORTED();
+}
+
+#define INSTANTIATE(T) \
+template unsigned susan<T>(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out, \
+ const Array<T> &in, const unsigned radius, const float diff_thr, \
+ const float geom_thr, const float feature_ratio, const unsigned edge);
+
+INSTANTIATE(float )
+INSTANTIATE(double)
+INSTANTIATE(char )
+INSTANTIATE(int )
+INSTANTIATE(uint )
+INSTANTIATE(uchar )
+
+}
diff --git a/src/backend/opencl/susan.hpp b/src/backend/opencl/susan.hpp
new file mode 100644
index 0000000..3fac35c
--- /dev/null
+++ b/src/backend/opencl/susan.hpp
@@ -0,0 +1,24 @@
+/*******************************************************
+ * 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 <af/features.h>
+#include <Array.hpp>
+
+using af::features;
+
+namespace opencl
+{
+
+template<typename T>
+unsigned susan(Array<float> &x_out, Array<float> &y_out, Array<float> &score_out,
+ const Array<T> &in,
+ const unsigned radius, const float diff_thr, const float geom_thr,
+ const float feature_ratio, const unsigned edge);
+
+}
diff --git a/test/data b/test/data
index eb003ae..35de6d7 160000
--- a/test/data
+++ b/test/data
@@ -1 +1 @@
-Subproject commit eb003aedbd4467883a596c482f9c4b5d366c7db7
+Subproject commit 35de6d78b7e46f6e3441dcceb81e96a968e940d3
diff --git a/test/susan.cpp b/test/susan.cpp
new file mode 100644
index 0000000..1c558f7
--- /dev/null
+++ b/test/susan.cpp
@@ -0,0 +1,125 @@
+/*******************************************************
+ * 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 <gtest/gtest.h>
+#include <arrayfire.h>
+#include <af/dim4.hpp>
+#include <af/traits.hpp>
+#include <af/compatible.h>
+#include <string>
+#include <vector>
+#include <cmath>
+#include <testHelpers.hpp>
+#include <typeinfo>
+
+using std::string;
+using std::vector;
+using af::dim4;
+
+typedef struct
+{
+ float f[5];
+} feat_t;
+
+bool feat_cmp(feat_t i, feat_t j)
+{
+ for (int k = 0; k < 5; k++)
+ if (i.f[k] != j.f[k])
+ return (i.f[k] < j.f[k]);
+
+ return false;
+}
+
+void array_to_feat(vector<feat_t>& feat, float *x, float *y, float *score, float *orientation, float *size, unsigned nfeat)
+{
+ feat.resize(nfeat);
+ for (unsigned i = 0; i < feat.size(); i++) {
+ feat[i].f[0] = x[i];
+ feat[i].f[1] = y[i];
+ feat[i].f[2] = score[i];
+ feat[i].f[3] = orientation[i];
+ feat[i].f[4] = size[i];
+ }
+}
+
+template<typename T>
+class Susan : public ::testing::Test
+{
+ public:
+ virtual void SetUp() {}
+};
+
+typedef ::testing::Types<float, double, int, uint, char, uchar> TestTypes;
+
+TYPED_TEST_CASE(Susan, TestTypes);
+
+template<typename T>
+void susanTest(string pTestFile, float t, float g)
+{
+ if (noDoubleTests<T>()) return;
+
+ vector<dim4> inDims;
+ vector<string> inFiles;
+ vector<vector<float> > gold;
+
+ readImageTests(pTestFile, inDims, inFiles, gold);
+
+ size_t testCount = inDims.size();
+
+ for (size_t testId=0; testId<testCount; ++testId) {
+ inFiles[testId].insert(0, string(TEST_DIR "/susan/"));
+
+ af::array in = af::loadImage(inFiles[testId].c_str(), false);
+
+ af::features out = af::susan(in, 3, 32, 10, 0.05f, 3);
+
+ float * outX = new float[gold[0].size()];
+ float * outY = new float[gold[1].size()];
+ float * outScore = new float[gold[2].size()];
+ float * outOrientation = new float[gold[3].size()];
+ float * outSize = new float[gold[4].size()];
+ out.getX().host(outX);
+ out.getY().host(outY);
+ out.getScore().host(outScore);
+ out.getOrientation().host(outOrientation);
+ out.getSize().host(outSize);
+
+ vector<feat_t> out_feat;
+ array_to_feat(out_feat, outX, outY, outScore, outOrientation, outSize, out.getNumFeatures());
+
+ vector<feat_t> gold_feat;
+ array_to_feat(gold_feat, &gold[0].front(), &gold[1].front(), &gold[2].front(), &gold[3].front(), &gold[4].front(), gold[0].size());
+
+ std::sort(out_feat.begin(), out_feat.end(), feat_cmp);
+ std::sort(gold_feat.begin(), gold_feat.end(), feat_cmp);
+
+ for (int elIter = 0; elIter < (int)out.getNumFeatures(); elIter++) {
+ ASSERT_EQ(out_feat[elIter].f[0], gold_feat[elIter].f[0]) << "at: " << elIter << std::endl;
+ ASSERT_EQ(out_feat[elIter].f[1], gold_feat[elIter].f[1]) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[2] - gold_feat[elIter].f[2]), 1e2) << "at: " << elIter << std::endl;
+ ASSERT_EQ(out_feat[elIter].f[3], gold_feat[elIter].f[3]) << "at: " << elIter << std::endl;
+ ASSERT_EQ(out_feat[elIter].f[4], gold_feat[elIter].f[4]) << "at: " << elIter << std::endl;
+ }
+
+ delete [] outX;
+ delete [] outY;
+ delete [] outScore;
+ delete [] outOrientation;
+ delete [] outSize;
+ }
+}
+
+#define SUSAN_TEST(image, tval, gval) \
+ TYPED_TEST(Susan, image) \
+ { \
+ susanTest<TypeParam>(string(TEST_DIR "/susan/"#image".test"), tval, gval);\
+ }
+
+SUSAN_TEST(square_t32_g10, 32, 10);
+SUSAN_TEST(square_t32_g20, 32, 20);
--
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