File: wxSubFrame.cpp

package info (click to toggle)
wxastrocapture 1.8.1%2Bgit20140821.796e1a1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 42,212 kB
  • sloc: cpp: 43,421; sh: 733; perl: 246; makefile: 14
file content (435 lines) | stat: -rw-r--r-- 12,306 bytes parent folder | download | duplicates (4)
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
#include "wxSubFrame.h"
#include <wx/utils.h>
#include <wx/timer.h>

// === helper class image2d

/*
   image2d.
   This extremely lightweight image class just borrows the wxImage data pointer temporarily,
   and provides a convenient wrapper around it to allow fast, easy and cheap access to pixels.
*/


class image2d {
public:
   image2d(unsigned char* image, int xdim, int ydim) : m_image(image),m_xdim(xdim),m_ydim(ydim) {}
   unsigned char* operator()(const int& x,const int& y) const { return m_image + y*m_xdim*3 + x*3 + m_chan; }
   int xdim() const {return int(m_xdim);}
   int ydim() const {return int(m_ydim);}
   int pixel_id(const int& x,const int& y) const { return y*m_xdim + x;}
private:
   unsigned char* m_image;
   int m_xdim;
   int m_ydim;
   static const int m_chan = 1;  // 0=R, 1=G, 2=B
};

// === end helper class

unsigned char  wxSubFrame::m_limit=100;
double         wxSubFrame::m_angle = 0;
double         wxSubFrame::m_imageScale=1.0;

const double pi = 4.0*atan(1.0);

double wxSubFrame::cameraAngle()
{
   return 180*m_angle/pi;
}

void wxSubFrame::setCameraAngle(double degrees)
{
   m_angle = pi*degrees/180.0;
}

double wxSubFrame::imageScale()
{
   return m_imageScale;
}

void wxSubFrame::setImageScale(double imageScale)
{
   m_imageScale = imageScale;
}

unsigned char wxSubFrame::cutoffLimit()
{
   return m_limit;
}

void wxSubFrame::setCutoffLimit(unsigned char limit)
{
   m_limit = limit;
}

wxSubFrame::wxSubFrame()
: m_timestamp_ms(0)
, m_locked(false)
, m_inverted(false)
{}

void wxSubFrame::setFrameInfo(const wxSize& fullsiz       // full frame size
                             ,const wxSize& subsiz        // subframe size
                             ,const wxRealPoint& subcen)  // subframe centre point in full frame
{
  m_fullsiz = fullsiz;
  m_subsiz  = subsiz;
  m_lockcen = subcen;
  m_curcen  = subcen;
  m_timestamp_ms = 0;
  m_locked = false;
}

wxSubFrame::~wxSubFrame()
{}

unsigned long wxSubFrame::timestamp_ms()
{
   return m_timestamp_ms;
}

// extract guiding subframe from fullframe
bool wxSubFrame::copySubFrame(const wxImage& fullframe, bool inverted)
{
   int fw  = fullframe.GetWidth();
   int fh  = fullframe.GetHeight();

   // if image has been inverted since we last saw it, we must invert the coords here
   if(m_locked && (m_inverted != inverted)) {
      m_curcen.y  = fh - m_curcen.y;
      m_lockcen.y = fh - m_lockcen.y;
   }

   m_inverted = inverted;

   // calculate lower left position of subframe in source
   // make sure low end of rectangle is within full frame
   int xlo = int(m_curcen.x - m_subsiz.x/2);
   int ylo = int(m_curcen.y - m_subsiz.y/2);

   if(xlo < 0)xlo = 0;
   if(ylo < 0)ylo = 0;

   // check high end of rectangle
   int xhi = xlo + m_subsiz.x;
   int yhi = ylo + m_subsiz.y;
   if( xhi >= fw) xlo = fw - (m_subsiz.x+1);
   if( yhi >= fh) ylo = fh - (m_subsiz.y+1);


   // record the actual centre position of the subframe
   m_curcen.x = xlo + m_subsiz.x/2;
   m_curcen.y = ylo + m_subsiz.y/2;

   // actually compute final rectangle and copy out the subframe
   wxPoint p1(xlo,ylo);
   wxRect rect(p1,m_subsiz);

   m_subframe = fullframe.GetSubImage(rect);
   if(inverted) {

      // The subframe must be flipped
      int w = m_subframe.GetWidth();
      int h = m_subframe.GetHeight();
      int line_size = 3*w;
      unsigned char* pix = m_subframe.GetData();
      unsigned char* cur = pix;
      unsigned char* mir = cur + line_size*(h-1);
      unsigned char* swp = new unsigned char[line_size];
      for(int iline=0; iline<h/2; iline++) {
         memcpy(swp,cur,line_size);
         memcpy(cur,mir,line_size);
         memcpy(mir,swp,line_size);
         cur += line_size;
         mir -= line_size;
      }
      delete[] swp;

 //     m_subframe = m_subframe.Mirror(false);
   }
/*
   m_subframe.SaveFile(wxT("subframe.bmp"),wxBITMAP_TYPE_BMP);
   exit(0);
*/
   // set the timestamp of the subframe
   m_timestamp_ms = computeTimeStampMillis();
   return true;
}

