Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ExampleDrawConic.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 /**
26  @example ExampleDrawConic.cpp
27  @relates Conic2D, ImageDraw
28  @brief Tried to implement a new of drawing conics.
29  Unfortunately it doesn't work for some cases:
30  - hyperbolas
31  - and all other conics that have two or more parts visible on screen
32  :-(
33  @ingroup g_examples
34  @author MIP
35 */
36 
37 #include <iostream>
38 #include <sstream>
39 
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 
44 #include <Base/Image/Image.hh>
45 #include <Base/Image/ImageIO.hh>
46 #include <Base/ImageUtils/ImageDraw.hh>
47 
48 #include <Base/Geometry/HomgPoint2D.hh>
49 #include <Base/Geometry/HomgPoint3D.hh>
50 #include <Geometry/RMatrix.hh>
51 #include <Geometry/Conic2D.hh>
52 
53 using namespace BIAS;
54 using namespace std;
55 
56 
57 
58 // takes a conic and two points and returns the point that is closer to the
59 // conic
60 // if distance for both points is equal, the first will be returned
61 inline HomgPoint2D ConicMinDist(const Conic2D &conic,
62  const HomgPoint2D &p1, const HomgPoint2D &p2) {
63  if (conic.LocatePoint(p1) <= conic.LocatePoint(p2)) {
64  return p1;
65  }
66  else {
67  return p2;
68  }
69 }
70 
71 
72 bool ConicGetStartPoint(const Conic2D &conic,
73  unsigned int imageWidth, unsigned int imageHeight,
74  HomgPoint2D &startPoint) {
75  // since the conic equation is of an implicit form, we first need to find
76  // a pixel that is on (or at least near to) the conic
77  // this is done by comparing neighbouring pixel. e.g. if pixel (x, y) is
78  // inside the conic and pixel (x+1, y) is outside, then the conic is
79  // between these two pixels.
80  // first we check the image borders, so we get conics that cross the image
81  // border very fast. furthermore this necessary for the main loop, since the
82  // iteration will run from an (arbitrary) start point until the start point
83  // is reached again or the image border.
84 
85  // some vars are redundant here and could be re-used
86  HomgPoint2D p(0, 0), p1(0, 0), p2(0, 0);
87  p.Homogenize();
88  p1.Homogenize();
89  p2.Homogenize();
90  register int initialSign;
91  int initialSign1, initialSign2;
92  double dist;
93 
94  // first check upper and lower borders of the image
95  p1[1] = 0;
96  p2[1] = imageHeight - 1;
97 
98  dist = conic.LocatePoint(p1);
99  if (dist > 0.0)
100  initialSign1 = 1;
101  else if (dist < 0.0)
102  initialSign1 = -1;
103  else
104  initialSign1 = 0;
105 
106  dist = conic.LocatePoint(p2);
107  if (dist > 0.0)
108  initialSign2 = 1;
109  else if (dist < 0.0)
110  initialSign2 = -1;
111  else
112  initialSign2 = 0;
113 
114  for (register unsigned int x = 1; x < imageWidth; x++) {
115  // upper border
116  p1[0] = x;
117  dist = conic.LocatePoint(p1);
118  if (dist < 0.0 && initialSign1 > 0) {
119  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, 0), p1);
120  return true;
121  }
122  if (dist > 0.0 && initialSign1 < 0) {
123  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, 0), p1);
124  return true;
125  }
126  if (dist == 0.0) {
127  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, 0), p1);
128  return true;
129  }
130 
131  // lower border
132  p2[0] = x;
133  dist = conic.LocatePoint(p2);
134  if (dist < 0.0 && initialSign2 > 0) {
135  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, imageHeight - 1), p2);
136  return true;
137  }
138  if (dist > 0.0 && initialSign2 < 0) {
139  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, imageHeight - 1), p2);
140  return true;
141  }
142  if (dist == 0.0) {
143  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, imageHeight - 1), p2);
144  return true;
145  }
146  }
147 
148  // first check left and right borders of the image
149  p1[0] = 0;
150  p2[0] = imageWidth - 1;
151 
152  dist = conic.LocatePoint(p1);
153  if (dist > 0.0)
154  initialSign1 = 1;
155  else if (dist < 0.0)
156  initialSign1 = -1;
157  else
158  initialSign1 = 0;
159 
160  dist = conic.LocatePoint(p2);
161  if (dist > 0.0)
162  initialSign2 = 1;
163  else if (dist < 0.0)
164  initialSign2 = -1;
165  else
166  initialSign2 = 0;
167 
168  for (register unsigned int y = 1; y < imageHeight; y++) {
169  // upper border
170  p1[1] = y;
171  dist = conic.LocatePoint(p1);
172  if (dist < 0.0 && initialSign1 > 0) {
173  startPoint = ConicMinDist(conic, HomgPoint2D(0, y), p1);
174  return true;
175  }
176  if (dist > 0.0 && initialSign1 < 0) {
177  startPoint = ConicMinDist(conic, HomgPoint2D(0, y), p1);
178  return true;
179  }
180  if (dist == 0.0) {
181  startPoint = ConicMinDist(conic, HomgPoint2D(0, y), p1);
182  return true;
183  }
184 
185  // lower border
186  p2[1] = y;
187  dist = conic.LocatePoint(p2);
188  if (dist < 0.0 && initialSign2 > 0) {
189  startPoint = ConicMinDist(conic, HomgPoint2D(imageWidth - 1, y), p2);
190  return true;
191  }
192  if (dist > 0.0 && initialSign2 < 0) {
193  startPoint = ConicMinDist(conic, HomgPoint2D(imageWidth - 1, y), p2);
194  return true;
195  }
196  if (dist == 0.0) {
197  startPoint = ConicMinDist(conic, HomgPoint2D(imageWidth - 1, y), p2);
198  return true;
199  }
200  }
201 
202  // if nothing found so far, check the whole image
203  for (register unsigned int y = 0; y < imageHeight; y++) {
204  p[0] = -1;
205  p[1] = y;
206  dist = conic.LocatePoint(p);
207  if (dist > 0.0)
208  initialSign = 1;
209  else if (dist < 0.0)
210  initialSign = -1;
211  else
212  initialSign = 0;
213 
214  for (register unsigned int x = 0; x < imageWidth; x++) {
215  p[0] = x;
216  p[1] = y;
217  dist = conic.LocatePoint(p);
218  if (dist < 0.0 && initialSign > 0) {
219  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, y), p);
220  return true;
221  }
222  if (dist > 0.0 && initialSign < 0) {
223  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, y), p);
224  return true;
225  }
226  if (dist == 0.0) {
227  startPoint = ConicMinDist(conic, HomgPoint2D(x - 1, y), p);
228  return true;
229  }
230  }
231  }
232 
233  // now run in perpendicular direction to catch x-parallel lines that we missed
234  // however, this may result in a lot of cach misses, and thus is slow
235  for (register unsigned int x = 0; x < imageWidth; x++) {
236  p[0] = x;
237  p[1] = -1;
238  dist = conic.LocatePoint(p);
239  if (dist > 0.0)
240  initialSign = 1;
241  else if (dist < 0.0)
242  initialSign = -1;
243  else
244  initialSign = 0 ;
245 
246  for (register unsigned int y = 0; y < imageWidth; y++) {
247  p[0] = x;
248  p[1] = y;
249  dist = conic.LocatePoint(p);
250  if (dist < 0.0 && initialSign > 0) {
251  startPoint = ConicMinDist(conic, HomgPoint2D(x, y - 1), p);
252  return true;
253  }
254  if (dist > 0.0 && initialSign < 0) {
255  startPoint = ConicMinDist(conic, HomgPoint2D(x, y - 1), p);
256  return true;
257  }
258  if (dist == 0.0) {
259  startPoint = ConicMinDist(conic, HomgPoint2D(x, y - 1), p);
260  return true;
261  }
262  }
263  }
264 
265  return false;
266 }
267 
268 
269 void ConicShadePixel(Image<unsigned char>& image, const HomgPoint2D &p) {
270  // prepare vars
271  unsigned char *pImageData = image.GetImageData();
272 
273  const unsigned int x = (unsigned int)rint(p[0]);
274  const unsigned int y = (unsigned int)rint(p[1]);
275 
276  unsigned int offset = y * image.GetWidth() * image.GetChannelCount() +
277  x * image.GetChannelCount();
278 
279  for (unsigned int c = 0; c < image.GetChannelCount(); c++) {
280  pImageData[offset + c] = 255;
281  }
282 }
283 
284 
285 bool ConicGetNextPoint(const Conic2D &conic,
286  const Image<unsigned char> &visitedPoints,
287  const HomgPoint2D &curPoint,
288  HomgPoint2D &nextPoint) {
289  HomgPoint2D p(0, 0), q(0, 0);
290  p.Homogenize();
291  q.Homogenize();
292 
293  double distP, distQ;
294  bool pUnvisited, qUnvisited;
295 
296  const unsigned char **pVisitedPoints = visitedPoints.GetImageDataArray();
297 
298  cout << "getting next point" << endl;
299 
300  // iterate over a 3x3 patch around curPoint
301  for (int y = -1; y <= 1; y++) {
302  for (int x = -1; x <= 1; x++) {
303  p[0] = curPoint[0] + x;
304  p[1] = curPoint[1] + y;
305 
306  // compare to right neighbour
307  if (x < 1) {
308  q[0] = p[0] + 1;
309  q[1] = p[1];
310 
311  distP = conic.LocatePoint(p);
312  distQ = conic.LocatePoint(q);
313 
314  pUnvisited =
315  pVisitedPoints[(unsigned int)p[0]][(unsigned int)p[1]] == 0;
316  qUnvisited =
317  pVisitedPoints[(unsigned int)q[0]][(unsigned int)q[1]] == 0;
318 
319  if (distP == 0.0 && pUnvisited) {
320  nextPoint = p;
321  return true;
322  }
323  if (distQ == 0.0 && qUnvisited) {
324  nextPoint = q;
325  return true;
326  }
327  if ((distP < 0.0 && distQ > 0.0) || (distP > 0.0 && distQ < 0.0)) {
328  if (pUnvisited && qUnvisited) {
329  nextPoint = ConicMinDist(conic, p, q);
330  return true;
331  }
332  }
333  }
334 
335  // compare to lower neighbour
336  if (y < 1) {
337  q[0] = p[0];
338  q[1] = p[1] + 1;
339 
340  distP = conic.LocatePoint(p);
341  distQ = conic.LocatePoint(q);
342 
343  pUnvisited =
344  pVisitedPoints[(unsigned int)p[0]][(unsigned int)p[1]] == 0;
345  qUnvisited =
346  pVisitedPoints[(unsigned int)q[0]][(unsigned int)q[1]] == 0;
347 
348  if (distP == 0.0 && pUnvisited) {
349  nextPoint = p;
350  return true;
351  }
352  if (distQ == 0.0 && qUnvisited) {
353  nextPoint = q;
354  return true;
355  }
356  if ((distP < 0.0 && distQ > 0.0) || (distP > 0.0 && distQ < 0.0)) {
357  if (pUnvisited && qUnvisited) {
358  nextPoint = ConicMinDist(conic, p, q);
359  return true;
360  }
361  }
362  }
363  }
364  }
365 
366  return false;
367 }
368 
369 
370 int DrawConic(Image<unsigned char>& image, Conic2D &conic) {
371  HomgPoint2D lastPoint, curPoint;
372 
373  Image<unsigned char> visitedPoints(image.GetWidth(), image.GetHeight(), 1);
374  visitedPoints.SetZero();
375  unsigned char **pVisitedPoints = visitedPoints.GetImageDataArray();
376 
377  if (!ConicGetStartPoint(conic, image.GetWidth(), image.GetHeight(), curPoint)) {
378  // conic is outside of image or - if it is an ellipse - the radius is
379  // less than 1 pixel
380  return 1;
381  }
382 
383  cout << endl << "got start point " << curPoint << endl;
384 
385  ConicShadePixel(image, curPoint);
386  pVisitedPoints[(unsigned int)curPoint[0]][(unsigned int)curPoint[1]] = 1;
387 
388  // iterate over conic
389  lastPoint = curPoint;
390  while (ConicGetNextPoint(conic, visitedPoints, lastPoint, curPoint)) {
391  cout << "got next point " << curPoint << endl;
392 
393  ConicShadePixel(image, curPoint);
394  pVisitedPoints[(unsigned int)curPoint[0]][(unsigned int)curPoint[1]] = 1;
395  lastPoint = curPoint;
396  }
397 
398  return 0;
399 }
400 
401 
402 
403 /**
404  * Simple example that draws some conics
405  */
406 int main(int argc, char** argv) {
407  Image<unsigned char> image(400, 400, 1);
408  image.SetZero();
409 
410  Conic2D conic;
411  conic.SetEllipse(HomgPoint2D(200, 200), M_PI, 50, 50);
412 
413  // kevin's conic plotter
414  conic.Draw(image);
415  ImageIO::Save("conicKK.mip", image);
416 
417  image.SetZero();
418 
419  // my conic plotter
420  DrawConic(image, conic);
421  ImageIO::Save("conicRW.mip", image);
422 
423  return 0;
424 }
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
Definition: HomgPoint2D.hh:67
HomgPoint2D & Homogenize()
homogenize class data member elements to W==1 by divison by W
Definition: HomgPoint2D.hh:215
void SetEllipse(const HomgPoint2D &Center, const double &dAngle, const double &radius_a, const double &radius_b)
construct an ellipse with explicit parameters
Definition: Conic2D.cpp:299
unsigned int GetWidth() const
Definition: ImageBase.hh:312
double LocatePoint(const HomgPoint2D &point2D) const
determines if the point is inside/on/outside the conic
Definition: Conic2D.hh:144
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
unsigned int GetHeight() const
Definition: ImageBase.hh:319
static int Save(const std::string &filename, const ImageBase &img, const enum TFileFormat FileFormat=FF_auto, const bool sync=BIAS_DEFAULT_SYNC, const int c_jpeg_quality=BIAS_DEFAULT_IMAGE_QUALITY, const bool forceNewID=BIAS_DEFAULT_FORCENEWID, const bool &writeMetaData=true)
Export image as file using extrnal libs.
Definition: ImageIO.cpp:725
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
void Draw(Image< unsigned char > &img) const
draws conic into an image using a brute force method
Definition: Conic2D.cpp:221
A 3x3 matrix representing a conic (cone/plane intersection)
Definition: Conic2D.hh:71
void SetZero()
zeroes the image
Definition: ImageBase.hh:83
class BIASGeometryBase_EXPORT HomgPoint2D
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153