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
00039
00040
00041
00042
00043
00044
00047
00048
00049
00050
00051
00052
00053 #include <iostream>
00054 #include <vector>
00055 #include "simple_tools.h"
00056 #include "cimg_dependent.h"
00057 #include "errormacros.h"
00058 #include "Image.h"
00059
00060
00061
00062
00063 using namespace std;
00064
00065
00066 namespace {
00067 inline bool in_zero_one_interval(double d) { return (d >= 0) && (d <= 1);}
00068
00069
00070 inline void uniformNoise(double* res, double lval, double uval, int num_samples)
00071 {
00072 if (uval <= lval) {
00073 throw runtime_error("uniformNoise(...) : erroneous range.");
00074 }
00075 double range = uval - lval;
00076 double scale_factor = range / double(RAND_MAX);
00077 for (int i = 0; i < num_samples; ++i) {
00078 res[i] = double(rand()) * scale_factor + lval;
00079 }
00080 }
00081
00082 };
00083
00084 namespace lsseg {
00085
00086
00087 void negate(Image<double>& img, double min, double max)
00088
00089 {
00090 double* it;
00091 for (it = img.begin(); it != img.end(); ++it) {
00092 *it = max - (*it-min);
00093 }
00094 }
00095
00096
00097 void rescale(Image<double>& img,
00098 double cur_min, double cur_max, double to_min, double to_max)
00099
00100 {
00101 double cur_int_inv = double(1) / (cur_max - cur_min);
00102 double* data = img.begin();
00103 for (size_t i = 0; i < img.size(); ++i) {
00104 double t = (data[i] - cur_min) * cur_int_inv;
00105 assert(t >= 0);
00106 data[i] = t * to_max + (1-t) * to_min;
00107 }
00108 }
00109
00110
00111 void rescale_channels(Image<double>& img, double to_min, double to_max)
00112
00113 {
00114 int chan_size = img.channelSize();
00115
00116
00117 for (int c = 0; c < img.numChannels(); ++c) {
00118 double cur_min = *min_element(img.begin() + c * chan_size,
00119 img.begin() + (c+1) * chan_size);
00120 double cur_max = *max_element(img.begin() + c * chan_size,
00121 img.begin() + (c+1) * chan_size);
00122
00123 double cur_int_inv = double(1) / (cur_max - cur_min);
00124
00125 double* data = img.begin();
00126 for (int i = 0; i < chan_size; ++i) {
00127 double& cur = data[c * chan_size + i];
00128 double t = (cur - cur_min) * cur_int_inv;
00129 cur = t * to_max + (1-t) * to_min;
00130 data[c * chan_size + i] = cur;
00131 }
00132 }
00133 }
00134
00135
00136 void clip(Image<double>& img, double min, double max)
00137
00138 {
00139 double* data = img.begin();
00140 for (int i = 0; i < int(img.size()); ++i) {
00141 double tmp = data[i];
00142 if (tmp < min) {
00143 data[i] = min;
00144 } else if (tmp > max) {
00145 data[i] = max;
00146 }
00147 }
00148 }
00149
00150
00151 void transpose(Image<double>& img)
00152
00153 {
00154 Image<double> tmp;
00155 transpose(img, tmp);
00156 img.swap(tmp);
00157 }
00158
00159
00160 void transpose(const Image<double>& img, Image<double>& target)
00161
00162 {
00163 target.resize(img);
00164 for (int c = 0; c < img.numChannels(); ++c) {
00165 for (int z = 0; z < img.dimz(); ++z) {
00166 for (int y = 0; y < img.dimy(); ++y) {
00167 for (int x = 0; x < img.dimx(); ++x) {
00168 target(y, x, z, c) = img(x, y, z, c);
00169 }
00170 }
00171 }
00172 }
00173 }
00174
00175
00176 void horizontal_sinusoidal_bands(LevelSetFunction& img, int num_bands, double phase)
00177
00178 {
00179 const double PI = 3.1415926535897932384;
00180 for (int h = 0; h < img.dimy(); ++h) {
00181 double angle = (double(h) / double(img.dimy()) + phase) * 2 * PI;
00182 double value = sin(angle * num_bands);
00183 for (int z = 0; z < img.dimz(); ++z) {
00184 for (int x = 0; x < img.dimx(); ++x) {
00185 img(x, h, z, 0) = value;
00186 }
00187 }
00188 }
00189 }
00190
00191
00192 void rectangle(LevelSetFunction& img,
00193 double xmin_ratio,
00194 double xmax_ratio,
00195 double ymin_ratio,
00196 double ymax_ratio,
00197 double zmin_ratio,
00198 double zmax_ratio)
00199
00200 {
00201 assert(img.numChannels() == 1);
00202
00203
00204 std::fill(img.begin(), img.end(), 1);
00205
00206
00207 int xmin = int(img.dimx() * xmin_ratio);
00208 int xmax = int(img.dimx() * xmax_ratio);
00209 int ymin = int(img.dimy() * ymin_ratio);
00210 int ymax = int(img.dimy() * ymax_ratio);
00211 int zmin = int(img.dimz() * zmin_ratio);
00212 int zmax = int(img.dimz() * zmax_ratio);
00213
00214 for (int z = zmin; z < zmax; ++z) {
00215 for (int y = ymin; y < ymax; ++y) {
00216 for (int x = xmin; x < xmax; ++x) {
00217 img(x, y, z) = -1;
00218 }
00219 }
00220 }
00221 }
00222
00223
00224 void init_voronoi_regions(LevelSetFunction* regs,
00225 const double* center_coords,
00226 int num_regions,
00227 bool three_d)
00228
00229 {
00230 assert(num_regions > 0);
00231 const int X = regs[0].dimx();
00232 const int Y = regs[0].dimy();
00233 const int Z = regs[0].dimz();
00234 assert(three_d || Z == 1);
00235 for (int i = 0; i < num_regions; ++i) {
00236 assert(regs[i].dimx() == X && regs[i].dimy() == Y && regs[i].dimz() == Z);
00237 }
00238 vector<double> dists(num_regions);
00239 const int stride = three_d ? 3 : 2;
00240 vector<double> abs_coords(num_regions * stride);
00241 for (int i = 0; i < num_regions; ++i) {
00242 abs_coords[i * stride] = center_coords[i * stride] * X;
00243 abs_coords[i * stride + 1] = center_coords[i * stride + 1] * Y;
00244 if (stride == 3) {
00245 abs_coords[i * stride + 2] = center_coords[i * stride + 2] * Z;
00246 }
00247 }
00248
00249 for (int z = 0; z < Z; ++z) {
00250 for (int y = 0; y < Y; ++y) {
00251 for (int x = 0; x < X; ++x) {
00252 int closest_reg = -1;
00253 double closest_dist2 = (X+Y+Z) * (X+Y+Z);
00254 for (int r = 0; r < num_regions; ++r) {
00255 double dx = x - abs_coords[r * stride + 0];
00256 double dy = y - abs_coords[r * stride + 1];
00257 double dz = (three_d) ? z - abs_coords[r * stride + 2] : 0;
00258 double cur_dist2 = dx * dx + dy * dy + dz * dz;
00259
00260 if (cur_dist2 < closest_dist2) {
00261 closest_dist2 = cur_dist2;
00262 closest_reg = r;
00263 }
00264 }
00265 assert(closest_reg != -1);
00266
00267 for (int r = 0; r < num_regions; ++r) {
00268 regs[r](x, y) = (r == closest_reg) ? -1 : 1;
00269 }
00270 }
00271 }
00272 }
00273 for (int r = 0; r < num_regions; ++r) {
00274 if (three_d) {
00275 regs[r].reinitialize3D();
00276 } else {
00277 regs[r].reinitialize2D();
00278 }
00279 }
00280 }
00281
00282
00283 void multiregion_bands(LevelSetFunction* regs,
00284 int num_regs,
00285 int pixel_bandwith)
00286
00287 {
00288 assert(num_regs > 1);
00289 const int X = regs[0].dimx();
00290 const int Y = regs[0].dimy();
00291 const int Z = regs[0].dimz();
00292 for (int i = 0; i < num_regs; ++i) {
00293 assert(regs[i].dimx() == X && regs[i].dimy() == Y && regs[i].dimz() == Z);
00294 }
00295 int current_band = 0;
00296 int b_count = 0;
00297 for (int z = 0; z < Z; ++z) {
00298 for (int y = 0; y < Y; ++y) {
00299 for (int r = 0; r < num_regs; ++r) {
00300 const double val = (r == current_band) ? -1 : 1;
00301 for (int x = 0; x < X; ++x) {
00302 regs[r](x, y, z) = val;
00303 }
00304 }
00305 ++b_count;
00306 if (b_count == pixel_bandwith) {
00307 b_count = 0;
00308 ++current_band;
00309 if (current_band == num_regs) {
00310 current_band = 0;
00311 }
00312 }
00313 }
00314 }
00315 for (int r = 0; r < num_regs; ++r) {
00316 if (Z == 1) {
00317 regs[r].reinitialize2D();
00318 } else {
00319 regs[r].reinitialize3D();
00320 }
00321 }
00322 }
00323
00324
00325 void random_scattered_voronoi(LevelSetFunction* regs,
00326 int num_regs,
00327 int num_fragments)
00328
00329 {
00330 assert(num_regs > 1);
00331 const int X = regs[0].dimx();
00332 const int Y = regs[0].dimy();
00333 const int Z = regs[0].dimz();
00334 for (int i = 0; i < num_regs; ++i) {
00335 assert(regs[i].dimx() == X && regs[i].dimy() == Y && regs[i].dimz() == Z);
00336 }
00337 const bool three_d = (Z == 1);
00338 const int stride = three_d ? 3 : 2;
00339
00340 vector<vector<double> > seed_abs_coords(num_regs);
00341 for (int i = 0; i < num_regs; ++i) {
00342 for (int fr = 0; fr < num_fragments; ++fr) {
00343 double seed_x, seed_y, seed_z;
00344 uniformNoise(&seed_x, 0, X, 1);
00345 uniformNoise(&seed_y, 0, Y, 1);
00346 seed_abs_coords[i].push_back(seed_x);
00347 seed_abs_coords[i].push_back(seed_y);
00348 if (three_d) {
00349 uniformNoise(&seed_z, 0, Z, 1);
00350 seed_abs_coords[i].push_back(seed_z);
00351 }
00352 }
00353 }
00354
00355 for (int z = 0; z < Z; ++z) {
00356 for (int y = 0; y < Y; ++y) {
00357 for (int x = 0; x < X; ++x) {
00358 int closest_reg = -1;
00359 double closest_dist2 = (X+Y+Z) * (X+Y+Z);
00360 for (int r = 0; r < num_regs; ++r) {
00361 for (int fr = 0; fr < num_fragments; ++fr) {
00362 const double dx = x - seed_abs_coords[r][stride * fr + 0];
00363 const double dy = y - seed_abs_coords[r][stride * fr + 1];
00364 const double dz = three_d ? z - seed_abs_coords[r][stride * fr + 2] : 0;
00365 double cur_dist2 = dx * dx + dy * dy + dz * dz;
00366 if (cur_dist2 < closest_dist2) {
00367 closest_dist2 = cur_dist2;
00368 closest_reg = r;
00369 }
00370 }
00371 }
00372 assert(closest_reg != -1);
00373
00374 for (int r = 0; r < num_regs; ++r) {
00375 regs[r](x, y, z) = (r == closest_reg) ? -1 : 1;
00376 }
00377 }
00378 }
00379 }
00380 for (int r = 0; r < num_regs; ++r) {
00381 if (three_d) {
00382 regs[r].reinitialize3D();
00383 } else {
00384 regs[r].reinitialize2D();
00385 }
00386 }
00387 }
00388
00389
00390 void set_from_parzen(LevelSetFunction& phi,
00391 const ParzenDistributionForce pf,
00392 const Mask* m)
00393
00394 {
00395 assert(pf.baseImage()->spatial_compatible(phi));
00396
00397 if (!m) {
00398 for (size_t ix = 0; ix < phi.size(); ++ix) {
00399 if (pf.force(ix) < 0) {
00400 phi[ix] = 1;
00401 } else {
00402 phi[ix] = -1;
00403 }
00404 }
00405 } else {
00406 phi = 1;
00407 for (size_t ix = 0; ix < phi.size(); ++ix) {
00408 if ((*m)[ix] && pf.force(ix) > 0) {
00409 phi[ix] = -1;
00410 }
00411 }
00412 }
00413 phi.reinitialize3D(m);
00414 }
00415
00416
00417 void sphere(LevelSetFunction& img,
00418 double relrad,
00419 double xrelpos,
00420 double yrelpos,
00421 double zrelpos)
00422
00423 {
00424 assert(img.numChannels() == 1);
00425
00426 const int xmax = img.dimx();
00427 const int ymax = img.dimy();
00428 const int zmax = img.dimz();
00429
00430 const int xpos = int (xmax * xrelpos);
00431 const int ypos = int (ymax * yrelpos);
00432 const int zpos = int (zmax * zrelpos);
00433
00434 int maxim = xmax > ymax ? xmax : ymax;
00435 maxim = maxim > zmax ? maxim : zmax;
00436 int radius2 = int(relrad * maxim);
00437 radius2 *= radius2;
00438
00439 for (int z = 0; z < zmax; ++z) {
00440 for (int y = 0; y < ymax; ++y) {
00441 for (int x = 0; x < xmax; ++x) {
00442 double dx = (xpos - x);
00443 double dy = (ypos - y);
00444 double dz = (zpos - z);
00445 double dist2 = dx * dx + dy * dy + dz * dz;
00446 img(x, y, z) = (dist2 > radius2) ? sqrt(dist2 - radius2) : -sqrt(radius2 - dist2);
00447 }
00448 }
00449 }
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 void make_border_mask(const LevelSetFunction& phi, Mask& target, int bandwidth, const Mask* geom_mask)
00499
00500 {
00501 ALWAYS_ERROR_IF(phi.numChannels() != 1, "wrong number of channels");
00502
00503 target.resize(phi.dimx(), phi.dimy(), phi.dimz(), 1);
00504 fill(target.begin(), target.end(), 0);
00505
00506 ALWAYS_ERROR_IF(bandwidth < 1, "zero or negative bandwidth");
00507
00508
00509 const int X = phi.dimx();
00510 const int Y = phi.dimy();
00511 const int Z = phi.dimz();
00512 const int bm1 = bandwidth - 1;
00513 const int Xmb = X - bandwidth;
00514 const int Ymb = Y - bandwidth;
00515 const int Zmb = Z - bandwidth;
00516
00517 const Mask::value_type* m_it = geom_mask ? geom_mask->begin() : 0;
00518
00519 for (int z = 0; z < Z; ++z) {
00520 const int zn = (z < Z-1) ? z+1 : z;
00521 for (int y = 0; y < Y; ++y) {
00522 const int yn = (y < Y-1) ? y+1 : y;
00523 for (int x = 0; x < X; ++x) {
00524 if (geom_mask && !(*m_it++)) {
00525 continue;
00526 }
00527 const int xn = (x < X-1) ? x+1 : x;
00528
00529 const double Iccc = phi( x, y, z, 0);
00530 const double Incc = phi(xn, y, z, 0);
00531 const double Icnc = phi( x, yn, z, 0);
00532 const double Iccn = phi( x, y, zn, 0);
00533
00534 if (Iccc * Incc <= 0 || Iccc * Icnc <= 0 || Iccc * Iccn <= 0) {
00535
00536 const int xstart = (x >= bm1) ? x - bm1 : 0;
00537 const int xend = (x < Xmb) ? x + bandwidth : X - 1;
00538
00539 const int ystart = (y >= bm1) ? y - bm1 : 0;
00540 const int yend = (y < Ymb) ? y + bandwidth : Y-1;
00541
00542 const int zstart = (z >= bm1) ? z - bm1 : 0;
00543 const int zend = (z < Zmb) ? z + bandwidth : Z-1;
00544
00545 for (int zz = zstart; zz <= zend; ++zz) {
00546 for (int yy = ystart; yy <= yend; ++yy) {
00547 for (int xx = xstart; xx <= xend; ++xx) {
00548 target(xx, yy, zz) = 1;
00549 }
00550 }
00551 }
00552 }
00553 }
00554 }
00555 }
00556 }
00557
00558
00559 void mask_from_segmentation(const LevelSetFunction& phi,
00560 Mask& target,
00561 SEG_REGION reg)
00562
00563 {
00564 target.resize(phi);
00565 const double* in = phi.begin();
00566 char* out = target.begin();
00567
00568 switch (reg) {
00569 case SEG_NEGATIVE:
00570 for (;in != phi.end(); ++in, ++out) {
00571 *out = *in < 0;
00572 }
00573 break;
00574 case SEG_POSITIVE:
00575 for (;in != phi.end(); ++in, ++out) {
00576 *out = *in > 0;
00577 }
00578 break;
00579 default:
00580 ALWAYS_ERROR_IF(true, "logical error in mask_from_segmentation");
00581 }
00582 }
00583
00584
00585
00586 void read_image_sequence(istream& image_list,
00587 Image<double>& result,
00588 bool convert_to_grayscale)
00589
00590 {
00591 vector<string> filenames;
00592
00593
00594 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
00595 char cur_name[_MAX_PATH];
00596 #else
00597 string cur_name;
00598 #endif
00599
00600 while (image_list >> cur_name) {
00601 filenames.push_back(cur_name);
00602 }
00603 if (filenames.size() == 0) {
00604 return;
00605 }
00606 cout << "Total number of images to read: " << filenames.size() << endl;
00607
00608
00609 Image<double> im;
00610 load_image(filenames[0].c_str(), im, convert_to_grayscale);
00611 assert(im.dimz() == 1);
00612
00613 result.resize(im.dimx(), im.dimy(), int(filenames.size()), im.numChannels());
00614
00615 int total_size = im.size();
00616 double* cur_pos = result.begin();
00617 copy(im.begin(), im.end(), cur_pos);
00618 cur_pos += total_size;
00619 for (size_t fnum = 1; fnum < filenames.size(); ++fnum) {
00620 cout << "Now reading image: " << fnum << endl;
00621 load_image(filenames[fnum].c_str(), im, convert_to_grayscale);
00622 assert(im.size() == total_size);
00623 copy(im.begin(), im.end(), cur_pos);
00624 cur_pos += total_size;
00625 }
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 unsigned long int nonzeroes(const Image<int>& img)
00668
00669 {
00670 unsigned long int res = 0;
00671 for (const int* dp = img.begin(); dp != img.end(); ++dp) {
00672 if (*dp != 0) {
00673 ++res;
00674 }
00675 }
00676 return res;
00677 }
00678
00679
00680 double nonzero_ratio(const Image<int>& img)
00681
00682 {
00683 unsigned long int total_size = img.size();
00684
00685 return double(nonzeroes(img)) / double(total_size);
00686 }
00687
00688
00689 unsigned long int positives(const Image<double>& img)
00690
00691 {
00692 unsigned long int res = 0;
00693 for (unsigned long int i =0 ; i < img.size(); ++i) {
00694 if (img[i] >= 0) {
00695 ++res;
00696 }
00697 }
00698 return res;
00699 }
00700
00701
00702 unsigned long int negatives(const Image<double>& img)
00703
00704 {
00705 return img.size() - positives(img);
00706 }
00707
00708
00709 double positive_ratio(const Image<double>& img)
00710
00711 {
00712 return double(positives(img)) / double(img.size());
00713 }
00714
00715
00716 double negative_ratio(const Image<double>& img)
00717
00718 {
00719 return double(negatives(img)) / double(img.size());
00720 }
00721
00722 };