// computes a millisecond based time stamp for this time instant
unsigned long wxSubFrame::computeTimeStampMillis()
{
   // based on BM-20090411 - fixup the clock issue

   /*
      why clock() is unreliable
      ========================
      i) it is the CPU time in cpu clocks used by the program so far and NOT the
      clock time the program runs as the name suggests
      ii) the man page says that CLOCKS_PER_SEC must be 1000000 to be POSIX
      compliant independent of the resolution
      Which means that Linux ist POSIX compliant and Win does not bother.

      Instead we use wxGetLocalTimeMillis() which returns time since 1.1.1970
      in milliseconds. This is absolute time and using wxLongLong. We don't want or
      need absolute time. We just use the lower part of the _int64 which is
      ts.GetLo(), it returns the remainder of the division ts / 2^32 or the
      low unsigned int of that number - that is where the ms counting takes place,
      the High part is only to cope with the 1.1.1970 timespan in ms.

      The result is a timestamp in ms units that is able to represent at least
      49.7 day long time spans.
   */

   wxLongLong ts= wxGetLocalTimeMillis();
   unsigned long timestamp = ts.GetLo(); //return the lower part only
   return timestamp;
}


bool wxSubFrame::FindStar(wxStar& subframe_star)
{
   DonePixels done_pixels,done_paint;

   bool success = false;

   // scan the frame for the highest magnitude pixel
   // and paint the star in that position

   image2d subframe(m_subframe.GetData(),m_subframe.GetWidth(),m_subframe.GetHeight());
   int xdim = subframe.xdim();
   int ydim = subframe.ydim();
   for(int y=1; y<ydim-1; y++) {
      for(int x=1; x<xdim-1; x++) {

         // get current pixel
         unsigned char* pixel = subframe(x,y);

         // check to see if pixel value is over cutoff limit
         if(*pixel > m_limit) {

            // Find the local peak
            unsigned long peak_mag=0;
            int x_peak=-1;
            int y_peak=-1;
            FindPeak(subframe,done_pixels,x,y,peak_mag,x_peak,y_peak);

            // initialise a star from the peak value and mark the pixel location as painted
            wxStar local_star(x_peak,y_peak,peak_mag);
            done_paint.insert(subframe.pixel_id(x_peak,y_peak));

            int recursion = 0;
            PaintStar(subframe,local_star,x_peak,y_peak, done_paint,recursion);
            if(local_star.mag() > subframe_star.mag()) {

               // this was a star of greater magnitude
               subframe_star = local_star;
               success = true;
            }
         }
      }
   }

   return success;
}


void wxSubFrame::PaintStar(const image2d& subframe, wxStar& star, int x, int y, DonePixels& done, int& recursion)
{
   // if recursion is too extreme, give up.
   // The program will eventually crash with stack overflow if this protection is not in place
   ++recursion;
   if(recursion < 64) {

      int xdim = subframe.xdim();
      int ydim = subframe.ydim();

      // look one pixel in all directions from the given point
      for(int yy=y-1; yy<=y+1; yy++) {

         if(yy <     0)continue;
         if(yy >= ydim)continue;

         for(int xx=x-1; xx<=x+1; xx++) {

            if(xx <    0)continue;
            if(xx >= xdim)continue;

            // if we have seen this pixel before, skip it
            int key = subframe.pixel_id(xx,yy);
            if(done.find(key) != done.end()) continue;
            done.insert(key);

            // ok, unseen pixel, so add it to our star if it is above limit
            unsigned char* pixel = subframe(xx,yy);
            if(*pixel > m_limit) {
               star.add(wxStar(xx,yy,*pixel));

               // continue painting
               PaintStar(subframe,star,xx,yy,done,recursion);
            }
         }
      }
   }
   --recursion;

}

