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 "gui.h"
   8 #include "gui_draw.h"
   9 #include "gui_lang.h"
  10 #include "bitvector.h"
  11 #include "time.h"
  12 #include "dirent.h"
  13 #include "ctype.h"
  14 
  15 #include "edgeoverlay.h"
  16 #include "module_def.h"
  17 
  18 //-------------------------------------------------------------------
  19 
  20 // the way we save edge overlays on their own...
  21 #define EDGE_FILE_PREFIX "EDG_"
  22 #define EDGE_FILE_FORMAT EDGE_FILE_PREFIX "%04d.edg"
  23 #define EDGE_SLICES     2
  24 
  25 // steps for up/down/left/right moving the overlay in ALT mode
  26 #define XINC 6
  27 #define YINC 2
  28 
  29 typedef enum _edge_fsm_state
  30 {
  31     EDGE_LIVE = 0,
  32     EDGE_FROZEN
  33 } edge_fsm_state_t;
  34 
  35 static edge_fsm_state_t fsm_state = EDGE_LIVE;
  36 static bit_vector_t* edgebuf = NULL;
  37 static int xoffset = 0, yoffset = 0;
  38 static unsigned char* smbuf = NULL;
  39 
  40 static int slice = 0;           // the current slice of the frame we are calculating/drawing
  41 static int slice_height;        // the height of a single slice
  42 
  43 static int viewport_byte_width; // width in bytes of one viewport line ??
  44 static int viewport_yscale;     // Y multiplier (for cameras with 480 pixel high viewports)
  45 static int viewport_height;     // height of visible / used area of viewport
  46 static int viewport_width;      // width of visible / used area of viewport (in 3 byte units)
  47 static int viewport_xoffset;    // used when image size != viewport size (e.g. wide screen image on 4:3 LCD)
  48 static int viewport_yoffset;    // used when image size != viewport size (e.g. wide screen image on 4:3 LCD)
  49 
  50 static void get_viewport_size()
  51 {
  52     viewport_height = vid_get_viewport_height()-camera_screen.edge_hmargin*2; //don't trace bottom lines
  53     viewport_width = vid_get_viewport_width();
  54     viewport_byte_width = vid_get_viewport_byte_width();
  55     viewport_yscale = vid_get_viewport_yscale();
  56 
  57         viewport_xoffset = vid_get_viewport_display_xoffset();
  58         viewport_yoffset = vid_get_viewport_display_yoffset();
  59 
  60     slice_height = viewport_height / EDGE_SLICES;
  61 }
  62 
  63 static void ensure_allocate_imagebuffer()
  64 {
  65     if (edgebuf == NULL)
  66     {
  67         edgebuf = bv_create(viewport_height * viewport_width, 1);
  68         if (edgebuf != NULL)
  69             memset(edgebuf->ptr, 0, edgebuf->ptrLen);
  70     }
  71     if (conf.edge_overlay_filter && (smbuf == NULL))
  72     {
  73         smbuf = (unsigned char*)malloc(viewport_byte_width*3);
  74         if (smbuf != NULL)
  75             memset(smbuf, 0, viewport_byte_width*3);
  76         else
  77         {
  78             // Disable filtering if we do not have enough memory for it
  79             conf.edge_overlay_filter = 0;
  80         }
  81     }
  82 }
  83 
  84 static void reset_edge_overlay()
  85 {
  86     if (smbuf != NULL)
  87     {
  88         free(smbuf);
  89         smbuf = NULL;
  90     }
  91 
  92     if (edgebuf != NULL)
  93     {
  94         gui_set_need_restore();     // Refresh display to restore Canon OSD
  95         bv_free(edgebuf);
  96         edgebuf = NULL;
  97     }
  98 
  99     fsm_state = EDGE_LIVE;
 100     slice = 0;
 101 
 102     // Clean up state saved in core CHDK
 103     module_save_edge(edgebuf, fsm_state);
 104 }
 105 
 106 static int is_buffer_ready()
 107 {
 108     if (edgebuf == NULL) return 0;
 109     if (edgebuf->ptr == NULL) return 0; // this should never happen, but it does not hurt to check
 110     return 1;
 111 }
 112 
 113 // scans a filename for the number of the edge detection file it contains
 114 static int get_edge_file_num(const char* fn)
 115 {
 116     int num = 0;
 117     if( strncmp(fn,EDGE_FILE_PREFIX,sizeof(EDGE_FILE_PREFIX)-1) == 0 )
 118     {
 119         // has the correct beginning at least, now try to read as a number...
 120         fn += sizeof(EDGE_FILE_PREFIX);
 121         while( *fn == '0' ) // skip leading 0s
 122         {
 123             ++fn;
 124         }
 125         while( isdigit(*fn) )
 126         {
 127             num *= 10;
 128             num += *fn - '0';
 129             ++fn;
 130         }
 131         // ignore anything else after it, that is like the ending etc.
 132     }
 133     return num;
 134 }
 135 
 136 // saves the actual active overlay data to a file.
 137 void save_edge_overlay(void)
 138 {
 139 
 140     char fn[64];
 141     char msg[64];
 142     FILE *fd;
 143     DIR* d;
 144     int fnum = 0;
 145     int fr = 0;
 146     int zoom = 0;
 147     struct dirent* de;
 148     static struct utimbuf t;
 149     // nothing to save? then dont save
 150 
 151     if( !is_buffer_ready() )
 152     {
 153         draw_string(0, 0, "No overlay to save.", user_color(conf.osd_color));
 154         return;
 155     }
 156 
 157     zoom = shooting_get_zoom();
 158 
 159     // first figure out the most appropriate filename to use
 160     d = opendir(EDGE_SAVE_DIR);
 161     if( ! d )
 162     {
 163         return;
 164     }
 165 
 166     while( (de = readdir(d)) )
 167     {
 168         fr = get_edge_file_num(de->d_name);
 169         if( fr > fnum )
 170         {
 171             fnum = fr;
 172         }
 173     }
 174     ++fnum; // the highest is set, we use the next one
 175     get_viewport_size();
 176     // open the right file
 177     sprintf(fn, EDGE_SAVE_DIR "/" EDGE_FILE_FORMAT, fnum );
 178     fd = fopen(fn, "wb");
 179     if(fd !=NULL)
 180     {
 181         // write the data
 182         fwrite(edgebuf->ptr,edgebuf->ptrLen,1,fd);
 183         fwrite(&zoom,sizeof(zoom),1,fd);
 184         fclose(fd);
 185         t.actime = t.modtime = time(NULL);
 186         utime(fn, &t);
 187         sprintf(msg, "Saved as %s",fn);
 188         draw_string(0, 0, msg, user_color(conf.osd_color));
 189     }
 190     closedir(d);
 191 }
 192 
 193 // load the edge overlay from a file
 194 void load_edge_overlay(const char* fn)
 195 {
 196     FILE *fd;
 197     int zoom;
 198 
 199     get_viewport_size();
 200     ensure_allocate_imagebuffer( );
 201     fd = fopen(fn,"rb");
 202     if( fd != NULL )
 203     {
 204         int ret = fread(edgebuf->ptr,edgebuf->ptrLen,1,fd);
 205         int ret2 = fread (&zoom,sizeof(zoom),1,fd);
 206         fclose(fd);
 207         if( (ret == 1) && (ret2 == 1) )
 208         {
 209             fsm_state = EDGE_FROZEN;    // switch to "edge overlay frozen"-mode
 210             if (conf.edge_overlay_zoom)
 211             {
 212                 shooting_set_zoom(zoom);
 213             }
 214         }
 215     }
 216 }
 217 
 218 static void average_filter_row(const unsigned char* ptrh1,  // previous row
 219                                unsigned char* smptr,        // write results here
 220                                int x, int x_max)
 221 {
 222     const unsigned char* ptrh2 = ptrh1 + viewport_byte_width*viewport_yscale;  // current row
 223     const unsigned char* ptrh3 = ptrh2 + viewport_byte_width*viewport_yscale;  // next row
 224 #ifndef THUMB_FW
 225     for (; x<x_max; x+=6)
 226     {
 227         *(smptr + x + 1) = (*(ptrh1 + x - 1) +
 228                             *(ptrh1 + x + 1) +
 229                             *(ptrh1 + x + 3) +
 230 
 231                             *(ptrh2 + x - 1) +
 232                             *(ptrh2 + x + 1) +
 233                             *(ptrh2 + x + 3) +
 234 
 235                             *(ptrh3 + x - 1) +
 236                             *(ptrh3 + x + 1) +
 237                             *(ptrh3 + x + 3)) / 9u;
 238 
 239         *(smptr + x + 3) = (*(ptrh1 + x + 1) +
 240                             *(ptrh1 + x + 3) +
 241                             *(ptrh1 + x + 4) +
 242 
 243                             *(ptrh2 + x + 1) +
 244                             *(ptrh2 + x + 3) +
 245                             *(ptrh2 + x + 4) +
 246 
 247                             *(ptrh3 + x + 1) +
 248                             *(ptrh3 + x + 3) +
 249                             *(ptrh3 + x + 4)) / 9u;
 250 
 251         *(smptr + x + 4) = (*(ptrh1 + x + 3) +
 252                             *(ptrh1 + x + 4) +
 253                             *(ptrh1 + x + 5) +
 254 
 255                             *(ptrh2 + x + 3) +
 256                             *(ptrh2 + x + 4) +
 257                             *(ptrh2 + x + 5) +
 258 
 259                             *(ptrh3 + x + 3) +
 260                             *(ptrh3 + x + 4) +
 261                             *(ptrh3 + x + 5)) / 9u;
 262 
 263         *(smptr + x + 5) = (*(ptrh1 + x + 4) +
 264                             *(ptrh1 + x + 5) +
 265                             *(ptrh1 + x + 7) +
 266 
 267                             *(ptrh2 + x + 4) +
 268                             *(ptrh2 + x + 5) +
 269                             *(ptrh2 + x + 7) +
 270 
 271                             *(ptrh3 + x + 4) +
 272                             *(ptrh3 + x + 5) +
 273                             *(ptrh3 + x + 7)) / 9u;
 274     }
 275 
 276     // copy 2nd last column to last column to prevent vertical stripe artifact.
 277     smptr[x+1] = smptr[x-5];
 278     smptr[x+3] = smptr[x-3];
 279     smptr[x+4] = smptr[x-2];
 280     smptr[x+5] = smptr[x-1];
 281 }
 282 #else
 283         for (; x<x_max; x+=8)
 284     {
 285         *(smptr + x + 1) = (*(ptrh1 + x - 1) +
 286                             *(ptrh1 + x + 1) +
 287                             *(ptrh1 + x + 3) +
 288 
 289                             *(ptrh2 + x - 1) +
 290                             *(ptrh2 + x + 1) +
 291                             *(ptrh2 + x + 3) +
 292 
 293                             *(ptrh3 + x - 1) +
 294                             *(ptrh3 + x + 1) +
 295                             *(ptrh3 + x + 3)) / 9u;
 296 
 297         *(smptr + x + 3) = (*(ptrh1 + x + 1) +
 298                             *(ptrh1 + x + 3) +
 299                             *(ptrh1 + x + 5) +
 300 
 301                             *(ptrh2 + x + 1) +
 302                             *(ptrh2 + x + 3) +
 303                             *(ptrh2 + x + 5) +
 304 
 305                             *(ptrh3 + x + 1) +
 306                             *(ptrh3 + x + 3) +
 307                             *(ptrh3 + x + 5)) / 9u;
 308 
 309         *(smptr + x + 5) = (*(ptrh1 + x + 3) +
 310                             *(ptrh1 + x + 5) +
 311                             *(ptrh1 + x + 7) +
 312 
 313                             *(ptrh2 + x + 3) +
 314                             *(ptrh2 + x + 5) +
 315                             *(ptrh2 + x + 7) +
 316 
 317                             *(ptrh3 + x + 3) +
 318                             *(ptrh3 + x + 5) +
 319                             *(ptrh3 + x + 7)) / 9u;
 320 
 321         *(smptr + x + 7) = (*(ptrh1 + x + 5) +
 322                             *(ptrh1 + x + 7) +
 323                             *(ptrh1 + x + 9) +
 324 
 325                             *(ptrh2 + x + 5) +
 326                             *(ptrh2 + x + 7) +
 327                             *(ptrh2 + x + 9) +
 328 
 329                             *(ptrh3 + x + 5) +
 330                             *(ptrh3 + x + 7) +
 331                             *(ptrh3 + x + 9)) / 9u;
 332     }
 333 
 334     // copy 2nd last column to last column to prevent vertical stripe artifact.
 335     smptr[x+1] = smptr[x-7];
 336     smptr[x+3] = smptr[x-5];
 337     smptr[x+5] = smptr[x-3];
 338     smptr[x+7] = smptr[x-1];
 339 }
 340 #endif
 341 
 342 // Sobel edge detector
 343 static int calc_edge_overlay()
 344 {
 345     int shutter_fullpress = kbd_is_key_pressed(KEY_SHOOT_FULL);
 346 
 347     const unsigned char* img = vid_get_viewport_active_buffer();
 348     if (!img) return shutter_fullpress;
 349 
 350     const unsigned char*  ptrh1 = NULL;    // previous pixel line
 351     const unsigned char*  ptrh2 = NULL;    // current pixel line
 352     const unsigned char*  ptrh3 = NULL;    // next pixel line
 353     unsigned char*  smptr = NULL;    // pointer to line in smbuf
 354     int x, y, xdiv3;
 355     int conv1, conv2;
 356 
 357     const int y_min = camera_screen.edge_hmargin+ slice   *slice_height;
 358     const int y_max = camera_screen.edge_hmargin+(slice+1)*slice_height;
 359 #ifndef THUMB_FW
 360     const int x_min = 6;
 361     const int x_max = (viewport_width - 2) * 3;
 362 #else
 363     const int x_min = 8;
 364     const int x_max = (viewport_width - 4) * 2;
 365 #endif
 366     img += vid_get_viewport_image_offset();             // offset into viewport for when image size != viewport size (e.g. 16:9 image on 4:3 LCD)
 367 
 368     xoffset = 0;
 369     yoffset = 0;
 370 
 371     // Reserve buffers
 372     ensure_allocate_imagebuffer();
 373     if( !is_buffer_ready() ) return 0;
 374 
 375     // In every 6 bytes the Y of four pixels are described in the
 376     // viewport (UYVYYY format). For edge detection we only
 377     // consider the second in the current and the first
 378     // in the next pixel.
 379 
 380     // Clear all edges in the current slice
 381     int compressed_slice = edgebuf->ptrLen / EDGE_SLICES;
 382     memset(edgebuf->ptr + slice*compressed_slice, 0, compressed_slice);
 383 
 384     if (conf.edge_overlay_filter)
 385     {
 386         // Prefill smbuf with three lines of avergae-filtered data.
 387         // This looks much more complex then it actually is.
 388         // We really are just summing up nine pixels in a 3x3 box
 389         // and averaging the current pixel based on them. And
 390         // we do it 4 bytes at a time because of the UYVYYY format.
 391         for (y = -1; y <= 1; ++y)
 392         {
 393             shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 394 
 395             ptrh1 = img + (y_min+y-1) * viewport_byte_width*viewport_yscale;
 396             smptr = smbuf + (y+1) * viewport_byte_width;
 397 
 398             average_filter_row(ptrh1, smptr, x_min, x_max);
 399         }
 400     }
 401 
 402     for (y = y_min; y < y_max; ++y)
 403     {
 404         shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 405 
 406         if (conf.edge_overlay_filter)
 407         {
 408             // We need to shift up our smbuf one line,
 409             // and fill in the last line (which now empty)
 410             // with average-filtered data from img.
 411             // By storing only three lines of smoothed picture
 412             // in memory, we save memory.
 413 
 414             // Shift
 415             memcpy(smbuf, smbuf+viewport_byte_width, viewport_byte_width*2);
 416 
 417             // Filter new line
 418             ptrh1 = img + y * viewport_byte_width*viewport_yscale;
 419             smptr = smbuf + 2 * viewport_byte_width;
 420             average_filter_row(ptrh1, smptr, x_min, x_max);
 421 
 422             ptrh1 = smbuf;
 423         }
 424         else
 425         {
 426             ptrh1 = img + (y-1) * viewport_byte_width*viewport_yscale;
 427         }
 428         ptrh2 = ptrh1 + viewport_byte_width*viewport_yscale;
 429         ptrh3 = ptrh2 + viewport_byte_width*viewport_yscale;
 430 
 431         // Now we do sobel on the current line
 432 #ifndef THUMB_FW
 433         for (x = x_min, xdiv3 = x_min/3; x < x_max; x += 6, xdiv3 += 2)
 434         {
 435             // convolve vert (second Y)
 436             conv1 = *(ptrh1 + x + 1) * ( 1) +
 437                     *(ptrh1 + x + 4) * (-1) +
 438 
 439                     *(ptrh2 + x + 1) * ( 2) +
 440                     *(ptrh2 + x + 4) * (-2) +
 441 
 442                     *(ptrh3 + x + 1) * ( 1) +
 443                     *(ptrh3 + x + 4) * (-1);
 444             if  (conv1 < 0)     // abs()
 445                 conv1 = -conv1;
 446 
 447             // convolve vert (first Y of next pixel)
 448             conv2 = *(ptrh1 + x + 1) * ( 1) +
 449                     *(ptrh1 + x + 3) * ( 2) +
 450                     *(ptrh1 + x + 4) * ( 1) +
 451 
 452                     *(ptrh3 + x + 1) * (-1) +
 453                     *(ptrh3 + x + 3) * (-2) +
 454                     *(ptrh3 + x + 4) * (-1);
 455             if  (conv2 < 0)     // abs()
 456                 conv2 = -conv2;
 457 
 458             if (conv1 + conv2 > conf.edge_overlay_thresh)
 459             {
 460                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3, 1);
 461             }
 462 
 463             // Do it once again for the next 'pixel'
 464 
 465             // convolve vert (second Y)
 466             conv1 = *(ptrh1 + x + 5) * ( 1) +
 467                     *(ptrh1 + x + 9) * (-1) +
 468 
 469                     *(ptrh2 + x + 5) * ( 2) +
 470                     *(ptrh2 + x + 9) * (-2) +
 471 
 472                     *(ptrh3 + x + 5) * ( 1) +
 473                     *(ptrh3 + x + 9) * (-1);
 474             if  (conv1 < 0)     // abs()
 475                 conv1 = -conv1;
 476 
 477             // convolve vert (first Y of next pixel)
 478             conv2 = *(ptrh1 + x + 5) * ( 1) +
 479                     *(ptrh1 + x + 7) * ( 2) +
 480                     *(ptrh1 + x + 9) * ( 1) +
 481 
 482                     *(ptrh3 + x + 5) * (-1) +
 483                     *(ptrh3 + x + 7) * (-2) +
 484                     *(ptrh3 + x + 9) * (-1);
 485             if  (conv2 < 0)     // abs()
 486                 conv2 = -conv2;
 487 
 488             if (conv1 + conv2 > conf.edge_overlay_thresh)
 489             {
 490                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3+1, 1);
 491             }
 492         }   // for x
 493     }   // for y
 494 
 495 #else
 496         for (x = x_min, xdiv3 = x_min/2; x < x_max; x += 4, xdiv3 += 2)
 497         {                                                                               //  1 231  2 3
 498             // convolve vert (second Y)                 //  1 234  5 678        >>       1 2  3 4  5 6
 499             conv1 = *(ptrh1 + x + 1) * ( 1) +   // UYVYYY UYVYYY        >>      UYVY UYVY UYVY
 500                     *(ptrh1 + x + 5) * (-1) +   // 012345 678901        >>      0123 4567 8901
 501 
 502                     *(ptrh2 + x + 1) * ( 2) +
 503                     *(ptrh2 + x + 5) * (-2) +
 504 
 505                     *(ptrh3 + x + 1) * ( 1) +
 506                     *(ptrh3 + x + 5) * (-1);
 507             if  (conv1 < 0)     // abs()
 508                 conv1 = -conv1;
 509 
 510             // convolve vert (first Y of next pixel)
 511             conv2 = *(ptrh1 + x + 1) * ( 1) +
 512                     *(ptrh1 + x + 3) * ( 2) +
 513                     *(ptrh1 + x + 5) * ( 1) +
 514 
 515                     *(ptrh3 + x + 1) * (-1) +
 516                     *(ptrh3 + x + 3) * (-2) +
 517                     *(ptrh3 + x + 5) * (-1);
 518             if  (conv2 < 0)     // abs()
 519                 conv2 = -conv2;
 520 
 521             if (conv1 + conv2 > conf.edge_overlay_thresh)
 522             {
 523                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3, 1);
 524             }
 525 
 526             // Do it once again for the next 'pixel'
 527 
 528             // convolve vert (second Y)
 529             conv1 = *(ptrh1 + x + 7) * ( 1) +
 530                     *(ptrh1 + x + 11) * (-1) +
 531 
 532                     *(ptrh2 + x + 7) * ( 2) +
 533                     *(ptrh2 + x + 11) * (-2) +
 534 
 535                     *(ptrh3 + x + 7) * ( 1) +
 536                     *(ptrh3 + x + 11) * (-1);
 537             if  (conv1 < 0)     // abs()
 538                 conv1 = -conv1;
 539 
 540             // convolve vert (first Y of next pixel)
 541             conv2 = *(ptrh1 + x + 7) * ( 1) +
 542                     *(ptrh1 + x + 9) * ( 2) +
 543                     *(ptrh1 + x + 11) * ( 1) +
 544 
 545                     *(ptrh3 + x + 7) * (-1) +
 546                     *(ptrh3 + x + 9) * (-2) +
 547                     *(ptrh3 + x + 11) * (-1);
 548             if  (conv2 < 0)     // abs()
 549                 conv2 = -conv2;
 550 
 551             if (conv1 + conv2 > conf.edge_overlay_thresh)
 552             {
 553                 bv_set(edgebuf, (y-camera_screen.edge_hmargin)*viewport_width + xdiv3+1, 1);
 554             }
 555         }   // for x
 556     }   // for y
 557 #endif
 558 
 559 //  For an even more improved edge overlay, enabling the following lines will
 560 //  post-filter the results of the edge detection, removing false edge 'dots'
 561 //  from the display. However, the speed hit is large. In the developer's opinion
 562 //  this code is not needed, but if you want that additional quality and do not
 563 //  care so much about performance, you can enable it.
 564 //
 565 //    if (conf.edge_overlay_filter)
 566 //    {
 567 //        // Here we do basic filtering on the detected edges.
 568 //        // If a pixel is marked as edge but just a few of its
 569 //        // neighbors are also edges, then we assume that the
 570 //        // current pixel is just noise and delete the mark.
 571 //
 572 //        bit_vector_t* bv_tmp = bv_create(edgebuf->nElem, edgebuf->nBits);
 573 //        if (bv_tmp != NULL)
 574 //        {
 575 //            memset(bv_tmp->ptr, 0, bv_tmp->ptrLen);
 576 //
 577 //            for (y = 1; y < viewport_height-1; ++y)
 578 //            {
 579 //                shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 580 //
 581 //                for (x=12; x<(viewport_width - 4); ++x)
 582 //                {
 583 //                    int bEdge = bv_get(edgebuf, y*viewport_width + x);
 584 //                    if (bEdge)
 585 //                    {
 586 //                        // Count the number of neighbor edges
 587 //                        int sum =
 588 //                            bv_get(edgebuf, (y-1)*viewport_width + (x-1)) +
 589 //                            bv_get(edgebuf, (y-1)*viewport_width + (x)) +
 590 //                            bv_get(edgebuf, (y-1)*viewport_width + (x+1)) +
 591 //
 592 //                            bv_get(edgebuf, (y)*viewport_width + (x-1)) +
 593 ////              bv_get(&edgebuf, (y)*viewport_width + (x)) + //  we only inspect the neighbors
 594 //                            bv_get(edgebuf, (y)*viewport_width + (x+1)) +
 595 //
 596 //                            bv_get(edgebuf, (y+1)*viewport_width + (x-1)) +
 597 //                            bv_get(edgebuf, (y+1)*viewport_width + (x)) +
 598 //                            bv_get(edgebuf, (y+1)*viewport_width + (x+1));
 599 //
 600 //                        if (!conf.edge_overlay_show)
 601 //                        {
 602 //                            if (sum >= 5)    // if we have at least 5 neighboring edges
 603 //                                bv_set(bv_tmp, y*viewport_width + x, 1);   // keep the edge
 604 //                            // else
 605 //                            // there is no need to delete because the buffer is already zeroed
 606 //                        }
 607 //                    }
 608 //                }   // for x
 609 //            }   // for y
 610 //
 611 //            // Swap the filtered edge buffer for the real one
 612 //            bit_vector_t* swap_tmp = edgebuf;
 613 //            edgebuf = bv_tmp;
 614 //            bv_free(swap_tmp);
 615 //        }   // NULL-check
 616 //    }   // if filtering
 617 
 618     return shutter_fullpress;
 619 }
 620 
 621 static int draw_edge_overlay()
 622 {
 623     int shutter_fullpress = kbd_is_key_pressed(KEY_SHOOT_FULL);
 624 
 625     int x, y;
 626     int x_off, y_off;
 627 
 628     const color cl = FG_COLOR(user_color(conf.edge_overlay_color));
 629     const int y_slice_min = camera_screen.edge_hmargin+ slice   *slice_height;
 630     const int y_slice_max = camera_screen.edge_hmargin+(slice+1)*slice_height;
 631     const int y_min = camera_screen.edge_hmargin;
 632     const int y_max = camera_screen.edge_hmargin+viewport_height;
 633     const int x_min = 2;
 634     const int x_max = (viewport_width - 2);
 635 
 636     if( !is_buffer_ready() ) return 0;
 637 
 638     for (y = y_slice_min; y < y_slice_max; ++y)
 639     {
 640         y_off = y + yoffset;
 641 
 642         shutter_fullpress |= kbd_is_key_pressed(KEY_SHOOT_FULL);
 643 
 644         if ((y_off > y_min) && (y_off < y_max)) // do not draw outside of allowed area
 645         {
 646             const int y_edgebuf = (y-y_min) * viewport_width;
 647 
 648             for (x = x_min; x < x_max; ++x)
 649             {
 650                 x_off = x + xoffset;
 651 
 652                 if ((x_off > x_min) && (x_off < x_max)) // do not draw outside of allowed area
 653                 {
 654                     // Draw a pixel to the screen wherever we detected an edge.
 655                     // If there is no edge based on the newest data, but there is one painted on the screen
 656                     // from previous calls, delete it from the screen.
 657                     draw_or_erase_edge_pixel(x_off+viewport_xoffset, y_off+viewport_yoffset, cl, bv_get(edgebuf, y_edgebuf + x));
 658                 }
 659             }   // for x
 660         }
 661     }   // for y
 662 
 663 
 664     // Drawing the overlay is over.
 665     // But as a finishing touch we clear up garbage on the screen
 666     // by clearing those parts that the overlay has left.
 667 
 668     if (xoffset != 0)
 669     {
 670         // Cleans up leftover from horizontal motion
 671 
 672         const int x_min_c = (xoffset < 0) ? x_max + xoffset : x_min;
 673         const int x_max_c = (xoffset > 0) ? x_min + xoffset : x_max;
 674 
 675         for (y = y_min; y < y_max; ++y)
 676         {
 677             for (x = x_min_c; x < x_max_c; ++x)
 678             {
 679                 // 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
 680                 draw_or_erase_edge_pixel(x+viewport_xoffset, y+viewport_yoffset, cl, 0);
 681             }
 682         }
 683     }
 684 
 685     if (yoffset != 0)
 686     {
 687         // Cleans up leftover from vertical motion
 688 
 689         const int y_min_c = (yoffset < 0) ? y_max + yoffset : y_min;
 690         const int y_max_c = (yoffset > 0) ? y_min + yoffset : y_max;
 691 
 692         for (y = y_min_c; y < y_max_c; ++y)
 693         {
 694             for (x = x_min; x < x_max; ++x)
 695             {
 696                 // 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
 697                 draw_or_erase_edge_pixel(x+viewport_xoffset, y+viewport_yoffset, cl, 0);
 698             }
 699         }
 700     }
 701 
 702     return shutter_fullpress;
 703 }
 704 
 705 static void set_offset_from_overlap()
 706 {
 707     const int y_max = viewport_height;
 708     const int x_max = (viewport_width - 2);
 709 
 710     switch(conf.edge_overlay_pano)
 711     {
 712     case 0:     // pano off
 713         xoffset = 0;
 714         yoffset = 0;
 715         break;
 716     case 1:     // pano from left to right
 717         xoffset = -x_max*(100-conf.edge_overlay_pano_overlap)/100;
 718         break;
 719     case 2:     // pano from top to bottom
 720         yoffset = -y_max*(100-conf.edge_overlay_pano_overlap)/100;
 721         break;
 722     case 3:     // pano from right to left
 723         xoffset = x_max*(100-conf.edge_overlay_pano_overlap)/100;
 724         break;
 725     case 4:     // pano from bottom to top
 726         yoffset = y_max*(100-conf.edge_overlay_pano_overlap)/100;
 727         break;
 728     case 5:     // free mode
 729     default:
 730         // free mode: change position with "ALT" and cursor
 731         // nothing to do here.
 732         break;
 733     }
 734 }
 735 
 736 
 737 // Main edge overlay function.
 738 // It works by detecting edges using the Sobel operator
 739 // (calc_edgeoverlay()), the detected edges are then stored into an
 740 // array of 1-bit elements. A set bit indicates that there is an
 741 // edge and that it should be drawn onto the overlay.
 742 // When needed, the 1-bit edge buffer is drawn onto the screen
 743 // (dynamically decompressing it) using draw_edge_overlay().
 744 void edge_overlay()
 745 {
 746     // Check that viewport dimensions do not exceed bitmap dimensions.
 747     // HDMI output may use a larger frame for the image compared to the bitmap we draw on - the code can't handle this.
 748     if ((vid_get_viewport_width() > camera_screen.width) || (vid_get_viewport_height() > camera_screen.height))
 749         return;
 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( __attribute__ ((unused))unsigned int* chdk_export_list )
 900 {
 901     fsm_state = module_restore_edge((void**)&edgebuf);
 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     0,
 964 };
 965 
 966 /*************** END OF AUXILARY PART *******************/

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