root/modules/edgeoverlay.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_viewport_size
  2. ensure_allocate_imagebuffer
  3. reset_edge_overlay
  4. is_buffer_ready
  5. get_edge_file_num
  6. save_edge_overlay
  7. load_edge_overlay
  8. average_filter_row
  9. calc_edge_overlay
  10. draw_edge_overlay
  11. set_offset_from_overlap
  12. edge_overlay
  13. _module_loader
  14. _module_unloader
  15. _module_can_unload

   1 #include "camera_info.h"
   2 #include "conf.h"
   3 #include "keyboard.h"
   4 #include "modes.h"
   5 #include "viewport.h"
   6 #include "shooting.h"
   7 #include "stdlib.h"
   8 #include "gui.h"
   9 #include "gui_draw.h"
  10 #include "gui_lang.h"
  11 #include "bitvector.h"
  12 
  13 #include "edgeoverlay.h"
  14 #include "module_def.h"
  15 
  16 //-------------------------------------------------------------------
  17 
  18 // the way we save edge overlays on their own...
  19 #define EDGE_FILE_PREFIX "EDG_"
  20 #define EDGE_FILE_FORMAT EDGE_FILE_PREFIX "%04d.edg"
  21 #define EDGE_SLICES     2
  22 
  23 // steps for up/down/left/right moving the overlay in ALT mode
  24 #define XINC 6
  25 #define YINC 2
  26 
  27 typedef enum _edge_fsm_state
  28 {
  29     EDGE_LIVE = 0,
  30     EDGE_FROZEN
  31 } edge_fsm_state_t;
  32 
  33 static edge_fsm_state_t fsm_state = EDGE_LIVE;
  34 static bit_vector_t* edgebuf = NULL;
  35 static int xoffset = 0, yoffset = 0;
  36 static unsigned char* smbuf = NULL;
  37 
  38 static int slice = 0;           // the current slice of the frame we are calculating/drawing
  39 static int slice_height;        // the height of a single slice
  40 
  41 static int viewport_byte_width; // width in bytes of one viewport line ??
  42 static int viewport_yscale;     // Y multiplier (for cameras with 480 pixel high viewports)
  43 static int viewport_height;     // height of visible / used area of viewport
  44 static int viewport_width;      // width of visible / used area of viewport (in 3 byte units)
  45 static int viewport_xoffset;    // used when image size != viewport size (e.g. wide screen image on 4:3 LCD)
  46 static int viewport_yoffset;    // used when image size != viewport size (e.g. wide screen image on 4:3 LCD)
  47 
  48 static void get_viewport_size()
  49 {
  50     viewport_height = vid_get_viewport_height()-camera_screen.edge_hmargin*2; //don't trace bottom lines
  51     viewport_width = vid_get_viewport_width();
  52     viewport_byte_width = vid_get_viewport_byte_width();
  53     viewport_yscale = vid_get_viewport_yscale();
  54 
  55         viewport_xoffset = vid_get_viewport_display_xoffset();
  56         viewport_yoffset = vid_get_viewport_display_yoffset();
  57 
  58     slice_height = viewport_height / EDGE_SLICES;
  59 }
  60 
  61 static void ensure_allocate_imagebuffer()
  62 {
  63     if (edgebuf == NULL)
  64     {
  65         edgebuf = bv_create(viewport_height * viewport_width, 1);
  66         if (edgebuf != NULL)
  67             memset(edgebuf->ptr, 0, edgebuf->ptrLen);
  68     }
  69     if (conf.edge_overlay_filter && (smbuf == NULL))
  70     {
  71         smbuf = (unsigned char*)malloc(viewport_byte_width*3);
  72         if (smbuf != NULL)
  73             memset(smbuf, 0, viewport_byte_width*3);
  74         else
  75         {
  76             // Disable filtering if we do not have enough memory for it
  77             conf.edge_overlay_filter = 0;
  78         }
  79     }
  80 }
  81 
  82 static void reset_edge_overlay()
  83 {
  84     if (smbuf != NULL)
  85     {
  86         free(smbuf);
  87         smbuf = NULL;
  88     }
  89 
  90     if (edgebuf != NULL)
  91     {
  92         gui_set_need_restore();     // Refresh display to restore Canon OSD
  93         bv_free(edgebuf);
  94         edgebuf = NULL;
  95     }
  96 
  97     fsm_state = EDGE_LIVE;
  98     slice = 0;
  99 
 100     // Clean up state saved in core CHDK
 101     module_save_edge(edgebuf, fsm_state);
 102 }
 103 
 104 static int is_buffer_ready()
 105 {
 106     if (edgebuf == NULL) return 0;
 107     if (edgebuf->ptr == NULL) return 0; // this should never happen, but it does not hurt to check
 108     return 1;
 109 }
 110 
 111 // scans a filename for the number of the edge detection file it contains
 112 static int get_edge_file_num(const char* fn)
 113 {
 114     int num = 0;
 115     if( strncmp(fn,EDGE_FILE_PREFIX,sizeof(EDGE_FILE_PREFIX)-1) == 0 )
 116     {
 117         // has the correct beginning at least, now try to read as a number...
 118         fn += sizeof(EDGE_FILE_PREFIX);
 119         while( *fn == '0' ) // skip leading 0s
 120         {
 121             ++fn;
 122         }
 123         while( isdigit(*fn) )
 124         {
 125             num *= 10;
 126             num += *fn - '0';
 127             ++fn;
 128         }
 129         // ignore anything else after it, that is like the ending etc.
 130     }
 131     return num;
 132 }
 133 
 134 // saves the actual active overlay data to a file.
 135 void save_edge_overlay(void)
 136 {
 137 
 138     char fn[64];
 139     char msg[64];
 140     FILE *fd;
 141     DIR* d;
 142     int fnum = 0;
 143     int fr = 0;
 144     int zoom = 0;
 145     struct dirent* de;
 146     static struct utimbuf t;
 147     // nothing to save? then dont save
 148 
 149     if( !is_buffer_ready() )
 150     {
 151         draw_string(0, 0, "No overlay to save.", user_color(conf.osd_color));
 152         return;
 153     }
 154 
 155     zoom = shooting_get_zoom();
 156 
 157     // first figure out the most appropriate filename to use
 158     d = opendir(EDGE_SAVE_DIR);
 159     if( ! d )
 160     {
 161         return;
 162     }
 163 
 164     while( (de = readdir(d)) )
 165     {
 166         fr = get_edge_file_num(de->d_name);
 167         if( fr > fnum )
 168         {
 169             fnum = fr;
 170         }
 171     }
 172     ++fnum; // the highest is set, we use the next one
 173     get_viewport_size();
 174     // open the right file
 175     sprintf(fn, EDGE_SAVE_DIR "/" EDGE_FILE_FORMAT, fnum );
 176     fd = fopen(fn, "wb");
 177     if(fd !=NULL)
 178     {
 179         // write the data
 180         fwrite(edgebuf->ptr,edgebuf->ptrLen,1,fd);
 181         fwrite(&zoom,sizeof(zoom),1,fd);
 182         fclose(fd);
 183         t.actime = t.modtime = time(NULL);
 184         utime(fn, &t);
 185         sprintf(msg, "Saved as %s",fn);
 186         draw_string(0, 0, msg, user_color(conf.osd_color));
 187     }
 188     closedir(d);
 189 }
 190 
 191 // load the edge overlay from a file
 192 void load_edge_overlay(const char* fn)
 193 {
 194     FILE *fd;
 195     int zoom;
 196 
 197     get_viewport_size();
 198     ensure_allocate_imagebuffer( );
 199     fd = fopen(fn,"rb");
 200     if( fd != NULL )
 201     {
 202         int ret = fread(edgebuf->ptr,edgebuf->ptrLen,1,fd);
 203         int ret2 = fread (&zoom,sizeof(zoom),1,fd);
 204         fclose(fd);
 205         if( (ret == 1) && (ret2 == 1) )
 206         {
 207             fsm_state = EDGE_FROZEN;    // switch to "edge overlay frozen"-mode
 208             if (conf.edge_overlay_zoom)
 209             {
 210                 shooting_set_zoom(zoom);
 211             }
 212         }
 213     }
 214 }
 215 
 216 static void average_filter_row(const unsigned char* ptrh1,  // previous row
 217                                unsigned char* smptr,        // write results here
 218                                int x, int x_max)
 219 {
 220     const unsigned char* ptrh2 = ptrh1 + viewport_byte_width*viewport_yscale;  // current row
 221     const unsigned char* ptrh3 = ptrh2 + viewport_byte_width*viewport_yscale;  // next row
 222 #ifndef THUMB_FW
 223     for (; x<x_max; x+=6)
 224     {
 225         *(smptr + x + 1) = (*(ptrh1 + x - 1) +
 226                             *(ptrh1 + x + 1) +
 227                             *(ptrh1 + x + 3) +
 228 
 229                             *(ptrh2 + x - 1) +
 230                             *(ptrh2 + x + 1) +
 231                             *(ptrh2 + x + 3) +
 232 
 233                             *(ptrh3 + x - 1) +
 234                             *(ptrh3 + x + 1) +
 235                             *(ptrh3 + x + 3)) / 9u;
 236 
 237         *(smptr + x + 3) = (*(ptrh1 + x + 1) +
 238                             *(ptrh1 + x + 3) +
 239                             *(ptrh1 + x + 4) +
 240 
 241                             *(ptrh2 + x + 1) +
 242                             *(ptrh2 + x + 3) +
 243                             *(ptrh2 + x + 4) +
 244 
 245                             *(ptrh3 + x + 1) +
 246                             *(ptrh3 + x + 3) +
 247                             *(ptrh3 + x + 4)) / 9u;
 248 
 249         *(smptr + x + 4) = (*(ptrh1 + x + 3) +
 250                             *(ptrh1 + x + 4) +
 251                             *(ptrh1 + x + 5) +
 252 
 253                             *(ptrh2 + x + 3) +
 254                             *(ptrh2 + x + 4) +
 255                             *(ptrh2 + x + 5) +
 256 
 257                             *(ptrh3 + x + 3) +
 258                             *(ptrh3 + x + 4) +
 259                             *(ptrh3 + x + 5)) / 9u;
 260 
 261         *(smptr + x + 5) = (*(ptrh1 + x + 4) +
 262                             *(ptrh1 + x + 5) +
 263                             *(ptrh1 + x + 7) +
 264 
 265                             *(ptrh2 + x + 4) +
 266                             *(ptrh2 + x + 5) +
 267                             *(ptrh2 + x + 7) +
 268 
 269                             *(ptrh3 + x + 4) +
 270                             *(ptrh3 + x + 5) +
 271                             *(ptrh3 + x + 7)) / 9u;
 272     }
 273 
 274     // copy 2nd last column to last column to prevent vertical stripe artifact.
 275     smptr[x+1] = smptr[x-5];
 276     smptr[x+3] = smptr[x-3];
 277     smptr[x+4] = smptr[x-2];
 278     smptr[x+5] = smptr[x-1];
 279 }
 280 #else
 281         for (; x<x_max; x+=8)
 282     {
 283         *(smptr + x + 1) = (*(ptrh1 + x - 1) +
 284                             *(ptrh1 + x + 1) +
 285                             *(ptrh1 + x + 3) +
 286 
 287                             *(ptrh2 + x - 1) +
 288                             *(ptrh2 + x + 1) +
 289                             *(ptrh2 + x + 3) +
 290 
 291                             *(ptrh3 + x - 1) +
 292                             *(ptrh3 + x + 1) +
 293                             *(ptrh3 + x + 3)) / 9u;
 294 
 295         *(smptr + x + 3) = (*(ptrh1 + x + 1) +
 296                             *(ptrh1 + x + 3) +
 297                             *(ptrh1 + x + 5) +
 298 
 299                             *(ptrh2 + x + 1) +
 300                             *(ptrh2 + x + 3) +
 301                             *(ptrh2 + x + 5) +
 302 
 303                             *(ptrh3 + x + 1) +
 304                             *(ptrh3 + x + 3) +
 305                             *(ptrh3 + x + 5)) / 9u;
 306 
 307         *(smptr + x + 5) = (*(ptrh1 + x + 3) +
 308                             *(ptrh1 + x + 5) +
 309                             *(ptrh1 + x + 7) +
 310 
 311                             *(ptrh2 + x + 3) +
 312                             *(ptrh2 + x + 5) +
 313                             *(ptrh2 + x + 7) +
 314 
 315                             *(ptrh3 + x + 3) +
 316                             *(ptrh3 + x + 5) +
 317                             *(ptrh3 + x + 7)) / 9u;
 318 
 319         *(smptr + x + 7) = (*(ptrh1 + x + 5) +
 320                             *(ptrh1 + x + 7) +
 321                             *(ptrh1 + x + 9) +
 322 
 323                             *(ptrh2 + x + 5) +
 324                             *(ptrh2 + x + 7) +
 325                             *(ptrh2 + x + 9) +
 326 
 327                             *(ptrh3 + x + 5) +
 328                             *(ptrh3 + x + 7) +
 329                             *(ptrh3 + x + 9)) / 9u;
 330     }
 331 
 332     // copy 2nd last column to last column to prevent vertical stripe artifact.
 333     smptr[x+1] = smptr[x-7];
 334     smptr[x+3] = smptr[x-5];
 335     smptr[x+5] = smptr[x-3];
 336     smptr[x+7] = smptr[x-1];
 337 }
 338 #endif
 339 
 340 // Sobel edge detector
 341 static int calc_edge_overlay()
 342 {
 343     int shutter_fullpress = kbd_is_key_pressed(KEY_SHOOT_FULL);
 344 
 345     const unsigned char* img = vid_get_viewport_active_buffer();
 346     if (!img) return shutter_fullpress;
 347 
 348     const unsigned char*  ptrh1 = NULL;    // previous pixel line
 349     const unsigned char*  ptrh2 = NULL;    // current pixel line
 350     const unsigned char*  ptrh3 = NULL;    // next pixel line
 351     unsigned char*  smptr = NULL;    // pointer to line in smbuf
 352     int x, y, xdiv3;
 353     int conv1, conv2;
 354 
 355     const int y_min = camera_screen.edge_hmargin+ slice   *slice_height;
 356     const int y_max = camera_screen.edge_hmargin+(slice+1)*slice_height;
 357 #ifndef THUMB_FW
 358     const int x_min = 6;
 359     const int x_max = (viewport_width - 2) * 3;
 360 #else
 361     const int x_min = 8;
 362     const int x_max = (viewport_width - 4) * 2;
 363 #endif
 364     img += vid_get_viewport_image_offset();             // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
 365 
 366     xoffset = 0;
 367     yoffset = 0;
 368 
 369     // Reserve buffers
 370     ensure_allocate_imagebuffer();
 371     if( !is_buffer_ready() ) return 0;
 372 
 373     // In every 6 bytes the Y of four pixels are described in the
 374     // viewport (UYVYYY format). For edge detection we only
 375     // consider the second in the current and the first
 376     // in the next pixel.
 377 
 378     // Clear all edges in the current slice
 379     int compressed_slice = edgebuf->ptrLen / EDGE_SLICES;
 380     memset(edgebuf->ptr + slice*compressed_slice, 0, compressed_slice);
 381 
 382     if (conf.edge_overlay_filter)
 383     {
 384         // Prefill smbuf with three lines of avergae-filtered data.
 385         // This looks much more complex then it actually is.
 386         // We really are just summing up nine pixels in a 3x3 box
 387         // and averaging the current pixel based on them. And
 388         // we do it 4 bytes at a time because of the UYVYYY format.
 389         for (y = -1; y <= 1; ++y)
 390         {
 391             shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 392 
 393             ptrh1 = img + (y_min+y-1) * viewport_byte_width*viewport_yscale;
 394             smptr = smbuf + (y+1) * viewport_byte_width;
 395 
 396             average_filter_row(ptrh1, smptr, x_min, x_max);
 397         }
 398     }
 399 
 400     for (y = y_min; y < y_max; ++y)
 401     {
 402         shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 403 
 404         if (conf.edge_overlay_filter)
 405         {
 406             // We need to shift up our smbuf one line,
 407             // and fill in the last line (which now empty)
 408             // with average-filtered data from img.
 409             // By storing only three lines of smoothed picture
 410             // in memory, we save memory.
 411 
 412             // Shift
 413             memcpy(smbuf, smbuf+viewport_byte_width, viewport_byte_width*2);
 414 
 415             // Filter new line
 416             ptrh1 = img + y * viewport_byte_width*viewport_yscale;
 417             smptr = smbuf + 2 * viewport_byte_width;
 418             average_filter_row(ptrh1, smptr, x_min, x_max);
 419 
 420             ptrh1 = smbuf;
 421         }
 422         else
 423         {
 424             ptrh1 = img + (y-1) * viewport_byte_width*viewport_yscale;
 425         }
 426         ptrh2 = ptrh1 + viewport_byte_width*viewport_yscale;
 427         ptrh3 = ptrh2 + viewport_byte_width*viewport_yscale;
 428 
 429         // Now we do sobel on the current line
 430 #ifndef THUMB_FW
 431         for (x = x_min, xdiv3 = x_min/3; x < x_max; x += 6, xdiv3 += 2)
 432         {
 433             // convolve vert (second Y)
 434             conv1 = *(ptrh1 + x + 1) * ( 1) +
 435                     *(ptrh1 + x + 4) * (-1) +
 436 
 437                     *(ptrh2 + x + 1) * ( 2) +
 438                     *(ptrh2 + x + 4) * (-2) +
 439 
 440                     *(ptrh3 + x + 1) * ( 1) +
 441                     *(ptrh3 + x + 4) * (-1);
 442             if  (conv1 < 0)     // abs()
 443                 conv1 = -conv1;
 444 
 445             // convolve vert (first Y of next pixel)
 446             conv2 = *(ptrh1 + x + 1) * ( 1) +
 447                     *(ptrh1 + x + 3) * ( 2) +
 448                     *(ptrh1 + x + 4) * ( 1) +
 449 
 450                     *(ptrh3 + x + 1) * (-1) +
 451                     *(ptrh3 + x + 3) * (-2) +
 452                     *(ptrh3 + x + 4) * (-1);
 453             if  (conv2 < 0)     // abs()
 454                 conv2 = -conv2;
 455 
 456             if (conv1 + conv2 > conf.edge_overlay_thresh)
 457             {
 458                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3, 1);
 459             }
 460 
 461             // Do it once again for the next 'pixel'
 462 
 463             // convolve vert (second Y)
 464             conv1 = *(ptrh1 + x + 5) * ( 1) +
 465                     *(ptrh1 + x + 9) * (-1) +
 466 
 467                     *(ptrh2 + x + 5) * ( 2) +
 468                     *(ptrh2 + x + 9) * (-2) +
 469 
 470                     *(ptrh3 + x + 5) * ( 1) +
 471                     *(ptrh3 + x + 9) * (-1);
 472             if  (conv1 < 0)     // abs()
 473                 conv1 = -conv1;
 474 
 475             // convolve vert (first Y of next pixel)
 476             conv2 = *(ptrh1 + x + 5) * ( 1) +
 477                     *(ptrh1 + x + 7) * ( 2) +
 478                     *(ptrh1 + x + 9) * ( 1) +
 479 
 480                     *(ptrh3 + x + 5) * (-1) +
 481                     *(ptrh3 + x + 7) * (-2) +
 482                     *(ptrh3 + x + 9) * (-1);
 483             if  (conv2 < 0)     // abs()
 484                 conv2 = -conv2;
 485 
 486             if (conv1 + conv2 > conf.edge_overlay_thresh)
 487             {
 488                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3+1, 1);
 489             }
 490         }   // for x
 491     }   // for y
 492 
 493 #else
 494         for (x = x_min, xdiv3 = x_min/2; x < x_max; x += 4, xdiv3 += 2)
 495         {                                                                               //  1 231  2 3
 496             // convolve vert (second Y)                 //  1 234  5 678        >>       1 2  3 4  5 6
 497             conv1 = *(ptrh1 + x + 1) * ( 1) +   // UYVYYY UYVYYY        >>      UYVY UYVY UYVY
 498                     *(ptrh1 + x + 5) * (-1) +   // 012345 678901        >>      0123 4567 8901
 499 
 500                     *(ptrh2 + x + 1) * ( 2) +
 501                     *(ptrh2 + x + 5) * (-2) +
 502 
 503                     *(ptrh3 + x + 1) * ( 1) +
 504                     *(ptrh3 + x + 5) * (-1);
 505             if  (conv1 < 0)     // abs()
 506                 conv1 = -conv1;
 507 
 508             // convolve vert (first Y of next pixel)
 509             conv2 = *(ptrh1 + x + 1) * ( 1) +
 510                     *(ptrh1 + x + 3) * ( 2) +
 511                     *(ptrh1 + x + 5) * ( 1) +
 512 
 513                     *(ptrh3 + x + 1) * (-1) +
 514                     *(ptrh3 + x + 3) * (-2) +
 515                     *(ptrh3 + x + 5) * (-1);
 516             if  (conv2 < 0)     // abs()
 517                 conv2 = -conv2;
 518 
 519             if (conv1 + conv2 > conf.edge_overlay_thresh)
 520             {
 521                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3, 1);
 522             }
 523 
 524             // Do it once again for the next 'pixel'
 525 
 526             // convolve vert (second Y)
 527             conv1 = *(ptrh1 + x + 7) * ( 1) +
 528                     *(ptrh1 + x + 11) * (-1) +
 529 
 530                     *(ptrh2 + x + 7) * ( 2) +
 531                     *(ptrh2 + x + 11) * (-2) +
 532 
 533                     *(ptrh3 + x + 7) * ( 1) +
 534                     *(ptrh3 + x + 11) * (-1);
 535             if  (conv1 < 0)     // abs()
 536                 conv1 = -conv1;
 537 
 538             // convolve vert (first Y of next pixel)
 539             conv2 = *(ptrh1 + x + 7) * ( 1) +
 540                     *(ptrh1 + x + 9) * ( 2) +
 541                     *(ptrh1 + x + 11) * ( 1) +
 542 
 543                     *(ptrh3 + x + 7) * (-1) +
 544                     *(ptrh3 + x + 9) * (-2) +
 545                     *(ptrh3 + x + 11) * (-1);
 546             if  (conv2 < 0)     // abs()
 547                 conv2 = -conv2;
 548 
 549             if (conv1 + conv2 > conf.edge_overlay_thresh)
 550             {
 551                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3+1, 1);
 552             }
 553         }   // for x
 554     }   // for y
 555 #endif
 556 
 557 //  For an even more improved edge overlay, enabling the following lines will
 558 //  post-filter the results of the edge detection, removing false edge 'dots'
 559 //  from the display. However, the speed hit is large. In the developer's opinion
 560 //  this code is not needed, but if you want that additional quality and do not
 561 //  care so much about performance, you can enable it.
 562 //
 563 //    if (conf.edge_overlay_filter)
 564 //    {
 565 //        // Here we do basic filtering on the detected edges.
 566 //        // If a pixel is marked as edge but just a few of its
 567 //        // neighbors are also edges, then we assume that the
 568 //        // current pixel is just noise and delete the mark.
 569 //
 570 //        bit_vector_t* bv_tmp = bv_create(edgebuf->nElem, edgebuf->nBits);
 571 //        if (bv_tmp != NULL)
 572 //        {
 573 //            memset(bv_tmp->ptr, 0, bv_tmp->ptrLen);
 574 //
 575 //            for (y = 1; y < viewport_height-1; ++y)
 576 //            {
 577 //                shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 578 //
 579 //                for (x=12; x<(viewport_width - 4); ++x)
 580 //                {
 581 //                    int bEdge = bv_get(edgebuf, y*viewport_width + x);
 582 //                    if (bEdge)
 583 //                    {
 584 //                        // Count the number of neighbor edges
 585 //                        int sum =
 586 //                            bv_get(edgebuf, (y-1)*viewport_width + (x-1)) +
 587 //                            bv_get(edgebuf, (y-1)*viewport_width + (x)) +
 588 //                            bv_get(edgebuf, (y-1)*viewport_width + (x+1)) +
 589 //
 590 //                            bv_get(edgebuf, (y)*viewport_width + (x-1)) +
 591 ////              bv_get(&edgebuf, (y)*viewport_width + (x)) + //  we only inspect the neighbors
 592 //                            bv_get(edgebuf, (y)*viewport_width + (x+1)) +
 593 //
 594 //                            bv_get(edgebuf, (y+1)*viewport_width + (x-1)) +
 595 //                            bv_get(edgebuf, (y+1)*viewport_width + (x)) +
 596 //                            bv_get(edgebuf, (y+1)*viewport_width + (x+1));
 597 //
 598 //                        if (!conf.edge_overlay_show)
 599 //                        {
 600 //                            if (sum >= 5)    // if we have at least 5 neighboring edges
 601 //                                bv_set(bv_tmp, y*viewport_width + x, 1);   // keep the edge
 602 //                            // else
 603 //                            // there is no need to delete because the buffer is already zeroed
 604 //                        }
 605 //                    }
 606 //                }   // for x
 607 //            }   // for y
 608 //
 609 //            // Swap the filtered edge buffer for the real one
 610 //            bit_vector_t* swap_tmp = edgebuf;
 611 //            edgebuf = bv_tmp;
 612 //            bv_free(swap_tmp);
 613 //        }   // NULL-check
 614 //    }   // if filtering
 615 
 616     return shutter_fullpress;
 617 }
 618 
 619 static int draw_edge_overlay()
 620 {
 621     int shutter_fullpress = kbd_is_key_pressed(KEY_SHOOT_FULL);
 622 
 623     int x, y;
 624     int x_off, y_off;
 625 
 626     const color cl = FG_COLOR(user_color(conf.edge_overlay_color));
 627     const int y_slice_min = camera_screen.edge_hmargin+ slice   *slice_height;
 628     const int y_slice_max = camera_screen.edge_hmargin+(slice+1)*slice_height;
 629     const int y_min = camera_screen.edge_hmargin;
 630     const int y_max = camera_screen.edge_hmargin+viewport_height;
 631     const int x_min = 2;
 632     const int x_max = (viewport_width - 2);
 633 
 634     if( !is_buffer_ready() ) return 0;
 635 
 636     for (y = y_slice_min; y < y_slice_max; ++y)
 637     {
 638         y_off = y + yoffset;
 639 
 640         shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 641 
 642         if ((unsigned)(y_off-y_min) < (y_max-y_min)) // is the same as ((y_off > y_min) && (y_off < y_max)) // do not draw outside of allowed area
 643         {
 644             const int y_edgebuf = (y-y_min) * viewport_width;
 645 
 646             for (x = x_min; x < x_max; ++x)
 647             {
 648                 x_off = x + xoffset;
 649 
 650                 if ((unsigned)(x_off-x_min) < (x_max-x_min)) // is the same as  ((x_off > x_min) && (x_off < x_max)) // do not draw outside of allowed area
 651                 {
 652                     // Draw a pixel to the screen wherever we detected an edge.
 653                     // If there is no edge based on the newest data, but there is one painted on the screen
 654                     // from previous calls, delete it from the screen.
 655                     const int bEdge = bv_get(edgebuf, y_edgebuf + x);
 656                     // TODO draw_get_pixel_unrotated not implemented for digic 6
 657                     const int bDraw = bEdge || (draw_get_pixel_unrotated(x_off+viewport_xoffset, y_off+viewport_yoffset) == cl);
 658                     if (bEdge || bDraw)
 659                         draw_pixel_unrotated(x_off+viewport_xoffset, y_off+viewport_yoffset, bEdge ? cl : 0);
 660 
 661                 }
 662             }   // for x
 663         }
 664     }   // for y
 665 
 666 
 667     // Drawing the overlay is over.
 668     // But as a finishing touch we clear up garbage on the screen
 669     // by clearing those parts that the overlay has left.
 670 
 671     if (xoffset != 0)
 672     {
 673         // Cleans up leftover from horizontal motion
 674 
 675         const int x_min_c = (xoffset < 0) ? x_max + xoffset : x_min;
 676         const int x_max_c = (xoffset > 0) ? x_min + xoffset : x_max;
 677 
 678         for (y = y_min; y < y_max; ++y)
 679         {
 680             for (x = x_min_c; x < x_max_c; ++x)
 681             {
 682                 // if there is an edge drawn on the screen but there is no edge there based on the newest data, delete it from the screen
 683                 if (draw_get_pixel_unrotated(x+viewport_xoffset, y+viewport_yoffset) == cl)
 684                     draw_pixel_unrotated(x+viewport_xoffset, y+viewport_yoffset, 0 );
 685             }
 686         }
 687     }
 688 
 689     if (yoffset != 0)
 690     {
 691         // Cleans up leftover from vertical motion
 692 
 693         const int y_min_c = (yoffset < 0) ? y_max + yoffset : y_min;
 694         const int y_max_c = (yoffset > 0) ? y_min + yoffset : y_max;
 695 
 696         for (y = y_min_c; y < y_max_c; ++y)
 697         {
 698             for (x = x_min; x < x_max; ++x)
 699             {
 700                 // if there is an edge drawn on the screen but there is no edge there based on the newest data, delete it from the screen
 701                 if (draw_get_pixel_unrotated(x+viewport_xoffset, y+viewport_yoffset) == cl)
 702                     draw_pixel_unrotated(x+viewport_xoffset, y+viewport_yoffset, 0 );
 703             }
 704         }
 705     }
 706 
 707     return shutter_fullpress;
 708 }
 709 
 710 static void set_offset_from_overlap()
 711 {
 712     const int y_max = viewport_height;
 713     const int x_max = (viewport_width - 2);
 714 
 715     switch(conf.edge_overlay_pano)
 716     {
 717     case 0:     // pano off
 718         xoffset = 0;
 719         yoffset = 0;
 720         break;
 721     case 1:     // pano from left to right
 722         xoffset = -x_max*(100-conf.edge_overlay_pano_overlap)/100;
 723         break;
 724     case 2:     // pano from top to bottom
 725         yoffset = -y_max*(100-conf.edge_overlay_pano_overlap)/100;
 726         break;
 727     case 3:     // pano from right to left
 728         xoffset = x_max*(100-conf.edge_overlay_pano_overlap)/100;
 729         break;
 730     case 4:     // pano from bottom to top
 731         yoffset = y_max*(100-conf.edge_overlay_pano_overlap)/100;
 732         break;
 733     case 5:     // free mode
 734     default:
 735         // free mode: change position with "ALT" and cursor
 736         // nothing to do here.
 737         break;
 738     }
 739 }
 740 
 741 
 742 // Main edge overlay function.
 743 // It works by detecting edges using the Sobel operator
 744 // (calc_edgeoverlay()), the detected edges are then stored into an
 745 // array of 1-bit elements. A set bit indicates that there is an
 746 // edge and that it should be drawn onto the overlay.
 747 // When needed, the 1-bit edge buffer is drawn onto the screen
 748 // (dynamically decompressing it) using draw_edge_overlay().
 749 void edge_overlay()
 750 {
 751     // Was the shutter fully pressed the last time we ran?
 752     // We use this to make sure that the user has released
 753     // the button before processing the next FullPress event.
 754     // This prevents switching FSM states more than once
 755     // per press.
 756     static int bFullPress_prev = 0;
 757 
 758     // Have we already started taking pictures in panorama mode?
 759     // We use this variable to be able to detect if panorama
 760     // mode has been turned off.
 761     static int bPanoInProgress = 0;
 762 
 763     // Precalculate some values to make the rest of the
 764     // code easier to read.
 765     int bFullPress = kbd_is_key_pressed(KEY_SHOOT_FULL);
 766     const int bHalfPress = camera_info.state.is_shutter_half_press;
 767     const int bPlayMode = camera_info.state.mode_play;
 768     const int bPanoramaMode = (conf.edge_overlay_pano != 0);
 769     const int bNeedHalfPress = (conf.edge_overlay_show != 1);
 770     const int bDisplayInPlay = (conf.edge_overlay_play == 1);
 771     const int bCanDisplay = (
 772                                 (!bPlayMode && (bHalfPress || !bNeedHalfPress)) ||   // we have a HalfPress in rec-mode
 773                                 ( bPlayMode && bDisplayInPlay)  // or we are in play-mode with the right settings
 774                             );
 775 
 776     if (bPanoInProgress && !bPanoramaMode)
 777     {
 778         // This means panorama mode has been recently
 779         // turned off in the menu. So let's release
 780         // Frozen mode for the user.
 781         reset_edge_overlay();
 782         bPanoInProgress = 0;
 783     }
 784 
 785     get_viewport_size();
 786 
 787     // For just two states a state machine is not actually needed.
 788     // But it is scalable in the future in case anybody
 789     // wants to extend the functionality of edge overlay.
 790     switch (fsm_state)
 791     {
 792     case EDGE_LIVE:
 793     {
 794         camera_info.state.edge_state_draw=0;
 795         // In this state we assume no edge overlay in memory,
 796         // but we are ready to create one if the user presses wishes so.
 797 
 798         int bRealtimeUpdate = bCanDisplay && (camera_info.state.gui_mode_alt || camera_info.state.gui_mode_none);
 799         if (bRealtimeUpdate)
 800         {
 801             // We try to detect button presses during the lengthy
 802             // calculations.
 803             bFullPress |= calc_edge_overlay();
 804             bFullPress |= draw_edge_overlay();
 805         }
 806 
 807         int bSwitch2Frozen = bFullPress && !bFullPress_prev && camera_info.state.gui_mode_none;
 808         if (bSwitch2Frozen)
 809         {
 810             // Switch to Frozen mode
 811 
 812             // Make sure we have one whole consistent frame
 813             for (slice = 0; slice < EDGE_SLICES; ++slice)
 814                 calc_edge_overlay();
 815 
 816             set_offset_from_overlap();
 817             fsm_state = EDGE_FROZEN;
 818             bPanoInProgress = bPanoramaMode;
 819         }
 820 
 821         if (!bRealtimeUpdate && !bSwitch2Frozen)
 822         {
 823             // Nothing happens. So do nothing.
 824             // Or rather, we could clean up if we are that bored.
 825             reset_edge_overlay();
 826         }
 827         break;
 828     }
 829     case EDGE_FROZEN:
 830     {
 831         camera_info.state.edge_state_draw=1;
 832         // We have a stored edge overlay in memory and we display
 833         // it on screen in 'frozen' mode.
 834 
 835         // Move edge overlay around.
 836         if (camera_info.state.gui_mode_alt)
 837         {
 838             if (kbd_is_key_pressed(KEY_RIGHT))
 839                 xoffset +=XINC;
 840             if (kbd_is_key_pressed(KEY_LEFT))
 841                 xoffset -=XINC;
 842             if (kbd_is_key_pressed(KEY_DOWN))
 843                 yoffset +=YINC;
 844             if (kbd_is_key_pressed(KEY_UP))
 845                 yoffset -=YINC;
 846         }
 847 
 848         if (bCanDisplay && (camera_info.state.gui_mode_alt || camera_info.state.gui_mode_none))
 849         {
 850             // We try to detect button presses during the lengthy
 851             // calculations.
 852             bFullPress |= draw_edge_overlay();
 853             //draw_string(0, 0, "Frozen", user_color(conf.osd_color));
 854         }
 855 
 856         // In event of a FullPress, we either capture a new
 857         // overlay and stay frozen, OR we go back to live mode.
 858         if (bFullPress && !bFullPress_prev && camera_info.state.gui_mode_none)
 859         {
 860             // Possible mode switch
 861             if (bPanoramaMode)
 862             {
 863                 // Make sure we have one whole consistent frame
 864                 for (slice = 0; slice < EDGE_SLICES; ++slice)
 865                     calc_edge_overlay();
 866 
 867                 set_offset_from_overlap();
 868                 bPanoInProgress = 1;
 869             }
 870             else
 871                 fsm_state = EDGE_LIVE;
 872         }
 873 
 874         break;
 875     }   // case
 876     }   // switch
 877 
 878 
 879     bFullPress_prev = bFullPress;
 880 
 881     if (++slice >= EDGE_SLICES)
 882         slice = 0;
 883 
 884 }   // function
 885 
 886 
 887 // =========  MODULE INIT =================
 888 
 889 #include "module_def.h"
 890 
 891 /***************** BEGIN OF AUXILARY PART *********************
 892 ATTENTION: DO NOT REMOVE OR CHANGE SIGNATURES IN THIS SECTION
 893 **************************************************************/
 894 
 895 //---------------------------------------------------------
 896 // PURPOSE:   Perform on-load initialisation
 897 // RETURN VALUE: 1 error, 0 ok
 898 //---------------------------------------------------------
 899 int _module_loader( unsigned int* chdk_export_list )
 900 {
 901     module_restore_edge((void**)&edgebuf, (int*)&fsm_state);
 902     return 0;
 903 }
 904 
 905 
 906 //---------------------------------------------------------
 907 // PURPOSE: Finalize module operations (close allocs, etc)
 908 // RETURN VALUE: 0-ok, 1-fail
 909 //---------------------------------------------------------
 910 int _module_unloader()
 911 {
 912     // Save state info
 913     module_save_edge(edgebuf, fsm_state);
 914 
 915     // Module can be unloaded when menu exits
 916     // Free filter buffer
 917     if (smbuf != NULL)
 918     {
 919         free(smbuf);
 920         smbuf = NULL;
 921     }
 922 
 923     return 0;
 924 }
 925 
 926 int _module_can_unload()
 927 {
 928     return conf.edge_overlay_enable == 0;
 929 }
 930 
 931 /******************** Module Information structure ******************/
 932 
 933 libedgeovr_sym _libedgeovr =
 934 {
 935     {
 936          _module_loader, _module_unloader, _module_can_unload, 0, 0
 937     },
 938 
 939     edge_overlay,
 940     load_edge_overlay,
 941     save_edge_overlay,
 942 };
 943 
 944 ModuleInfo _module_info =
 945 {
 946     MODULEINFO_V1_MAGICNUM,
 947     sizeof(ModuleInfo),
 948     EDGEOVERLAY_VERSION,                // Module version
 949 
 950     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,                       // Requirements of CHDK version
 951     ANY_PLATFORM_ALLOWED,               // Specify platform dependency
 952 
 953     (int32_t)"Edge Overlay (dll)",
 954     MTYPE_EXTENSION,
 955 
 956     &_libedgeovr.base,
 957 
 958     CONF_VERSION,               // CONF version
 959     CAM_SCREEN_VERSION,         // CAM SCREEN version
 960     ANY_VERSION,                // CAM SENSOR version
 961     CAM_INFO_VERSION,           // CAM INFO version
 962 };
 963 
 964 /*************** END OF AUXILARY PART *******************/

/* [<][>][^][v][top][bottom][index][help] */