bool wxSubFrame::FindPeak(const image2d& subframe, DonePixels& done_pixels, int x, int y, unsigned long& peak_mag, int& xmax, int& ymax)
{
   int xdim = subframe.xdim();
   int ydim = subframe.ydim();

   // initial values
   peak_mag = *subframe(x,y);
   xmax = x;
   ymax = y;

   // mark this pixel as visited
   done_pixels.insert(subframe.pixel_id(x,y));

   // check neigbour pixels for larger values
   const int delta=1;
   for(int yy=y-delta; yy<=y+delta; yy++) {

      // don't look outside frame
      if(yy<0)continue;
      if(yy>=ydim)continue;

      for(int xx=x-delta; xx<=x+delta; xx++) {

         // don't look outside frame
         if(xx<0)continue;
         if(xx>=xdim)continue;

         if(xx!=x && yy!=y) {
            unsigned char* neighbour = subframe(xx,yy);
            if(*neighbour > peak_mag) {

               // check that this pixel has not been visited before
               if(done_pixels.find(subframe.pixel_id(x,y)) == done_pixels.end()) {
                  // new peak value found, recurse
                  FindPeak(subframe, done_pixels,xx,yy,peak_mag,xmax,ymax);
               }
            }
         }
      }
   }
   return true;
}

bool wxSubFrame::lock(wxStar& offset_star)
{
   if(!m_locked) {

      wxStar star;
      if(FindStar(star)) {

         updateFrameCentre(star);

         // the lock position is also the current position initially
         m_lockcen = m_curcen;

         // just return a zero offset star
         offset_star = wxStar(0,0,star.mag());

         m_locked = true;
      }
   }
   return m_locked;
}

void wxSubFrame::updateFrameCentre(wxStar& subframe_star)
{
   // values for half width and half height
   double hsdimx = m_subsiz.x/2;
   double hsdimy = m_subsiz.y/2;

   double sign = (m_inverted)? -1.0 : 1.0;

   // convert the star subframe coordinates to fullframe coordinates
   double test_x = m_curcen.x + subframe_star.x() - hsdimx;
   double test_y = m_curcen.y + sign*subframe_star.y() - sign*hsdimy;

   // will the subframe extend beyond the fullframe border if we center
   // the subframe on the found guide star?

   // adjust the subframe centre point so that the box
   // does not go beyond the fullframe
   if( (test_x-hsdimx) <            0) test_x = hsdimx;
   if( (test_x+hsdimx) >= m_fullsiz.x) test_x = m_fullsiz.x-hsdimx-1;

   if( (test_y-hsdimy) <            0) test_y = hsdimy;
   if( (test_y+hsdimy) >= m_fullsiz.y) test_y = m_fullsiz.y-hsdimy-1;

   // set the computed centre position
   m_curcen.x = test_x;
   m_curcen.y = test_y;
}


bool wxSubFrame::getOffset(wxRealPoint& offset)
{
   if(m_locked) {
      offset = m_curcen - m_lockcen;

      double sign = (m_inverted)? 1.0 : -1.0;

      // allow for camera rotation
      double cosang = m_imageScale*cos(m_angle);
      double sinang = m_imageScale*sin(m_angle);

      double ra  = cosang*offset.x - sign*sinang*offset.y;
      double dec = sinang*offset.x + sign*cosang*offset.y;
      offset.x = ra;
      offset.y = dec;

      return true;
   }
   return false;
}

// find the guidestar and return its position in pixels relative to the locked position.
// If the guidestar is unlocked, a lock will be established.
// The function returns false if the guidestar was not found in the subframe
bool wxSubFrame::guide(wxStar& offset_star)
{
   if(!m_locked) {
      m_locked = lock(offset_star);
   }
   else {
      wxStar framestar;
      if(FindStar(framestar)) {
         updateFrameCentre(framestar);

         // compute the RA, DEC offset
         wxRealPoint offset;
         getOffset(offset);
         offset_star = wxStar( offset.x,offset.y,framestar.mag());
      }
      else {

         // guide star lost, sound a bell
         wxBell();
         return false;
      }
   }

   return m_locked;
}

const wxRealPoint& wxSubFrame::centre() const
{
   return m_curcen;
}

const wxSize& wxSubFrame::size() const
{
   return m_subsiz;
}

const wxRealPoint& wxSubFrame::lockpos() const
{
   return m_lockcen;
}