Code

  1 #include "ipdp.h"
  2 
  3 #include <iostream>
  4 
  5 using namespace std;
  6 using namespace ipdp;
  7 
  8 ///////////////////////////////////////////////////////////////////////////////
  9 // Copy the image data to internal memory
 10 //
 11 image::image(const int *data, const int *shape, const int nDim):
 12     posDomain(0),
 13     posRefNeighbourhood(-1),
 14     input(NULL),
 15     shape(NULL),
 16     work(NULL),
 17     label(NULL),
 18     offsetsShape(NULL),
 19     workShape(NULL),
 20     roffsets(NULL)
 21 {
 22     eErrorCode = NO_ERROR;
 23 
 24     // calculate the number of pixels on the original image
 25     this->nPixels = shape[0];
 26     for (int i=1; i<nDim; i++)
 27         this->nPixels *= shape[i];
 28 
 29     try
 30     {
 31         // alloc the internal image
 32         this->input = new int[this->nPixels];
 33         memcpy(this->input, data, sizeof(int)*this->nPixels);
 34     }
 35     catch (std::bad_alloc ba)
 36     {
 37         this->eErrorCode = ALLOC_ERROR;
 38     }
 39 
 40     // copy the shape
 41     try
 42     {
 43         this->shape = new int[nDim];
 44         memcpy(this->shape, shape, sizeof(int)*nDim);
 45     }
 46     catch (std::bad_alloc ba)
 47     {
 48         this->eErrorCode = ALLOC_ERROR;
 49     }
 50 
 51     // and dimensions
 52     this->nDim = nDim;
 53 
 54     // initialize pointers
 55     this->work = NULL;
 56     this->label = NULL;
 57 }
 58 
 59 ///////////////////////////////////////////////////////////////////////////////
 60 // Free resources
 61 //
 62 image::~image()
 63 {
 64     if (this->input != NULL)
 65         delete[] this->input;
 66     if (this->shape != NULL)
 67         delete[] this->shape;
 68     if (this->work != NULL)
 69         delete[] this->work;
 70     if (this->label != NULL)
 71         delete[] this->label;
 72     if (this->offsetsShape != NULL)
 73         delete[] this->offsetsShape;
 74     if (this->workShape != NULL)
 75         delete[] this->workShape;
 76     if (this->roffsets != NULL)
 77         delete[] this->roffsets;
 78 
 79     for (auto it = this->vecWorkImages.begin();
 80         it != this->vecWorkImages.end();
 81         it++)
 82     {
 83         delete[] *it;
 84     }
 85 }
 86 
 87 ///////////////////////////////////////////////////////////////////////////////
 88 // Create the working images
 89 //
 90 void image::begin(const int *offsets, const int nOffsets)
 91 {
 92     this->nOffsets = nOffsets;
 93     //
 94     // Calculate the shape of the offsets and of the working image
 95     //
 96     try
 97     {
 98         this->offsetsShape = new int[this->nDim];
 99         this->workShape = new int[this->nDim];
100     }
101     catch (std::bad_alloc ba)
102     {
103         this->eErrorCode = ALLOC_ERROR;
104         return;
105     }
106 
107     this->nWorkPixels = 1;
108     for (int dim = 0; dim < this->nDim; dim++)
109     {
110         int nMin = INT_MAX,
111             nMax = INT_MIN,
112             delta = 0;
113 
114         for (int ix = 0; ix < nOffsets; ix++)
115         {
116             nMin = min(offsets[ix*this->nDim + dim], nMin);
117             nMax = max(offsets[ix*this->nDim + dim], nMax);
118         }
119 
120         // check for symmetry
121         if (abs(nMin) != abs(nMax))
122         {
123             this->eErrorCode = DIMENSION_ERROR;
124             return;
125         }
126 
127         delta = nMax - nMin + 1;
128         this->offsetsShape[dim] = delta + (delta % 2 == 0 ? 1 : 0);
129         this->workShape[dim] = this->shape[dim] + delta - 1;
130         this->nWorkPixels *= this->workShape[dim];
131     }
132 
133     //
134     // Create the working image of input
135     //
136     this->pad(&(this->work), this->input, workShape, this->shape, this->nDim);
137 
138     //
139     // Create the working image of labels
140     //
141     try
142     {
143         this->label = new int[this->nWorkPixels];
144         memset(this->label, 0, sizeof(int)*this->nWorkPixels);
145     }
146     catch (std::bad_alloc ba)
147     {
148         this->eErrorCode = ALLOC_ERROR;
149         return;
150     }
151 
152 
153     //
154     // Calculate rasterized offsets
155     // See python code for explanation
156     //
157     try
158     {
159         this->roffsets = new int[nOffsets];
160     }
161     catch (std::bad_alloc ba)
162     {
163         this->eErrorCode = ALLOC_ERROR;
164         return;
165     }
166 
167     for (int ix = 0; ix < nOffsets; ix++)
168     {
169         int roffset = 0;
170         for (int dim = 0; dim < this->nDim; dim++)
171         {
172             int n = offsets[ix*this->nDim + dim];
173             for (int dim_shape = dim + 1; dim_shape < this->nDim; dim_shape++)
174             {
175                 n *= this->workShape[dim_shape];
176             }
177             roffset += n;
178         }
179         roffsets[ix] = roffset;
180     }
181 
182 }
183 
184 ///////////////////////////////////////////////////////////////////////////////
185 // Crop the image
186 //
187 int *image::end()
188 {
189     int *output;
190     this->crop(&output, this->label, this->shape, this->workShape, this->nDim);
191     return output;
192 }
193 
194 ///////////////////////////////////////////////////////////////////////////////
195 // Iterate on the neighbourhood
196 //
197 int image::N(const int p)
198 {
199     if (p != this->posRefNeighbourhood)
200     {
201         this->posRefNeighbourhood = p;
202         this->ixRoffset = 0;
203     }
204 
205     if (this->ixRoffset >= this->nOffsets)
206     {
207         return this->domainEnd();
208     }
209 
210     int posNeigh = p + this->roffsets[this->ixRoffset++];
211     while (this->isBorder(posNeigh))
212     {
213         if (this->ixRoffset >= this->nOffsets)
214         {
215             return this->domainEnd();
216         }
217         posNeigh = p + this->roffsets[this->ixRoffset++];
218     }
219 
220     return posNeigh;
221 }
222 
223 ///////////////////////////////////////////////////////////////////////////////
224 // Start the domain iteration
225 //
226 int image::domainBegin()
227 {
228     this->posDomain = 0; // may be optimized to skip border
229     return this->domainNext();
230 }
231 
232 ///////////////////////////////////////////////////////////////////////////////
233 // Visit the next on domain
234 //
235 int image::domainNext()
236 {
237     if (this->posDomain >= this->domainEnd())
238     {
239         posDomain = 0;
240         return this->domainEnd();
241     }
242 
243     while (this->isBorder(this->posDomain))
244     {
245         posDomain++;
246         if (this->posDomain >= this->domainEnd())
247         {
248             posDomain = 0;
249             return this->domainEnd();
250         }
251     }
252 
253     return posDomain++;
254 }
255 
256 ///////////////////////////////////////////////////////////////////////////////
257 // End of domain
258 //
259 int image::domainEnd()
260 {
261     return this->nWorkPixels; // may be optimized
262 }
263 
264 ///////////////////////////////////////////////////////////////////////////////
265 // Get the working input image
266 //
267 int *image::getWorkInput() const
268 {
269     return this->work;
270 }
271 
272 ///////////////////////////////////////////////////////////////////////////////
273 // Get the working output
274 //
275 int *image::getWorkOutput() const
276 {
277     return this->label;
278 }
279 
280 ///////////////////////////////////////////////////////////////////////////////
281 // Generate an image with the same size of working input/output
282 //
283 int *image::makeWorkImage(const int default_value)
284 {
285     int *newWork;
286     try
287     {
288         newWork = new int[this->nWorkPixels];
289     }
290     catch (std::bad_alloc ba)
291     {
292         this->eErrorCode = ALLOC_ERROR;
293         return NULL;
294     }
295 
296     std::fill(newWork, newWork + this->nWorkPixels, default_value);
297 
298     vecWorkImages.push_back(newWork);
299 
300     return newWork;
301 }
302 
303 ///////////////////////////////////////////////////////////////////////////////
304 // Test if a pixel is a border
305 //
306 bool image::isBorder(int p)
307 {
308     if (this->work == NULL)
309     {
310         this->eErrorCode = ALLOC_ERROR;
311         return true;
312     }
313     return this->work[p] == BORDER;
314 }
315 
316 ///////////////////////////////////////////////////////////////////////////////
317 // Pad a src image to be centered on dest with destshape
318 //
319 void image::pad(int **dest, const int *src, const int *destshape, const int *srcshape, const int nDim)
320 {
321     *dest = NULL;
322     this->eErrorCode = NO_ERROR;
323     //
324     // Currently only supports 2-dimensional image
325     //
326     if (nDim != 2)
327     {
328         this->eErrorCode = UNSUPPORTED_OPERATION;
329         return;
330     }
331 
332     int nPixels = 1;
333     auto_ptr<int> nOffsets(new int[nDim]);
334     for (int i=0; i<nDim; i++)
335     {
336         nPixels *= destshape[i];
337         nOffsets.get()[i] = (destshape[i] - srcshape[i]) / 2; // assume symmetry
338         if (nOffsets.get()[i] < 0)
339         {
340             this->eErrorCode = UNSUPPORTED_OPERATION;
341             return;
342         }
343     }
344 
345     try
346     {
347         *dest = new int[nPixels];
348     }
349     catch (std::bad_alloc ba)
350     {
351         this->eErrorCode = ALLOC_ERROR;
352         return;
353     }
354 
355     memset(*dest, 0xFF, sizeof(int)*nPixels);
356 
357     //
358     // This is the part specific for 2 dimensions
359     //
360     for (int i=nOffsets.get()[0], k=0; i < destshape[0] - nOffsets.get()[0]; i++, k++)
361     {
362         memcpy((*dest) + (destshape[1]*i + nOffsets.get()[1]),
363                src + srcshape[1]*k,
364                sizeof(int)*srcshape[1]);
365     }
366 }
367 
368 ///////////////////////////////////////////////////////////////////////////////
369 //
370 //
371 void image::crop(int **dest, const int *src, const int *destshape, const int *srcshape, const int nDim)
372 {
373     *dest = NULL;
374     this->eErrorCode = NO_ERROR;
375     //
376     // Currently only supports 2-dimensional image
377     //
378     if (nDim != 2)
379     {
380         this->eErrorCode = UNSUPPORTED_OPERATION;
381         return;
382     }
383 
384     int nPixels = 1;
385     auto_ptr<int> nOffsets(new int[nDim]);
386     for (int i=0; i<nDim; i++)
387     {
388         nPixels *= destshape[i];
389         nOffsets.get()[i] = (srcshape[i] - destshape[i]) / 2; // assume symmetry
390         if (nOffsets.get()[i] < 0)
391         {
392             this->eErrorCode = UNSUPPORTED_OPERATION;
393             return;
394         }
395     }
396 
397     try
398     {
399         *dest = new int[nPixels];
400     }
401     catch (std::bad_alloc ba)
402     {
403         this->eErrorCode = ALLOC_ERROR;
404         return;
405     }
406 
407     memset(*dest, 0xFF, sizeof(int)*nPixels);
408 
409     //
410     // This is the part specific for 2 dimensions
411     //
412     for (int i=nOffsets.get()[0], k=0; i < srcshape[0] - nOffsets.get()[0]; i++, k++)
413     {
414         memcpy((*dest) + destshape[1]*k,
415                src + (srcshape[1]*i + nOffsets.get()[1]),
416                sizeof(int)*destshape[1]);
417     }
418 }
419 
420 int main()
421 {
422     int data[9] = {1,2,3,4,5,6,7,8,9};
423     int shape[2] = {3,3};
424     image i(data, shape, 2);
425     i.begin(N4, 4);
426     int *work = i.getWorkInput();
427     int *lab = i.getWorkOutput();
428 
429     for (int p = i.domainBegin();
430              p < i.domainEnd();
431              p = i.domainNext())
432     {
433         lab[p] = work[p] * 2;
434     }
435 
436     int *output = i.end();
437     for (int i=0;i<3;i++)
438     {
439         for (int j=0;j<3;j++)
440             cout << output[i*3+j] << ' ';
441         cout << endl;
442     }
443 
444     delete[] output;
445 
446 
447     int i2;
448     cin >> i2;
449 }
OK