File: knnmodule.hpp

package info (click to toggle)
gamera 1:3.4.2+git20160808.1725654-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 22,312 kB
  • ctags: 24,991
  • sloc: xml: 122,324; ansic: 52,869; cpp: 50,664; python: 35,034; makefile: 118; sh: 101
file content (177 lines) | stat: -rw-r--r-- 5,321 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
 *
 * Copyright (C) 2001-2005 Ichiro Fujinaga, Michael Droettboom, and Karl MacMillan
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/*
  This holds various functions for using k-NN and Python together.
*/
#ifndef KWM12172002_knnmodule
#define KWM12172002_knnmodule

#include <Python.h>
#include "knn.hpp"

using namespace Gamera;
using namespace Gamera::kNN;

/*
  This enum is for selecting between the various methods of
  computing the distance between two floating-point feature
  vectors.
*/
enum DistanceType {
  CITY_BLOCK,
  EUCLIDEAN,
  FAST_EUCLIDEAN
};


/*
  get the feature vector from an image. image argument _must_ an image - no
  type checking is performed.
*/
inline int image_get_fv(PyObject* image, double** buf, Py_ssize_t* len) {
  ImageObject* x = (ImageObject*)image;

  if (PyObject_CheckReadBuffer(x->m_features) < 0) {
    return -1;
  }

  if (PyObject_AsReadBuffer(x->m_features, (const void**)buf, len) < 0) {
    PyErr_SetString(PyExc_TypeError, "knn: Could not use image as read buffer.");
    return -1;
  }
  if (*len == 0) {
    return -1;
  }
  *len = *len / sizeof(double);
  return 0;
}

/*
  get the id_name from an image. The image argument _must_ be an image -
  no type checking is performed.
*/
inline int image_get_id_name(PyObject* image, char** id_name, int* len) {
  ImageObject* x = (ImageObject*)image;

  // PyList_Size shoule type check the argument
  if (PyList_Size(x->m_id_name) < 1) {
    PyErr_SetString(PyExc_TypeError, "knn: id_name not a list or list is empty.");
    return -1;
  }
  PyObject* id_tuple = PyList_GET_ITEM(x->m_id_name, 0);
  if (PyTuple_Size(id_tuple) != 2) {
    PyErr_SetString(PyExc_TypeError, "knn: id_name is not a tuple or is the wrong size.");
    return -1;
  }
  PyObject* id = PyTuple_GET_ITEM(id_tuple, 1);
  *id_name = PyString_AsString(id);
  if (*id_name == 0) {
    PyErr_SetString(PyExc_TypeError, "knn: could not get string from id_name tuple.");
    return -1;
  }
  *len = PyString_GET_SIZE(id);
  return 0;
}

/*
  Compute the distance between two feature vectors.
*/
inline void compute_distance(DistanceType distance_type, const double* known_buf,
                 int known_len, const double* unknown_buf, double* distance, 
                 const int* selections, const double* weights) {

  if (distance_type == CITY_BLOCK) {
    *distance = city_block_distance(known_buf, known_buf + known_len, unknown_buf,
				   selections, weights);
  } else if (distance_type == FAST_EUCLIDEAN) {
    *distance = fast_euclidean_distance(known_buf, known_buf + known_len, unknown_buf,
				   selections, weights);
  } else {
    *distance = euclidean_distance(known_buf, known_buf + known_len, unknown_buf,
				   selections, weights);
  }
}


/*
  Compute the distance between a known and an unknown image
  with weights. This version takes an image and a buffer
  for the unknown image.
*/
inline int compute_distance(DistanceType distance_type, PyObject* known,
                double* unknown_buf, double* distance,
                int* selections, double* weights, Py_ssize_t unknown_len) {
  double* known_buf;
  Py_ssize_t known_len;

  if (image_get_fv(known, &known_buf, &known_len) < 0)
    return -1;

  if (unknown_len != known_len) {
    PyErr_SetString(PyExc_IndexError, "Array lengths do not match");
    return -1;
  }

  compute_distance(distance_type, known_buf, known_len, unknown_buf, distance,
                   selections, weights);

  return 0;
}

/*
  Compute the distance between a known and an unknown image with weights. This version takes
  an image and a buffer for the unknown image. Arguments must be images - no type checking
  is performed.
*/
inline int compute_distance(DistanceType distance_type, PyObject* known,
                PyObject* unknown, double* distance,
                int* selections, int selections_len,
                double* weights, int weights_len) {
  double *known_buf, *unknown_buf;
  Py_ssize_t known_len, unknown_len;

  if (image_get_fv(known, &known_buf, &known_len) < 0)
    return -1;

  if (image_get_fv(unknown, &unknown_buf, &unknown_len) < 0)
    return -1;

  if (unknown_len != known_len) {
    PyErr_SetString(PyExc_IndexError, "Array lengths do not match");
    return -1;
  }

  if (unknown_len != selections_len) {
    PyErr_SetString(PyExc_IndexError, "Array lengths do not match");
    return -1;
  }

  if (unknown_len != weights_len) {
    PyErr_SetString(PyExc_IndexError, "Array lengths do not match");
    return -1;
  }

  compute_distance(distance_type, known_buf, known_len, unknown_buf, distance,
                   selections, weights);

  return 0;
}

#endif