[arrayfire] 252/408: Added SIFT unit tests
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Mon Sep 21 19:12:08 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 ca570676bc3eb5b95bed78a6a5b18bbe269c2ee8
Author: Peter Andreas Entschev <peter at arrayfire.com>
Date: Thu Aug 13 10:34:13 2015 -0400
Added SIFT unit tests
---
test/sift.cpp | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 336 insertions(+)
diff --git a/test/sift.cpp b/test/sift.cpp
new file mode 100644
index 0000000..6ad4c4d
--- /dev/null
+++ b/test/sift.cpp
@@ -0,0 +1,336 @@
+/*******************************************************
+ * 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];
+ unsigned d[128];
+} feat_desc_t;
+
+typedef struct
+{
+ float f[5];
+} feat_t;
+
+typedef struct
+{
+ float d[128];
+} desc_t;
+
+bool feat_cmp(feat_desc_t i, feat_desc_t j)
+{
+ for (int k = 0; k < 5; k++)
+ if (round(i.f[k]*1e1f) != round(j.f[k]*1e1f))
+ return (round(i.f[k]*1e1f) < round(j.f[k]*1e1f));
+
+ return true;
+}
+
+void array_to_feat_desc(vector<feat_desc_t>& feat, float* x, float* y, float* score, float* ori, float* size, float* desc, unsigned nfeat)
+{
+ feat.resize(nfeat);
+ for (size_t 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] = ori[i];
+ feat[i].f[4] = size[i];
+ for (unsigned j = 0; j < 128; j++)
+ feat[i].d[j] = desc[i * 128 + j];
+ }
+}
+
+void array_to_feat_desc(vector<feat_desc_t>& feat, float* x, float* y, float* score, float* ori, float* size, vector<vector<float> >& desc, unsigned nfeat)
+{
+ feat.resize(nfeat);
+ for (size_t 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] = ori[i];
+ feat[i].f[4] = size[i];
+ for (unsigned j = 0; j < 128; j++)
+ feat[i].d[j] = desc[i][j];
+ }
+}
+
+void array_to_feat(vector<feat_t>& feat, float *x, float *y, float *score, float *ori, 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] = ori[i];
+ feat[i].f[4] = size[i];
+ }
+}
+
+void split_feat_desc(vector<feat_desc_t>& fd, vector<feat_t>& f, vector<desc_t>& d)
+{
+ f.resize(fd.size());
+ d.resize(fd.size());
+ for (size_t i = 0; i < fd.size(); i++) {
+ f[i].f[0] = fd[i].f[0];
+ f[i].f[1] = fd[i].f[1];
+ f[i].f[2] = fd[i].f[2];
+ f[i].f[3] = fd[i].f[3];
+ f[i].f[4] = fd[i].f[4];
+ for (unsigned j = 0; j < 128; j++)
+ d[i].d[j] = fd[i].d[j];
+ }
+}
+
+unsigned popcount(unsigned x)
+{
+ x = x - ((x >> 1) & 0x55555555);
+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ x = x + (x >> 8);
+ x = x + (x >> 16);
+ return x & 0x0000003F;
+}
+
+bool compareEuclidean(dim_t desc_len, dim_t ndesc, float *cpu, float *gpu, float unit_thr = 1.f, float euc_thr = 1.f)
+{
+ bool ret = true;
+ float sum = 0.0f;
+
+ for (dim_t i = 0; i < ndesc; i++) {
+ sum = 0.0f;
+ for (dim_t l = 0; l < desc_len; l++) {
+ dim_t idx = i * desc_len + l;
+ float x = (cpu[idx] - gpu[idx]);
+ sum += x*x;
+ if (abs(x) > (float)unit_thr) {
+ ret = false;
+ std::cout<<std::endl<<"@compareEuclidean: unit mismatch."<<std::endl;
+ std::cout<<"(cpu,gpu,cpu-gpu)["<<i<<","<<l<<"] : {"<<cpu[idx]<<","<<gpu[idx]<<","<<cpu[idx]-gpu[idx]<<"}"<<std::endl;
+ std::cout<<std::endl;
+ break;
+ }
+ }
+ if (sqrt(sum) > euc_thr) {
+ ret = false;
+ std::cout<<std::endl<<"@compareEuclidean: distance mismatch."<<std::endl;
+ std::cout<<"Euclidean distance: "<<sqrt(sum)<<std::endl;
+ }
+ if (ret == false)
+ return ret;
+ }
+
+ return ret;
+}
+
+template<typename T>
+class SIFT : public ::testing::Test
+{
+ public:
+ virtual void SetUp() {}
+};
+
+typedef ::testing::Types<float, double> TestTypes;
+
+TYPED_TEST_CASE(SIFT, TestTypes);
+
+template<typename T>
+void siftTest(string pTestFile)
+{
+#ifdef AF_NONFREE
+ if (noDoubleTests<T>()) return;
+
+ vector<dim4> inDims;
+ vector<string> inFiles;
+ vector<vector<float> > goldFeat;
+ vector<vector<float> > goldDesc;
+
+ readImageFeaturesDescriptors<float>(pTestFile, inDims, inFiles, goldFeat, goldDesc);
+
+ size_t testCount = inDims.size();
+
+ for (size_t testId=0; testId<testCount; ++testId) {
+ af_array inArray_f32 = 0;
+ af_array inArray = 0;
+ af_array desc = 0;
+ af_features feat;
+
+ inFiles[testId].insert(0,string(TEST_DIR"/sift/"));
+
+ ASSERT_EQ(AF_SUCCESS, af_load_image(&inArray_f32, inFiles[testId].c_str(), false));
+ ASSERT_EQ(AF_SUCCESS, conv_image<T>(&inArray, inArray_f32));
+
+ ASSERT_EQ(AF_SUCCESS, af_sift(&feat, &desc, inArray, 3, 0.04f, 10.0f, 1.6f, true, 1.f/256.f, 0.05f));
+
+ dim_t n = 0;
+ af_array x, y, score, orientation, size;
+
+ ASSERT_EQ(AF_SUCCESS, af_get_features_num(&n, feat));
+ ASSERT_EQ(AF_SUCCESS, af_get_features_xpos(&x, feat));
+ ASSERT_EQ(AF_SUCCESS, af_get_features_ypos(&y, feat));
+ ASSERT_EQ(AF_SUCCESS, af_get_features_score(&score, feat));
+ ASSERT_EQ(AF_SUCCESS, af_get_features_orientation(&orientation, feat));
+ ASSERT_EQ(AF_SUCCESS, af_get_features_size(&size, feat));
+
+ float * outX = new float[n];
+ float * outY = new float[n];
+ float * outScore = new float[n];
+ float * outOrientation = new float[n];
+ float * outSize = new float[n];
+ dim_t descSize;
+ dim_t descDims[4];
+ ASSERT_EQ(AF_SUCCESS, af_get_elements(&descSize, desc));
+ ASSERT_EQ(AF_SUCCESS, af_get_dims(&descDims[0], &descDims[1], &descDims[2], &descDims[3], desc));
+ float * outDesc = new float[descSize];
+ ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outX, x));
+ ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outY, y));
+ ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outScore, score));
+ ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outOrientation, orientation));
+ ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outSize, size));
+ ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outDesc, desc));
+
+ vector<feat_desc_t> out_feat_desc;
+ array_to_feat_desc(out_feat_desc, outX, outY, outScore, outOrientation, outSize, outDesc, n);
+
+ vector<feat_desc_t> gold_feat_desc;
+ array_to_feat_desc(gold_feat_desc, &goldFeat[0].front(), &goldFeat[1].front(), &goldFeat[2].front(), &goldFeat[3].front(), &goldFeat[4].front(), goldDesc, goldFeat[0].size());
+
+ std::sort(out_feat_desc.begin(), out_feat_desc.end(), feat_cmp);
+ std::sort(gold_feat_desc.begin(), gold_feat_desc.end(), feat_cmp);
+
+ vector<feat_t> out_feat;
+ vector<desc_t> v_out_desc;
+ vector<feat_t> gold_feat;
+ vector<desc_t> v_gold_desc;
+
+ split_feat_desc(out_feat_desc, out_feat, v_out_desc);
+ split_feat_desc(gold_feat_desc, gold_feat, v_gold_desc);
+
+ for (int elIter = 0; elIter < (int)n; elIter++) {
+ ASSERT_LE(fabs(out_feat[elIter].f[0] - gold_feat[elIter].f[0]), 1e-3) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[1] - gold_feat[elIter].f[1]), 1e-3) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[2] - gold_feat[elIter].f[2]), 1e-3) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[3] - gold_feat[elIter].f[3]), 0.5f) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[4] - gold_feat[elIter].f[4]), 1e-3) << "at: " << elIter << std::endl;
+ }
+
+ EXPECT_TRUE(compareEuclidean(descDims[0], descDims[1], (float*)&v_out_desc[0], (float*)&v_gold_desc[0], 1.f, 2.f));
+
+ ASSERT_EQ(AF_SUCCESS, af_release_array(inArray));
+ ASSERT_EQ(AF_SUCCESS, af_release_array(inArray_f32));
+
+ ASSERT_EQ(AF_SUCCESS, af_release_array(x));
+ ASSERT_EQ(AF_SUCCESS, af_release_array(y));
+ ASSERT_EQ(AF_SUCCESS, af_release_array(score));
+ ASSERT_EQ(AF_SUCCESS, af_release_array(orientation));
+ ASSERT_EQ(AF_SUCCESS, af_release_array(size));
+ ASSERT_EQ(AF_SUCCESS, af_release_array(desc));
+
+ delete[] outX;
+ delete[] outY;
+ delete[] outScore;
+ delete[] outOrientation;
+ delete[] outSize;
+ delete[] outDesc;
+ }
+#endif
+}
+
+#define SIFT_INIT(desc, image) \
+ TYPED_TEST(SIFT, desc) \
+ { \
+ siftTest<TypeParam>(string(TEST_DIR"/sift/"#image".test")); \
+ }
+
+ SIFT_INIT(man, man);
+
+///////////////////////////////////// CPP ////////////////////////////////
+//
+TEST(SIFT, CPP)
+{
+#ifdef AF_NONFREE
+ if (noDoubleTests<float>()) return;
+
+ vector<dim4> inDims;
+ vector<string> inFiles;
+ vector<vector<float> > goldFeat;
+ vector<vector<float> > goldDesc;
+
+ readImageFeaturesDescriptors<float>(string(TEST_DIR"/sift/man.test"), inDims, inFiles, goldFeat, goldDesc);
+ inFiles[0].insert(0,string(TEST_DIR"/sift/"));
+
+ af::array in = af::loadImage(inFiles[0].c_str(), false);
+
+ af::features feat;
+ af::array desc;
+ af::sift(feat, desc, in, 3, 0.04f, 10.0f, 1.6f, true, 1.f/256.f, 0.05f);
+
+ float * outX = new float[feat.getNumFeatures()];
+ float * outY = new float[feat.getNumFeatures()];
+ float * outScore = new float[feat.getNumFeatures()];
+ float * outOrientation = new float[feat.getNumFeatures()];
+ float * outSize = new float[feat.getNumFeatures()];
+ float * outDesc = new float[desc.elements()];
+ af::dim4 descDims = desc.dims();
+ feat.getX().host(outX);
+ feat.getY().host(outY);
+ feat.getScore().host(outScore);
+ feat.getOrientation().host(outOrientation);
+ feat.getSize().host(outSize);
+ desc.host(outDesc);
+
+ vector<feat_desc_t> out_feat_desc;
+ array_to_feat_desc(out_feat_desc, outX, outY, outScore, outOrientation, outSize, outDesc, feat.getNumFeatures());
+
+ vector<feat_desc_t> gold_feat_desc;
+ array_to_feat_desc(gold_feat_desc, &goldFeat[0].front(), &goldFeat[1].front(), &goldFeat[2].front(), &goldFeat[3].front(), &goldFeat[4].front(), goldDesc, goldFeat[0].size());
+
+ std::sort(out_feat_desc.begin(), out_feat_desc.end(), feat_cmp);
+ std::sort(gold_feat_desc.begin(), gold_feat_desc.end(), feat_cmp);
+
+ vector<feat_t> out_feat;
+ vector<desc_t> v_out_desc;
+ vector<feat_t> gold_feat;
+ vector<desc_t> v_gold_desc;
+
+ split_feat_desc(out_feat_desc, out_feat, v_out_desc);
+ split_feat_desc(gold_feat_desc, gold_feat, v_gold_desc);
+
+ for (int elIter = 0; elIter < (int)feat.getNumFeatures(); elIter++) {
+ ASSERT_LE(fabs(out_feat[elIter].f[0] - gold_feat[elIter].f[0]), 1e-3) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[1] - gold_feat[elIter].f[1]), 1e-3) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[2] - gold_feat[elIter].f[2]), 1e-3) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[3] - gold_feat[elIter].f[3]), 0.5f) << "at: " << elIter << std::endl;
+ ASSERT_LE(fabs(out_feat[elIter].f[4] - gold_feat[elIter].f[4]), 1e-3) << "at: " << elIter << std::endl;
+ }
+
+ EXPECT_TRUE(compareEuclidean(descDims[0], descDims[1], (float*)&v_out_desc[0], (float*)&v_gold_desc[0], 1.f, 2.f));
+
+ delete[] outX;
+ delete[] outY;
+ delete[] outScore;
+ delete[] outOrientation;
+ delete[] outSize;
+ delete[] outDesc;
+#endif
+}
--
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