00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef ENVISION_ENV_CHANNEL_C_DEFINED
00039 #define ENVISION_ENV_CHANNEL_C_DEFINED
00040
00041 #include "Envision/env_channel.h"
00042
00043 #include "Envision/env_c_math_ops.h"
00044 #include "Envision/env_image_ops.h"
00045 #include "Envision/env_log.h"
00046 #include "Envision/env_params.h"
00047
00048 #ifndef ENV_NO_DEBUG
00049
00050
00051
00052
00053 static int is_dyadic(const struct env_pyr* pyr,
00054 const env_size_t first, const env_size_t last)
00055 {
00056 if (first == last) return 0;
00057
00058 for (env_size_t i = first + 1; i < last; ++i)
00059 {
00060 const struct env_dims prevdims = env_pyr_img(pyr, i-1)->dims;
00061 const struct env_dims curdims = env_pyr_img(pyr, i)->dims;
00062
00063
00064 const env_size_t pw2 = ENV_MAX(prevdims.w/2,((env_size_t) 1));
00065 const env_size_t ph2 = ENV_MAX(prevdims.h/2,((env_size_t) 1));
00066
00067 if (curdims.w != pw2) return 0;
00068 if (curdims.h != ph2) return 0;
00069 }
00070
00071 return 1;
00072 }
00073
00074 #endif
00075
00076 #ifdef ENV_WITH_DYNAMIC_CHANNELS
00077
00078
00079 static void abs_diff_thresh(const struct env_image* b,
00080 const struct env_image* c,
00081 const intg32 thresh,
00082 struct env_image* result)
00083 {
00084 ENV_ASSERT(env_dims_equal(b->dims, c->dims));
00085 ENV_ASSERT(env_dims_equal(b->dims, result->dims));
00086
00087 const intg32* const bptr = env_img_pixels(b);
00088 const intg32* const cptr = env_img_pixels(c);
00089 intg32* const dptr = env_img_pixelsw(result);
00090
00091 const env_size_t sz = env_img_size(b);
00092
00093 for (env_size_t i = 0; i < sz; ++i)
00094 {
00095 dptr[i] =
00096 (bptr[i] < cptr[i])
00097 ? cptr[i] - bptr[i]
00098 : bptr[i] - cptr[i];
00099
00100 if (dptr[i] < thresh) dptr[i] = 0;
00101 }
00102 }
00103
00104
00105 static void abs_diff_thresh_pyr(const struct env_pyr* b,
00106 const struct env_pyr* c,
00107 const intg32 thresh,
00108 struct env_pyr* result)
00109 {
00110 ENV_ASSERT(env_pyr_depth(b) == env_pyr_depth(c));
00111 ENV_ASSERT(env_pyr_depth(c) == env_pyr_depth(result));
00112
00113 const env_size_t n = env_pyr_depth(b);
00114
00115 if (env_pyr_depth(result) != n)
00116 {
00117 env_pyr_make_empty(result);
00118 env_pyr_init(result, n);
00119 }
00120
00121 for (env_size_t i = 0; i < n; ++i)
00122 {
00123 const struct env_image* bimg = env_pyr_img(b, i);
00124
00125 if (!env_img_initialized(bimg))
00126 continue;
00127
00128
00129
00130 const struct env_image* cimg = env_pyr_img(c, i);
00131 struct env_image* rimg = env_pyr_imgw(result, i);
00132
00133 env_img_resize_dims(rimg, bimg->dims);
00134
00135 abs_diff_thresh(bimg, cimg, thresh, rimg);
00136 }
00137 }
00138
00139 #endif // ENV_WITH_DYNAMIC_CHANNELS
00140
00141
00142 void env_chan_process_pyr(const char* tagName,
00143 const struct env_dims inputDims,
00144 const struct env_pyr* pyr,
00145 const struct env_params* envp,
00146 const struct env_math* imath,
00147 const int takeAbs,
00148 const int normalizeOutput,
00149 struct env_image* result)
00150 {
00151 const struct env_dims mapDims =
00152 { ENV_MAX(inputDims.w / (1 << envp->output_map_level), 1),
00153 ENV_MAX(inputDims.h / (1 << envp->output_map_level), 1) };
00154
00155 if (env_pyr_depth(pyr) == 0)
00156
00157
00158 {
00159 env_img_make_empty(result);
00160 return;
00161 }
00162
00163
00164 ENV_ASSERT(is_dyadic(pyr, envp->cs_lev_min, env_max_pyr_depth(envp)));
00165
00166 env_img_resize_dims(result, mapDims);
00167
00168 {
00169 const env_size_t mapSize = mapDims.w * mapDims.h;
00170 intg32* const rptr = env_img_pixelsw(result);
00171 for (env_size_t i = 0; i < mapSize; ++i)
00172 rptr[i] = 0;
00173 }
00174
00175
00176 for (env_size_t clev = envp->cs_lev_min; clev <= envp->cs_lev_max; ++clev)
00177 for (env_size_t delta = envp->cs_del_min; delta <= envp->cs_del_max; ++delta)
00178 {
00179 const env_size_t slev = clev + delta;
00180
00181
00182 struct env_image submap;
00183 env_img_init(&submap, env_pyr_img(pyr, clev)->dims);
00184 env_center_surround(env_pyr_img(pyr, clev),
00185 env_pyr_img(pyr, slev),
00186 takeAbs, &submap);
00187 #ifdef ENV_WITH_VISIT_CHANNEL
00188 if (envp->submapPreProc != 0)
00189 (*envp->submapPreProc)(tagName, clev, slev, &submap,
00190 env_pyr_img(pyr, clev), env_pyr_img(pyr, slev) );
00191 #endif
00192
00193
00194 if (submap.dims.w > mapDims.w
00195 || submap.dims.h > mapDims.h)
00196 {
00197
00198
00199
00200 const env_size_t n =
00201 envp->output_map_level - clev;
00202
00203 env_downsize_9_inplace(&submap, n, imath);
00204 }
00205 else if (submap.dims.w < mapDims.w
00206 || submap.dims.h < mapDims.h)
00207 {
00208 struct env_image tmp;
00209 env_img_init(&tmp, mapDims);
00210 env_rescale(&submap, &tmp);
00211 env_img_swap(&submap, &tmp);
00212 }
00213
00214
00215
00216 ENV_ASSERT(env_dims_equal(submap.dims, mapDims));
00217
00218
00219
00220
00221 env_max_normalize_inplace
00222 (&submap, INTMAXNORMMIN, INTMAXNORMMAX,
00223 envp->maxnorm_type,
00224 envp->range_thresh);
00225
00226 #ifdef ENV_WITH_VISIT_CHANNEL
00227 if (envp->submapPostNormProc != 0)
00228 (*envp->submapPostNormProc)(tagName, clev, slev, &submap,
00229 env_pyr_img(pyr, clev), env_pyr_img(pyr, slev) );
00230 #endif
00231
00232
00233 env_c_image_div_scalar_accum
00234 (env_img_pixels(&submap),
00235 env_img_size(&submap),
00236 (intg32) env_max_cs_index(envp),
00237 env_img_pixelsw(result));
00238
00239 env_img_make_empty(&submap);
00240 }
00241
00242 #ifdef ENV_WITH_VISIT_CHANNEL
00243 if (envp->submapPostProc != 0)
00244 (*envp->submapPostProc)(tagName, result);
00245 #endif
00246
00247
00248 if (normalizeOutput)
00249 env_max_normalize_inplace
00250 (result, INTMAXNORMMIN, INTMAXNORMMAX,
00251 envp->maxnorm_type,
00252 envp->range_thresh);
00253 }
00254
00255
00256 void env_chan_intensity(const char* tagName,
00257 const struct env_params* envp,
00258 const struct env_math* imath,
00259 const struct env_dims inputdims,
00260 const struct env_pyr* lowpass5,
00261 const int normalizeOutput,
00262 env_chan_status_func* status_func,
00263 void* status_userdata,
00264 struct env_image* result)
00265 {
00266 env_chan_process_pyr(tagName, inputdims, lowpass5,
00267 envp,
00268 imath,
00269 1,
00270 normalizeOutput,
00271 result);
00272
00273 if (status_func)
00274 (*status_func)(status_userdata, tagName, result);
00275 }
00276
00277
00278 void env_chan_color(const char* tagName,
00279 const struct env_params* envp,
00280 const struct env_math* imath,
00281 const struct env_rgb_pixel* const colimg,
00282 const struct env_rgb_pixel* const prev_colimg,
00283 const struct env_dims dims,
00284 env_chan_status_func* status_func,
00285 void* status_userdata,
00286 struct env_image* result)
00287 {
00288 struct env_image rg; env_img_init(&rg, dims);
00289 struct env_image by; env_img_init(&by, dims);
00290
00291 const intg32 lumthresh = (3*255) / 10;
00292 env_get_rgby(colimg, prev_colimg, dims.w * dims.h,
00293 &rg, &by, lumthresh, imath->nbits);
00294
00295 const env_size_t firstlevel = envp->cs_lev_min;
00296 const env_size_t depth = env_max_pyr_depth(envp);
00297
00298 {
00299 struct env_pyr rgpyr;
00300 env_pyr_init(&rgpyr, depth);
00301 env_pyr_build_lowpass_5(&rg, firstlevel, imath, &rgpyr);
00302
00303 env_chan_intensity("red/green", envp, imath,
00304 rg.dims, &rgpyr, 0,
00305 status_func, status_userdata, result);
00306
00307 env_pyr_make_empty(&rgpyr);
00308 }
00309
00310 struct env_image byOut = env_img_initializer;
00311
00312 {
00313 struct env_pyr bypyr;
00314 env_pyr_init(&bypyr, depth);
00315 env_pyr_build_lowpass_5(&by, firstlevel, imath, &bypyr);
00316
00317 env_chan_intensity("blue/yellow", envp, imath,
00318 by.dims, &bypyr, 0,
00319 status_func, status_userdata, &byOut);
00320 env_pyr_make_empty(&bypyr);
00321 }
00322
00323 env_img_make_empty(&rg);
00324 env_img_make_empty(&by);
00325
00326 const intg32* const byptr = env_img_pixels(&byOut);
00327 intg32* const dptr = env_img_pixelsw(result);
00328 const env_size_t sz = env_img_size(result);
00329
00330 for (env_size_t i = 0; i < sz; ++i)
00331 dptr[i] = (dptr[i] / 2) + (byptr[i] / 2);
00332
00333 env_max_normalize_inplace(result, INTMAXNORMMIN, INTMAXNORMMAX,
00334 envp->maxnorm_type,
00335 envp->range_thresh);
00336 if (status_func)
00337 (*status_func)(status_userdata, tagName, result);
00338
00339 env_img_make_empty(&byOut);
00340 }
00341
00342
00343 void env_chan_steerable(const char* tagName,
00344 const struct env_params* envp,
00345 const struct env_math* imath,
00346 const struct env_dims inputdims,
00347 const struct env_pyr* hipass9,
00348 const env_size_t thetaidx,
00349 env_chan_status_func* status_func,
00350 void* status_userdata,
00351 struct env_image* result)
00352 {
00353 const env_size_t kdenombits = ENV_TRIG_NBITS;
00354
00355
00356
00357 const intg32 sfnumer = 2069;
00358 const intg32 sfdenom = 5000;
00359
00360 const intg32 kxnumer = ((intg32) (sfnumer * imath->costab[thetaidx] * ENV_TRIG_TABSIZ)) / sfdenom;
00361 const intg32 kynumer = ((intg32) (sfnumer * imath->sintab[thetaidx] * ENV_TRIG_TABSIZ)) / sfdenom;
00362
00363
00364 struct env_pyr pyr = env_pyr_initializer;
00365 env_pyr_build_steerable_from_hipass_9(hipass9,
00366 kxnumer, kynumer, kdenombits,
00367 imath,
00368 &pyr);
00369
00370 env_chan_process_pyr(tagName, inputdims, &pyr,
00371 envp,
00372 imath,
00373 0,
00374 1,
00375 result);
00376
00377 if (status_func)
00378 (*status_func)(status_userdata, tagName, result);
00379
00380 env_pyr_make_empty(&pyr);
00381 }
00382
00383
00384 void env_chan_orientation(const char* tagName,
00385 const struct env_params* envp,
00386 const struct env_math* imath,
00387 const struct env_image* img,
00388 env_chan_status_func* status_func,
00389 void* status_userdata,
00390 struct env_image* result)
00391 {
00392 env_img_make_empty(result);
00393
00394 if (envp->num_orientations == 0)
00395 return;
00396
00397 struct env_pyr hipass9;
00398 env_pyr_init(&hipass9, env_max_pyr_depth(envp));
00399 env_pyr_build_hipass_9(img,
00400 envp->cs_lev_min,
00401 imath,
00402 &hipass9);
00403
00404 struct env_image chanOut = env_img_initializer;
00405
00406 char buf[17] =
00407 {
00408 's', 't', 'e', 'e', 'r', 'a', 'b', 'l', 'e',
00409 '(', '_', '_',
00410 '/', '_', '_', ')', '\0'
00411 };
00412
00413 ENV_ASSERT(envp->num_orientations <= 99);
00414
00415 buf[13] = '0' + (envp->num_orientations / 10);
00416 buf[14] = '0' + (envp->num_orientations % 10);
00417
00418 for (env_size_t i = 0; i < envp->num_orientations; ++i)
00419 {
00420
00421
00422
00423 const env_size_t thetaidx =
00424 (ENV_TRIG_TABSIZ * i)
00425 / (2 * envp->num_orientations)
00426 + (ENV_TRIG_TABSIZ / 4);
00427
00428 ENV_ASSERT(thetaidx < ENV_TRIG_TABSIZ);
00429
00430 buf[10] = '0' + ((i+1) / 10);
00431 buf[11] = '0' + ((i+1) % 10);
00432
00433 env_chan_steerable
00434 (buf, envp, imath, img->dims,
00435 &hipass9, thetaidx,
00436 status_func, status_userdata, &chanOut);
00437
00438 ENV_ASSERT(env_img_initialized(&chanOut));
00439
00440 if (!env_img_initialized(result))
00441 {
00442 env_img_resize_dims(result, chanOut.dims);
00443 env_c_image_div_scalar
00444 (env_img_pixels(&chanOut),
00445 env_img_size(&chanOut),
00446 (intg32) envp->num_orientations,
00447 env_img_pixelsw(result));
00448 }
00449 else
00450 {
00451 ENV_ASSERT(env_dims_equal(chanOut.dims,
00452 result->dims));
00453 env_c_image_div_scalar_accum
00454 (env_img_pixels(&chanOut),
00455 env_img_size(&chanOut),
00456 (intg32) envp->num_orientations,
00457 env_img_pixelsw(result));
00458 }
00459 }
00460
00461 env_img_make_empty(&chanOut);
00462 env_pyr_make_empty(&hipass9);
00463
00464 ENV_ASSERT(env_img_initialized(result));
00465
00466 env_max_normalize_inplace(result, INTMAXNORMMIN, INTMAXNORMMAX,
00467 envp->maxnorm_type,
00468 envp->range_thresh);
00469
00470 if (status_func)
00471 (*status_func)(status_userdata, tagName, result);
00472 }
00473
00474 #ifdef ENV_WITH_DYNAMIC_CHANNELS
00475
00476
00477 void env_chan_flicker(const char* tagName,
00478 const struct env_params* envp,
00479 const struct env_math* imath,
00480 const struct env_image* prev,
00481 const struct env_image* cur,
00482 env_chan_status_func* status_func,
00483 void* status_userdata,
00484 struct env_image* result)
00485 {
00486
00487
00488
00489
00490 if (!env_img_initialized(prev))
00491 {
00492 env_img_make_empty(result);
00493 }
00494 else
00495 {
00496 const intg32 lowthresh =
00497 (envp->scale_bits > 8)
00498 ? (envp->flicker_thresh << (envp->scale_bits - 8))
00499 : (envp->flicker_thresh >> (8 - envp->scale_bits));
00500
00501
00502
00503 struct env_image fli;
00504 env_img_init(&fli, prev->dims);
00505 abs_diff_thresh(cur, prev, lowthresh, &fli);
00506
00507 const env_size_t firstlevel = envp->cs_lev_min;
00508 const env_size_t depth = env_max_pyr_depth(envp);
00509
00510
00511 struct env_pyr pyr;
00512 env_pyr_init(&pyr, depth);
00513 env_pyr_build_lowpass_5(&fli, firstlevel, imath, &pyr);
00514
00515 env_chan_process_pyr(tagName, fli.dims, &pyr,
00516 envp,
00517 imath,
00518 1,
00519 1,
00520 result);
00521
00522 if (status_func)
00523 (*status_func)(status_userdata, tagName, result);
00524
00525 env_img_make_empty(&fli);
00526 env_pyr_make_empty(&pyr);
00527 }
00528 }
00529
00530
00531 void env_chan_msflicker(const char* tagName,
00532 const struct env_params* envp,
00533 const struct env_math* imath,
00534 const struct env_dims inputDims,
00535 const struct env_pyr* prev_lowpass5,
00536 const struct env_pyr* cur_lowpass5,
00537 env_chan_status_func* status_func,
00538 void* status_userdata,
00539 struct env_image* result)
00540 {
00541
00542
00543
00544
00545 if (env_pyr_depth(prev_lowpass5) == 0)
00546 {
00547 env_img_make_empty(result);
00548 }
00549 else
00550 {
00551 const intg32 lowthresh =
00552 (envp->scale_bits > 8)
00553 ? (envp->flicker_thresh << (envp->scale_bits - 8))
00554 : (envp->flicker_thresh >> (8 - envp->scale_bits));
00555
00556
00557
00558 struct env_pyr fli;
00559 env_pyr_init(&fli, env_pyr_depth(cur_lowpass5));
00560 abs_diff_thresh_pyr(cur_lowpass5, prev_lowpass5,
00561 lowthresh, &fli);
00562
00563 env_chan_process_pyr(tagName, inputDims, &fli,
00564 envp,
00565 imath,
00566 1,
00567 1,
00568 result);
00569
00570 if (status_func)
00571 (*status_func)(status_userdata, tagName, result);
00572
00573 env_pyr_make_empty(&fli);
00574 }
00575 }
00576
00577
00578 void env_chan_direction(const char* tagName,
00579 const struct env_params* envp,
00580 const struct env_math* imath,
00581 const struct env_dims inputdims,
00582 const struct env_pyr* unshiftedPrev,
00583 const struct env_pyr* unshiftedCur,
00584 const struct env_pyr* shiftedPrev,
00585 const struct env_pyr* shiftedCur,
00586 env_chan_status_func* status_func,
00587 void* status_userdata,
00588 struct env_image* result)
00589 {
00590 const env_size_t firstlevel = envp->cs_lev_min;
00591 const env_size_t depth = env_max_pyr_depth(envp);
00592
00593 const env_size_t nshift = (imath->nbits+1)/2;
00594
00595 if (env_pyr_depth(unshiftedPrev) == 0)
00596 {
00597
00598 env_img_make_empty(result);
00599 }
00600 else
00601 {
00602 struct env_pyr pyr;
00603 env_pyr_init(&pyr, depth);
00604
00605 const intg32 lowthresh =
00606 (envp->scale_bits > 8)
00607 ? (envp->motion_thresh << (envp->scale_bits - 8))
00608 : (envp->motion_thresh >> (8 - envp->scale_bits));
00609
00610
00611 for (env_size_t i = firstlevel; i < depth; i++)
00612 {
00613 env_img_resize_dims
00614 (env_pyr_imgw(&pyr, i),
00615 env_pyr_img(unshiftedCur, i)->dims);
00616
00617 const intg32* const ucurr = env_img_pixels(env_pyr_img(unshiftedCur, i));
00618 const intg32* const uprev = env_img_pixels(env_pyr_img(unshiftedPrev, i));
00619 const intg32* const scurr = env_img_pixels(env_pyr_img(shiftedCur, i));
00620 const intg32* const sprev = env_img_pixels(env_pyr_img(shiftedPrev, i));
00621 intg32* const dptr = env_img_pixelsw(env_pyr_imgw(&pyr, i));
00622
00623 const env_size_t sz = env_img_size(env_pyr_img(&pyr, i));
00624
00625 for (env_size_t c = 0; c < sz; ++c)
00626 {
00627 dptr[c] =
00628 ((ucurr[c] >> nshift) * (sprev[c] >> nshift)) -
00629 ((uprev[c] >> nshift) * (scurr[c] >> nshift));
00630
00631 if (dptr[c] < lowthresh) dptr[c] = 0;
00632 }
00633 }
00634
00635 env_chan_process_pyr(tagName, inputdims, &pyr,
00636 envp,
00637 imath,
00638 1,
00639 1,
00640 result);
00641
00642 if (status_func)
00643 (*status_func)(status_userdata, tagName, result);
00644
00645 env_pyr_make_empty(&pyr);
00646 }
00647 }
00648
00649 #endif // ENV_WITH_DYNAMIC_CHANNELS
00650
00651
00652
00653
00654
00655
00656
00657
00658 #endif // ENVISION_ENV_CHANNEL_C_DEFINED