| Bsoft 2.0.5 Bernard's software package

Bimage_segment.cpp
Go to the documentation of this file.
1
9 #include <math.h>
10 #include <time.h>
11 #include "Bimage.h"
12 #include "linked_list.h"
13 #include "utilities.h"
14
15 // Declaration of global variables
16 extern int verbose; // Level of output to the screen
17
21 struct GSedge {
22 long u, v; // GSedge ends in the 1D data array
23 float w; // GSedge weight: Neighbor value difference
24 } ;
25
29 struct GSregion {
30 long p; // GSregion index
31 int r; // Number of region joins
32 int s; // Number of voxels in the region
33 float a; // Average value for the region
34 } ;
35
36
58 Bimage* Bimage::regions(double threshold, int sign)
59 {
60 // The extreme considered as a region depends on the threshold and sign
61 if ( sign < 0 ) sign = -1;
62 else if ( sign > 0 ) sign = 1;
63 else {
64 sign = 1;
65 if ( threshold < avg ) sign = -1;
66 }
67
68 long i, count(0), rsize;
69 double abs_threshold(sign*threshold);
70
71 if ( verbose & VERB_PROCESS ) {
72 cout << "Finding regions:" << endl;
73 cout << "Threshold: " << threshold << " (" << sign << ")" << endl;
74 }
75
76 Bimage* pmask = new Bimage(Integer, TSimple, size(), n);
77 pmask->file_name(file_name());
78 pmask->sampling(sampling());
79 for ( i=0; i<n; i++ ) pmask->image[i] = image[i];
80
81 //Using a mask, all the regions are grouped and numbered.
82 for ( i=0; i<datasize; i++ ) {
83 if ( (*pmask)[i] == 0 ) {
84 if ( sign*(*this)[i] > abs_threshold ) {
85 count++;
86 rsize = region_assign(pmask, i, count, threshold, sign);
87 if ( verbose & VERB_DEBUG )
88 cout << "DEBUG Bimage::regions: i=" << i << " count=" <<
89 count << " rsize=" << rsize << endl;
90 }
91 }
92 }
93
94 pmask->statistics();
95
96 if ( verbose & VERB_PROCESS )
97 cout << "Regions: " << count << endl << endl;
98
99 return pmask;
100 }
101
102
121 long Bimage::region_assign(Bimage* pmask, long idx,
122 long region_number, double threshold, int sign)
123 {
124 if ( verbose & VERB_DEBUG )
125 cout << "DEBUG Bimage::region_assign: Starting with region " <<
126 region_number << " idx=" << idx << endl;
127
128 if ( sign < 0 ) sign = -1;
129 else if ( sign > 0 ) sign = 1;
130 else {
131 sign = 1;
132 if ( threshold < avg ) sign = -1;
133 }
134
135 double abs_threshold(sign*threshold);
136 long i, j, nn, kx, ky, kz;
137 Vector3<long> lo, hi;
138
139 // Set up two lists:
140 // First list is for voxels to loop through for checking
141 // Second list is for new voxels to be checked in a subsequent iteration
142 long number, new_number, count(1);
143 long list_size = 2*(x + y)*z;
144 if ( z > 1 ) list_size += 2*x*y;
145 int* list = new int[list_size];
146 int* new_list = new int[list_size];
147
148 // Initialize the first item in the list
149 pmask->set(idx, region_number);
150 number = 1;
151 list[0] = idx;
152 nn = idx / (x*y*z);
153
154 // Find neighbors in shells around already found neighbors
155 while ( number > 0 ) {
156 if ( verbose & VERB_DEBUG )
157 cout << "DEBUG Bimage::region_assign: region=" << region_number << " list size=" << number << endl;
158 new_number = 0;
159 for ( i=0; i<number; i++ ) {
160 lo = kernel_low(list[i]);
161 hi = kernel_high(list[i]);
162
163 // Loop through the kernel and construct the new list
164 for ( kz=lo[2]; kz<=hi[2]; kz++ ) {
165 for ( ky=lo[1]; ky<=hi[1]; ky++ ) {
166 for ( kx=lo[0]; kx<=hi[0]; kx++ ) {
167 j = index(kx, ky, kz, nn);
168 if ( ((*pmask)[j] == 0) && (sign*(*this)[j] > abs_threshold) ) {
169 pmask->set(j, region_number);
170 count++;
171 new_list[new_number] = j;
172 new_number++;
173 if ( new_number >= list_size ) {
174 cerr << "Error: The list size exceeded its limit ("
175 << list_size << ")" << endl;
176 }
177 }
178 }
179 }
180 }
181 }
182 number = new_number;
183 for ( i=0; i<number; i++ ) list[i] = new_list[i];
184 }
185
186 delete[] list;
187 delete[] new_list;
188
189 if ( verbose & VERB_DEBUG )
190 cout << "DEBUG Bimage::region_assign: Ending with region " << region_number << endl;
191
192 return count;
193 }
194
202 int Bimage::region_threshold_series(double threshold_first,
203 double threshold_last, double threshold_step)
204 {
205 int sign(1);
206 double threshold, a(0);
207 Bimage* pmask;
208
209 if ( threshold_step == 0 ) {
210 if ( threshold_last == threshold_first )
211 threshold_step = 1;
212 else
213 threshold_step = threshold_last - threshold_first;
214 } else {
215 if ( threshold_step > 0 && threshold_first > threshold_last )
216 threshold_step = -threshold_step;
217 if ( threshold_step < 0 && threshold_first < threshold_last )
218 threshold_step = -threshold_step;
219 }
220
221 if ( threshold_step < 0 ) sign = -1;
222 threshold_last += threshold_step/2;
223
224 cout << "Finding the number of regions at each threshold:" << endl;
225 cout << "Thresh\tRegions\tAvgSize" << endl;
226 for ( threshold = threshold_first; sign*threshold <= sign*threshold_last;
227 threshold+=threshold_step ) {
228 pmask = regions(threshold, 0);
229 a = pmask->levelmask_average_region_size();
230 cout << threshold << tab << pmask->maximum() << tab << a << endl;
231 delete pmask;
232 }
233 cout << endl;
234
235 return 0;
236 }
237
257 long Bimage::region_flood(Bimage* pmask, double threshold_hi,
258 double threshold_lo, double threshold_step, int fill_borders)
259 {
260 if ( !pmask ) {
261 error_show("No region mask in Bimage::region_flood", __FILE__, __LINE__);
262 return 0;
263 }
264
265 long i;
266
267 // The extreme considered as a region depends on the sign of the threshold
268 int sign(1);
269 if ( threshold_hi < avg ) sign = -1;
270 if ( fabs(threshold_hi-avg) < fabs(threshold_lo-avg) )
271 swap(threshold_hi, threshold_lo);
272 double threshold, dt;
273 if ( threshold_step == 0 )
274 threshold_step = (threshold_lo - threshold_hi)/100;
275 else if ( (threshold_lo - threshold_hi)/threshold_step < 0 )
276 threshold_step *= -1;
277 double abs_threshold(sign*threshold_hi);
278 double abs_threshold_lo(sign*threshold_lo);
279
280 if ( verbose & VERB_LABEL ) {
281 cout << "Segmenting an image by flooding from a threshold or region set:" << endl;
282 if ( pmask )
283 cout << "Region set: " << pmask->file_name() << endl;
284 cout << "Starting threshold: " << threshold_hi << endl;
285 cout << "Finishing threshold: " << threshold_lo << endl;
286 cout << "Threshold step: " << threshold_step << endl;
287 }
288
289 if ( !check_if_same_size(pmask) ) {
290 error_show("Error in Bimage::region_flood", __FILE__, __LINE__);
291 cerr << "The region mask must have the same dimensions as the image!" << endl;
292 return 0;
293 }
294
295 if ( pmask->data_type() != Integer ) {
296 if ( pmask->data_type() > Integer )
297 cerr << "Warning: The region mask must of integer type!" << endl;
298 pmask->change_type(Integer);
299 }
300
301 if ( verbose & VERB_LABEL )
302 cout << "Starting regions: " << pmask->maximum() << endl;
303
304 Bimage* pt = pmask->copy();
305
306 // Progressively decrease threshold and find new adjacent voxels belonging to
307 // each region - disputes over voxel assignment are settled later
308 for ( threshold=threshold_hi; abs_threshold>abs_threshold_lo; threshold+=threshold_step ) {
309 abs_threshold = sign*threshold;
310 dt = threshold_lo - threshold_hi;
311 if ( dt > 0 ) dt = 100*(threshold - threshold_hi)/dt;
312 else dt = 100;
313 if ( verbose )
314 cout << "Processing threshold: " << threshold << " (" << dt << " %) \r" << flush;
315
316 #ifdef HAVE_GCD
317 dispatch_apply(datasize, dispatch_get_global_queue(0, 0), ^(size_t it){
318 if ( sign*(*this)[it] > abs_threshold )
319 pt->set(it, pmask->check_neighbors(it));
320 else
321 pt->set(it, 0);
322 });
323 #else
324 #pragma omp parallel for
325 for ( long it=0; it<datasize; it++ ) {
326 if ( sign*(*this)[it] > abs_threshold )
327 pt->set(it, pmask->check_neighbors(it));
328 else
329 pt->set(it, 0);
330 }
331 #endif
332 for ( i=0; i<datasize; i++ ) pmask->set(i, (*pt)[i]);
333 }
334
335 if ( verbose )
336 cout << endl;
337
338 long nborder(0), dnb(1), maxtries(20);
339
340 for ( i=0; i<datasize; i++ ) if ( (*pmask)[i] < 0 ) nborder++;
341 if ( verbose & VERB_LABEL )
342 cout << "Border voxels: " << nborder << endl;
343
344 // Assign the borders between regions to one of the regions
345 if ( fill_borders ) {
346 if ( verbose & VERB_PROCESS )
347 cout << "Assigning borders:" << endl;
348
349 while ( maxtries-- > 0 && nborder > 0 && dnb > 0 ) {
350 if ( verbose )
351 cout << "Processing border voxels: " << nborder << " \r" << flush;
352 dnb = nborder;
353 nborder = 0;
354
355 #ifdef HAVE_GCD
356 dispatch_apply(datasize, dispatch_get_global_queue(0, 0), ^(size_t it){
357 if ( (*pmask)[it] < 0 ) {
358 size_t j = kernel_max_neigbor(it, 1);
359 pmask->set(it, (*pmask)[j]);
360 if ( (*pmask)[it] < 0 ) {
361 j = kernel_max_neigbor(it, 2);
362 pmask->set(it, (*pmask)[j]);
363 }
364 }
365 });
366 #else
367 #pragma omp parallel for
368 for ( long it=0; it<datasize; it++ ) {
369 if ( (*pmask)[it] < 0 ) {
370 long j = kernel_max_neigbor(it, 1);
371 pmask->set(it, (*pmask)[j]);
372 if ( (*pmask)[it] < 0 ) {
373 j = kernel_max_neigbor(it, 2);
374 pmask->set(it, (*pmask)[j]);
375 }
376 }
377 }
378 #endif
379 for ( long it=0; it<datasize; it++ ) if ( (*pmask)[it] < 0 ) nborder++;
380
381 dnb -= nborder;
382 }
383
384 if ( verbose )
385 cout << "Processing border voxels: " << nborder << endl;
386 if ( verbose && nborder > 0 )
387 cerr << "Warning: " << nborder << " border voxels were not assigned!" << endl;
388 }
389
390 long nseg = (long)(pmask->maximum() + 1.9);
391 int* vol;
392
393 if ( verbose & VERB_FULL ) {
394 vol = new int[nseg];
395 for ( i=0; i<nseg; i++ ) vol[i] = 0;
396 for ( i=0; i<datasize; i++ )
397 if ( (*pmask)[i] > -1 ) vol[(long)(*pmask)[i]]++;
398 cout << "Region\tVoxels\tVolume\tMass" << endl;
399 for ( i=1; i<nseg; i++ )
400 cout << i << tab << vol[i] << tab << vol[i]*sampling().volume()
401 << tab << vol[i]*sampling().volume()*RHO << endl;
402 delete[] vol;
403 }
404
405 if ( verbose )
406 cout << endl;
407
408 if ( verbose & VERB_DEBUG )
409 cout << "DEBUG Bimage::region_flood: Finished with segmentation" << endl;
410
411 return nseg;
412 }
413
419 long Bimage::check_neighbors(long idx)
420 {
421 if ( (*this)[idx] != 0 ) return (long)(*this)[idx];
422
423 long i, xx, yy, zz, nn(0), nv(0);
424
425 //calculate the bounds on the kernel
426 Vector3<long> lo = kernel_low(idx);
427 Vector3<long> hi = kernel_high(idx);
428
429 // Loop through the kernel and check neighbors
430 for ( zz=lo[2]; zz<=hi[2]; zz++ ) {
431 for ( yy=lo[1]; yy<=hi[1]; yy++ ) {
432 for ( xx=lo[0]; xx<=hi[0]; xx++ ) {
433 i = index(0,xx,yy,zz,nn);
434 if ( i != idx ) {
435 if ( (*this)[i] > 0 ) {
436 if ( nv == 0 )
437 nv = (long)(*this)[i];
438 else if ( nv != (*this)[i] )
439 nv = -100; // Border voxel
440 }
441 }
442 }
443 }
444 }
445
446 if ( verbose & VERB_DEBUG )
447 cout << "DEBUG Bimage::check_neighbors: Ending with region " << (int)(*this)[idx] << endl;
448
449 return nv;
450 }
451
470 Bimage* Bimage::region_peaks(long kernel_size, double threshold, int flood, int wrap)
471 {
472 if ( kernel_size < 3 ) kernel_size = 3;
473
474 long i, nn, dn;
475 long hk(kernel_size/2), npeak(0);
476
477 if ( verbose & VERB_LABEL ) {
478 cout << "Segmenting an image by flooding from peaks:" << endl;
479 cout << "Kernel size: " << 2*hk+1 << endl;
480 cout << "Threshold: " << threshold << endl;
481 if ( wrap ) cout << "With wrapping" << endl;
482 }
483
484 Bimage* pmask = new Bimage(Integer, TSimple, size(), n);
485 pmask->sampling(sampling());
486 for ( nn=0; nn<n; nn++ ) pmask->image[nn] = image[nn];
487
488 int* pnt = new int[datasize];
489 for ( i=0; i<datasize; i++ ) pnt[i] = -1;
490
491 #ifdef HAVE_GCD
492 dispatch_apply(datasize, dispatch_get_global_queue(0, 0), ^(size_t i){
493 if ( (*this)[i] >= threshold ) {
494 if ( wrap ) pnt[i] = kernel_max_wrap(i, hk);
495 else pnt[i] = kernel_max(i, hk);
496 }
497 });
498 #else
499 #pragma omp parallel for
500 for ( i=0; i<datasize; ++i ) {
501 if ( (*this)[i] >= threshold ) {
502 if ( wrap ) pnt[i] = kernel_max_wrap(i, hk);
503 else pnt[i] = kernel_max(i, hk);
504 }
505 }
506 #endif
507
508 for ( i=npeak=0; i<datasize; i++ )
509 if ( pnt[i] == i ) pmask->set(i, ++npeak);
510
511 if ( flood ) {
512 nn = 0;
513 dn = 1;
514 while ( dn ) {
515 dn = nn;
516 for ( i=0; i<datasize; i++ )
517 if ( (*this)[i] >= threshold && (*pmask)[i] < 1 )
518 pmask->set(i, (*pmask)[pnt[i]]);
519 for ( i=nn=0; i<datasize; i++ ) if ( (*pmask)[i] > 0 ) nn++;
520 dn = nn - dn;
521 }
522 }
523
524 delete[] pnt;
525
526 pmask->maximum(npeak);
527
528 if ( verbose & VERB_LABEL )
529 cout << "Number of peaks: " << npeak << endl << endl;
530
531 return pmask;
532 }
533
551 long Bimage::blobs(double threshold, double min_size, double max_size,
552 double setvalue, int sign)
553 {
554 if ( min_size > max_size ) swap(min_size, max_size);
555
556 if ( sign < 0 ) sign = -1;
557 else if ( sign > 0 ) sign = 1;
558 else {
559 sign = 1;
560 if ( threshold < avg ) sign = -1;
561 }
562
563 if ( verbose & ( VERB_LABEL | VERB_PROCESS ) ) {
564 if ( sign > 0 )
565 cout << "Finding blobs above " << threshold << endl;
566 else
567 cout << "Finding blobs below " << threshold << endl;
568 }
569
570 if ( verbose & VERB_PROCESS ) {
571 cout << "Size range to keep: " << min_size << " - " << max_size << endl;
572 cout << "Set value: " << setvalue << endl << endl;
573 }
574
575 Bimage* pmask = regions(threshold, sign);
576 long count = (long) pmask->maximum();
577
578 long i, f, nvox(0), nblobs(0);
579
580 int* region_size = new int[count+1];
581
582 for ( i=0; i<=count; i++ ) region_size[i] = 0;
583
584 for ( i=0; i<datasize; i++ ) region_size[(long)(*pmask)[i]]++;
585
586 if ( verbose & VERB_PROCESS ) {
587 cout << "Region\tSize";
588 for ( i=0; i<=count; i++ ) {
589 if ( i%5 == 0 ) cout << endl << i;
590 cout << tab << region_size[i];
591 }
592 cout << endl << endl;
593 }
594
595 if ( ( min_size > 0 ) || ( max_size < datasize ) ) {
596 for ( i=1; i<=count; i++ )
597 if ( region_size[i] < min_size || region_size[i] > max_size ) nblobs++;
598
599 for ( i=0; i<datasize; i++ ) {
600 f = (long)(*pmask)[i];
601 if ( f > 0 ) {
602 if ( ( region_size[f] < min_size ) || ( region_size[f] > max_size ) ) {
603 set(i, setvalue);
604 nvox++;
605 }
606 }
607 }
608 }
609
610 if ( verbose & VERB_PROCESS ) {
611 cout << "Number of blobs deleted: " << nblobs << endl;
612 cout << "Number of voxels set: " << nvox << endl << endl;
613 }
614
615 delete[] region_size;
616
617 // write_img("pf.pif", pmask);
618
619 delete pmask;
620
621 statistics();
622
623 return nvox;
624 }
625
634 int Bimage::filter_extremes()
635 {
636 statistics();
637
638 double threshold = avg + 3*std;
639 if ( threshold >= max ) threshold = (max - avg)*0.75 + avg;
640
641 blobs(threshold, 100, 1e30, avg, 0);
642
643 threshold = avg - 3*std;
644 if ( threshold <= min ) threshold = (min - avg)*0.75 + avg;
645
646 blobs(threshold, 1000, 1e30, avg, 0);
647
648 return 0;
649 }
650
663 int Bimage::filter_extremes(int mod_flag)
664 {
665 double tmin, tmax;
666
667 histogram_thresholds(tmin, tmax);
668
669 if ( mod_flag )
670 truncate_to_min_max(tmin, tmax);
671 else
672 truncate_to_avg(tmin, tmax);
673
674 return 0;
675 }
676
677
692 long Bimage::replace_maxima(double threshold)
693 {
694 Bimage* pmask = regions(threshold, 0);
695
696 if ( verbose & ( VERB_LABEL | VERB_PROCESS ) ) {
697 cout << "Replacing maxima above: " << threshold << endl;
698 cout << "Number of maxima: " << pmask->maximum() << endl << endl;
699 }
700
701 if ( pmask->maximum() < 1 ) { // No regions found = no modification
702 delete pmask;
703 return 0;
704 }
705
706 long i, j, k, m, nn, xx, yy, zz, iter, nvr(0);
707 long kx, ky, kz, nval, tx, ty, tz;
708 long nr((long) (pmask->maximum() + 1.9)), rs;
709 double val;
710 Vector3<long> lo, hi, region_size;
711
712 int* num = new int[nr];
713 int* nimg = new int[nr];
714 Vector3<float>* region = new Vector3<float>[nr];
715 Vector3<int>* rmin = new Vector3<int>[nr];
716 Vector3<int>* rmax = new Vector3<int>[nr];
717 float* temp;
718
719 for ( j=1; j<nr; j++ ) rmin[j] = size();
720
721 for ( i=nn=0; nn<n; nn++ ) {
722 for ( zz=0; zz<z; zz++ ) {
723 for ( yy=0; yy<y; yy++ ) {
724 for ( xx=0; xx<x; xx++, i++ ) {
725 j = (long) (*pmask)[i];
726 if ( j ) {
727 num[j]++;
728 nimg[j] = nn;
729 region[j][0] += xx;
730 region[j][1] += yy;
731 region[j][2] += zz;
732 if ( rmin[j][0] > xx ) rmin[j][0] = xx;
733 if ( rmin[j][1] > yy ) rmin[j][1] = yy;
734 if ( rmin[j][2] > zz ) rmin[j][2] = zz;
735 if ( rmax[j][0] < xx ) rmax[j][0] = xx;
736 if ( rmax[j][1] < yy ) rmax[j][1] = yy;
737 if ( rmax[j][2] < zz ) rmax[j][2] = zz;
738 }
739 }
740 }
741 }
742 }
743
744 if ( verbose & VERB_STATS )
745 cout << "Regions:\n#\tImage\tx\ty\tz\tSize" << endl;
746 for ( j=1; j<nr; j++ ) {
747 nn = nimg[j];
748 if ( num[j] ) region[j] /= num[j];
749 if ( verbose & VERB_STATS )
750 cout << j << tab << nn << tab << region[j] << tab << num[j] << endl;
751 rmin[j] = rmin[j].max(0);
752 rmax[j] = rmax[j].min(size()-1);
753 region_size = rmax[j] - rmin[j] + 1;
754 rs = (long) region_size.volume();
755 temp = new float[rs];
756 nval = iter = 0;
757 val = 0;
758 while ( nval < num[j] ) {
759 for ( k=0; k<rs; k++ )
760 temp[k] = min;
761 for ( zz=rmin[j][2], tz=0; zz<=rmax[j][2]; zz++, tz++ ) {
762 for ( yy=rmin[j][1], ty=0; yy<=rmax[j][1]; yy++, ty++ ) {
763 for ( xx=rmin[j][0], tx=0; xx<=rmax[j][0]; xx++, tx++ ) {
764 i = index(0,xx,yy,zz,nn);
765 lo = kernel_low(i);
766 hi = kernel_high(i);
767 if ( (*pmask)[i] == j ) {
768 val = 0;
769 m = 0;
770 for ( kz=lo[2]; kz<=hi[2]; kz++ ) {
771 for ( ky=lo[1]; ky<=hi[1]; ky++ ) {
772 for ( kx=lo[0]; kx<=hi[0]; kx++ ) {
773 k = index(0,kx,ky,kz,nn);
774 if ( (*pmask)[k] < 1 ) {
775 val += (*this)[k];
776 m++;
777 }
778 }
779 }
780 }
781 if ( m ) {
782 k = (tz*region_size[1] + ty)*region_size[0] + tx;
783 temp[k] = val/m;
784 }
785 }
786 }
787 }
788 }
789 for ( zz=rmin[j][2], k=tz=0; zz<=rmax[j][2]; zz++, tz++ ) {
790 for ( yy=rmin[j][1], ty=0; yy<=rmax[j][1]; yy++, ty++ ) {
791 for ( xx=rmin[j][0], tx=0; xx<=rmax[j][0]; xx++, tx++, k++ ) {
792 if ( temp[k] > min ) {
793 i = index(0,xx,yy,zz,nn);
794 set(i, temp[k]);
795 if ( (*pmask)[i] == j ) pmask->set(i, 0);
796 nval++;
797 }
798 }
799 }
800 }
801 iter++;
802 if ( verbose & VERB_FULL )
803 cout << iter << ":\t" << nval << endl;
804 }
805 delete[] temp;
806 nvr += nval;
807 }
808 if ( verbose & ( VERB_STATS | VERB_FULL ) )
809 cout << endl;
810
811 delete[] num;
812 delete[] nimg;
813 delete[] region;
814 delete[] rmin;
815 delete[] rmax;
816
817 delete pmask;
818
819 return nvr;
820 }
821
834 double Bimage::mass_threshold(long img_num, double mol_weight, double rho)
835 {
836 if ( rho <= 0 ) rho = RHO;
837
838 long i, j, nn, nvox(0);
839 long dnvox(-1);
840 long imgsize(x*y*z);
841
842 double mass, dmass, vs(voxel_size());
843 double volume(mol_weight/rho);
844 double threshold(0);
845 double thresh_step;
846 double vol_diff;
847 double min_vol(vs);
848 double min_step(1e-6*std);
849
850 if ( verbose & VERB_LABEL ) {
851 cout << "Finding the threshold for image " << img_num+1 << ":" << endl;
852 cout << "Protein density: " << rho << " Da/A3" << endl;
853 cout << "Molecular weight: " << mol_weight << " Da" << endl;
854 cout << "Molecular volume: " << volume << " A3" << endl;
855 cout << "Voxel size: " << vs << " A3" << endl << endl;
856 }
857
858 if ( verbose )
859 cout << "Image\tThresh\tVolRes\tIntMass\tMW/mass" << endl;
860 for ( nn=0; nn<n; nn++ ) {
861 if ( verbose & VERB_FULL )
862 cout << " Threshold\tThreshStep\tVolume(A3)\tDifference\tMass" << endl;
863 threshold = avg;
864 thresh_step = std/2;
865 nvox = 0;
866 mass = 0;
867 vol_diff = 1e30;
868 while ( fabs(vol_diff) >= min_vol && fabs(thresh_step) > min_step ) {
869 dnvox = nvox;
870 dmass = mass;
871 if ( vol_diff > 0 ) {
872 if ( thresh_step < 0 ) thresh_step *= -0.5;
873 } else {
874 if ( thresh_step > 0 ) thresh_step *= -0.5;
875 }
876 threshold += thresh_step;
877 for ( i=nn*imgsize, j=i+imgsize, nvox = 0, mass = 0; i<j; i++ ) {
878 if ( (*this)[i] >= threshold ) {
879 nvox++;
880 mass += (*this)[i];
881 }
882 }
883 vol_diff = nvox*vs - volume;
884 if ( verbose & VERB_FULL )
885 cout << threshold << tab << thresh_step << tab
886 << nvox*vs << tab << vol_diff << tab << mass << endl;
887 dnvox = nvox - dnvox;
888 dmass = mass - dmass;
889 }
890 if ( verbose )
891 cout << nn+1 << tab << threshold << tab <<
892 fabs(vol_diff)/volume << tab << mass << tab << mol_weight/mass << endl;
893 }
894 if ( verbose )
895 cout << endl;
896
897 /*
898 if ( verbose & VERB_LABEL ) {
899 cout << "Threshold: " << threshold << endl;
900 cout << "Relative volume residual: " << fabs(vol_diff)/volume << endl;
901 cout << "Integrated mass: " << mass << endl;
902 cout << "Molecular weight/mass: " << mol_weight/mass << endl << endl;
903 }
904 */
905 return threshold;
906 }
907
918 double Bimage::mass_at_threshold(long img_num, double threshold, double rho)
919 {
920 if ( rho <= 0 ) rho = RHO;
921
922 long i, j, nvox;
923 long imgsize(x*y*z);
924
925 for ( i=img_num*imgsize, j=i+imgsize, nvox=0; i<j; i++ )
926 if ( (*this)[i] >= threshold ) nvox++;
927
928 double vs(voxel_size());
929 double volume(nvox*vs);
930 double mass(volume*rho);
931
932 if ( verbose & VERB_LABEL ) {
933 cout << "Protein density: " << rho << " Da/A3" << endl;
934 cout << "Threshold: " << threshold << endl;
935 cout << "Volume: " << volume << " A3" << endl;
936 cout << "Molecular weight: " << mass << " Da" << endl << endl;
937 }
938
939 return mass;
940 }
941
950 double Bimage::internal_volume(double threshold, int mask_out_freq)
951 {
952 long i, j, jn, jz, jy, nn;
953 long xx, yy, zz, kx, ky, kz;
954 long iter, dvol, vol(0);
955 long slicesize(x*y), imgsize(x*y*z);
956 double vs(voxel_size());
957 Vector3<long> lo, hi;
958 Vector3<long> lo2, hi2;
959
960 Bstring fn;
961
962 int nb, nbcut(6), sign(1);
963 if ( z < 2 ) nbcut = 2;
964 if ( threshold < avg ) sign = -1;
965
966 next = new Bimage(Float, TSimple, size(), n);
967
968 for ( nn=0; nn<n; nn++ ) {
969 jn = nn*imgsize;
970 lo2 = image[nn].origin();
971 i = index(lo2,nn);
972 lo = image[nn].origin() - 1;
973 lo = lo.max(0);
974 hi = image[nn].origin() + 1;
975 hi = hi.min(size()-1);
976 next->set(i, 2);
977 dvol = vol = 1;
978 if ( verbose ) {
979 cout << "Image " << nn+1 << ":" << endl;
980 cout << "Origin: " << lo2 << endl;
981 cout << "Iter\tVol\tdVol\tVol(A3)\tdVol(A3)" << endl;
982 }
983 iter = 0;
984 while ( dvol > 0 ) {
985 dvol = 0;
986 iter++;
987 for ( zz=lo[2]; zz<=hi[2]; zz++ ) {
988 lo2[2] = (zz)? zz-1: 0;
989 hi2[2] = (zz<z-1)? zz+1: zz;
990 for ( yy=lo[1]; yy<=hi[1]; yy++ ) {
991 lo2[1] = (yy)? yy-1: 0;
992 hi2[1] = (yy<y-1)? yy+1: yy;
993 for ( xx=lo[0]; xx<=hi[0]; xx++ ) {
994 lo2[0] = (xx)? xx-1: 0;
995 hi2[0] = (xx<x-1)? xx+1: xx;
996 i = index(0,xx,yy,zz,nn);
997 nb = 0;
998 if ( (*next)[i] < 1 && sign*(*this)[i] <= threshold ) {
999 jz = jn + lo2[2]*slicesize;
1000 for ( kz=lo2[2]; kz<=hi2[2]; kz++, jz += slicesize ) {
1001 jy = jz + lo2[1]*x;
1002 for ( ky=lo2[1]; ky<=hi2[1]; ky++, jy += x ) {
1003 j = jy + lo2[0];
1004 for ( kx=lo2[0]; kx<=hi2[0]; kx++, j++ ) {
1005 if ( i != j && (*next)[j] > 1 ) nb++;
1006 }
1007 }
1008 }
1009 if ( ( nb >= vol ) || ( nb > nbcut ) ) {
1010 next->set(i, 1);
1011 dvol++;
1012 } else next->set(i, 0);
1013 }
1014 }
1015 }
1016 }
1017 lo2 = lo;
1018 hi2 = hi;
1019 for ( zz=lo2[2]; zz<=hi2[2]; zz++ ) {
1020 for ( yy=lo2[1]; yy<=hi2[1]; yy++ ) {
1021 for ( xx=lo2[0]; xx<=hi2[0]; xx++ ) {
1022 i = index(0,xx,yy,zz,nn);
1023 if ( (*next)[i] == 1 ) {
1024 next->set(i, 2);
1025 if ( lo[0] == xx && xx > 0 ) lo[0]--;
1026 if ( lo[1] == yy && yy > 0 ) lo[1]--;
1027 if ( lo[2] == zz && zz > 0 ) lo[2]--;
1028 if ( hi[0] == xx && xx < x - 1 ) hi[0]++;
1029 if ( hi[1] == yy && yy < y - 1 ) hi[1]++;
1030 if ( hi[2] == zz && zz < z - 1 ) hi[2]++;
1031 }
1032 }
1033 }
1034 }
1035 vol += dvol;
1036 if ( verbose )
1037 cout << iter << tab << vol << tab << dvol << tab
1038 << vol*vs << tab << dvol*vs << endl;
1039 if ( mask_out_freq > 0 && iter%mask_out_freq == 0 ) {
1040 if ( n == 1 ) fn = Bstring(iter, "v%04ld.map");
1041 else fn = Bstring(nn, "v%02ld") + Bstring(iter, "_%04ld.bff");
1042 write(fn);
1043 }
1044 }
1045 }
1046
1047 return vol*vs;
1048 }
1049
1067 Bimage* Bimage::kmeans_segment(long nregion, double ratio)
1068 {
1069 random_seed();
1070
1071 long i, j, j4, h, k, m, mi(10);
1072 double v, dv, mdv, da(1e30);
1073 double r(1/std);
1074 Vector3<long> coor;
1075 Vector3<double> vec, start, end(size()-1);
1076
1077 long* nm = new long[nregion];
1078 double* a = new double[4*nregion]; // 3 values for coordinates and one for density
1079 double* an = new double[4*nregion];
1080
1081 Bimage* pseg = copy_header();
1082 pseg->data_type(Integer);
1083 pseg->data_alloc();
1084
1085 if ( verbose ) {
1086 cout << "Segmentation using K-means:" << endl;
1087 cout << "Number of regions: " << nregion << endl;
1088 cout << "Density:distance ratio: " << ratio << endl << endl;
1089 }
1090
1091 // Initial averages
1092 for ( j=j4=0; j<nregion; j++, j4+=4 ) {
1093 vec = vector3_random(start, end);
1094 for ( h=0; h<3; h++ ) a[j4+h] = vec[h];
1095 a[j4+3] = get(0, vec);
1096 if ( verbose )
1097 cout << j+1 << tab << vec << tab << a[j4+3] << endl;
1098 }
1099
1100 // Iterations
1101 cout << "#\tChange" << endl;
1102 for ( i=0; i<mi && da > 0.001; i++ ) {
1103 for ( j=0; j<nregion; j++ ) nm[j] = 0;
1104 for ( j=0; j<4*nregion; j++ ) an[j] = 0;
1105
1106 for ( k=0; k<datasize; k++ ) {
1107 v = (*this)[k];
1108 coor = coordinates(k);
1109 for ( j=j4=m=0, mdv=1e30; j<nregion; j++, j4+=4 ) {
1110 dv = r * fabs(a[j4+3] - v);
1111 for ( h=0; h<3; h++ ) dv += fabs(a[j4+h] - coor[h])/size()[h];
1112 if ( mdv > dv ) {
1113 mdv = dv;
1114 m = j;
1115 }
1116 }
1117 an[4*m+3] += v;
1118 for ( h=0; h<3; h++ ) an[4*m+h] += coor[h];
1119 nm[m]++;
1120 pseg->set(k, m);
1121 }
1122
1123 for ( j=j4=0, da=0; j<nregion; j++, j4+=4 ) {
1124 if ( nm[j] < 1 ) {
1125 vec = vector3_random(start, end);
1126 for ( h=0; h<3; h++ ) an[j4+h] = vec[h];
1127 an[j4+3] = get(0, vec);
1128 }
1129 if ( verbose )
1130 cout << j+1 << tab << nm[j];
1131 for ( h=0; h<4; h++ ) {
1132 if ( nm[j] ) an[j4+h] /= nm[j];
1133 da += fabs(a[j4+h] - an[j4+h]);
1134 a[j4+h] = an[j4+h];
1135 if ( verbose )
1136 cout << tab << a[j4+h];
1137 }
1138 if ( verbose )
1139 cout << endl;
1140 }
1141 da /= 4*nregion;
1142 if ( verbose )
1143 cout << i+1 << tab << da << endl;
1144 }
1145
1146 delete[] nm;
1147 delete[] a;
1148 delete[] an;
1149
1150 return pseg;
1151 }
1152
1153 /*
1154 Functions for graph segmentation
1155 */
1156 int QsortSmallToLargeEdge(const void *x, const void *y)
1157 {
1158 GSedge* r1 = (GSedge*) x;
1159 GSedge* r2 = (GSedge*) y;
1160 if( r1->w < r2->w ) return -1;
1161 else return 1;
1162 }
1163
1164 long region_find(GSregion* region, long i)
1165 {
1166 long j(i);
1167 while ( j != region[j].p ) j = region[j].p;
1168 region[i].p = j;
1169 return j;
1170 }
1171
1172 int region_join(GSregion* region, long i, long j)
1173 {
1174 if ( i == j ) return 0;
1175
1176 int s(region[i].s + region[j].s);
1177 double a((region[i].s*region[i].a + region[j].s*region[j].a)/s);
1178
1179 if ( region[i].r > region[j].r ) {
1180 region[j].p = i;
1181 region[i].s += region[j].s;
1182 region[i].a = a;
1183 } else {
1184 region[i].p = j;
1185 region[j].s += region[i].s;
1186 region[j].a = a;
1187 if ( region[i].r == region[j].r ) region[j].r++;
1188 }
1189
1190 return 1;
1191 }
1192
1193 /*
1194 Sets up every voxel as a region with the voxel value.
1195 */
1196 GSregion* region_setup(Bimage* p, Bimage* pmask)
1197 {
1198 long i, imagesize(p->image_size());
1199
1200 GSregion* region = new GSregion[imagesize];
1201
1202 if ( pmask ) pmask->to_mask();
1203
1204 for ( i=0; i<imagesize; i++ ) {
1205 region[i].p = i;
1206 region[i].r = 0;
1207 region[i].s = 1;
1208 if ( !pmask || ( pmask && (*pmask)[i] ) ) {
1209 if ( p->compound_type() == TSimple )
1210 region[i].a = (*p)[i];
1211 else if ( p->compound_type() == TRGB )
1212 region[i].a = p->rgb(i).average();
1213 }
1214 else region[i].a = 0;
1215 }
1216
1217 return region;
1218 }
1219
1220 /*
1221 Sets up each forward edge
1222 */
1223 GSedge* edge_setup(Bimage* p, Bimage* pmask, int connect_type, long& me, long& ne)
1224 {
1225 long x(p->sizeX()), y(p->sizeY()), z(p->sizeZ());
1226 long i, xx, yy, zz, x1, y1, z1;
1227 long imagesize(p->image_size());
1228 long dim = (z > 1)? 3: 2;
1229 long nn(imagesize);
1230
1231 if ( pmask ) {
1232 pmask->to_mask();
1233 for ( nn=i=0; i<imagesize; i++ ) if ( (*pmask)[i] ) nn++;
1234 }
1235
1236 if ( connect_type < 1 ) me = dim*nn;
1237 else me = (z > 1)? 13*nn: 4*nn;
1238
1239 GSedge* edge = new GSedge[me];
1240
1241 for ( ne=i=zz=0; zz<z; zz++ ) {
1242 for ( yy=0; yy<y; yy++ ) {
1243 for ( xx=0; xx<x; xx++, i++ ) if ( !pmask || ( pmask && (*pmask)[i] ) ) {
1244 if ( xx < x - 1 ) {
1245 x1 = xx + 1;
1246 if ( connect_type ) {
1247 for ( z1=(zz>0)?zz-1:zz; z1<zz+1 && z1<z; z1++ ) {
1248 for ( y1=(yy>0)?yy-1:yy; y1<yy+1 && y1<y; y1++ ) {
1249 edge[ne].u = i;
1250 edge[ne++].v = (z1*y + y1)*x + x1;
1251 }
1252 }
1253 } else {
1254 edge[ne].u = i;
1255 edge[ne++].v = (zz*y + yy)*x + x1;
1256 }
1257 }
1258 if ( yy < y - 1 ) {
1259 y1 = yy + 1;
1260 if ( connect_type ) {
1261 for ( z1=(zz>0)?zz-1:zz; z1<zz+1 && z1<z; z1++ ) {
1262 edge[ne].u = i;
1263 edge[ne++].v = (z1*y + y1)*x + xx;
1264 }
1265 } else {
1266 edge[ne].u = i;
1267 edge[ne++].v = (zz*y + y1)*x + xx;
1268 }
1269 }
1270 if ( zz < z - 1 ) {
1271 z1 = zz + 1;
1272 edge[ne].u = i;
1273 edge[ne++].v = (z1*y + yy)*x + xx;
1274 }
1275 }
1276 }
1277 }
1278
1279 if ( p->compound_type() == TSimple )
1280 for ( i=0; i<ne; i++ ) edge[i].w = fabs((*p)[edge[i].u] - (*p)[edge[i].v]);
1281 else if ( p->compound_type() == TRGB )
1282 // for ( i=0; i<ne; i++ ) edge[i].w = fabs((p->rgb(edge[i].u) - p->rgb(edge[i].v)).average());
1283 for ( i=0; i<ne; i++ ) edge[i].w = fabs((p->rgb(edge[i].u) - p->rgb(edge[i].v)).rms());
1284
1285 return edge;
1286 }
1287
1288 /*
1289 The starting threshold is taken to be the standard deviation divided by the complexity value
1290 */
1291 long region_merging(GSregion* region, GSedge* edge, long nrc, long ne, float threshold)
1292 {
1293 long i, u, v;
1294 GSedge e;
1295 for ( i=0; i<ne; i++ ) {
1296 e = edge[i];
1297 u = region_find(region, e.u);
1298 v = region_find(region, e.v);
1299 if ( u != v ) {
1300 if ( e.w <= region[u].a && e.w <= region[v].a ) {
1301 nrc -= region_join(region, u, v);
1302 u = region_find(region, u);
1303 region[u].a = e.w + threshold/region[u].s;
1304 }
1305 }
1306 }
1307
1308 return nrc;
1309 }
1310
1311 /*
1312 fac = g*g/Q, g is taken to be the standard deviation and Q a complexity value
1313 */
1314 long statistical_region_merging(GSregion* region, GSedge* edge, long nr, long ne, double fac)
1315 {
1316 // Find segment memberships
1317 double d2, ln1, ln2, s1, s2;
1318 double lnd(2*log(6*nr));
1319 long i, u, v, nrc(nr);
1320 GSedge e;
1321
1322 for ( i=0; i<ne; i++ ) {
1323 e = edge[i];
1324 u = region_find(region, e.u);
1325 v = region_find(region, e.v);
1326 if ( u != v ) {
1327 d2 = region[u].a - region[v].a; d2 *= d2;
1328 s1 = region[u].s; s2 = region[v].s;
1329 // ln1 = lnd + log(1.0 + s1) * ((g < s1)? g: s1);
1330 // ln2 = lnd + log(1.0 + s2) * ((g < s2)? g: s2);
1331 ln1 = lnd + log(1.0 + s1);
1332 ln2 = lnd + log(1.0 + s2);
1333 if ( d2 < fac * (ln1/s1 + ln2/s2) )
1334 nrc -= region_join(region, u, v);
1335 }
1336 }
1337
1338 return nrc;
1339 }
1340
1341 long region_merge_small(GSregion* region, GSedge* edge, long nrc, long ne, int min_size)
1342 {
1343 if ( min_size < 1 ) return nrc;
1344
1345 // Merge small regions
1346 long i, u, v;
1347 GSedge e;
1348
1349 for ( i=0; i<ne; i++ ) {
1350 e = edge[i];
1351 u = region_find(region, e.u);
1352 v = region_find(region, e.v);
1353 if ( ( u != v ) && ( region[u].s < min_size || region[v].s < min_size ) ) {
1354 nrc -= region_join(region, u, v);
1355 }
1356 }
1357
1358 return nrc;
1359 }
1360
1383 Bimage* Bimage::graph_segment(int type, Bimage* pmask, int connect_type,
1384 double complexity, long min_size, int return_type)
1385 {
1386 // color_to_simple();
1387 // change_type(Float);
1388
1389 long i, j, ne;
1390 long slicesize(x*y);
1391 long imagesize(slicesize*z);
1392 long dim = (z > 1)? 3: 2;
1393 long max_edges;
1394 double threshold(std/complexity);
1395
1396 if ( pmask ) pmask->to_mask();
1397
1398 if ( verbose ) {
1399 cout << "Segmenting image:" << endl;
1400 cout << "Algorithm: ";
1401 if ( type == 1 ) {
1402 cout << "Simple" << endl;
1403 cout << "Threshold: " << threshold << endl;
1404 } else {
1405 cout << "Statistical region merging" << endl;
1406 cout << "Complexity: " << complexity << endl;
1407 }
1408 cout << "Connectivity: ";
1409 if ( connect_type < 1 ) cout << 2*dim << endl;
1410 else if ( dim < 3 ) cout << 8 << endl;
1411 else cout << 26 << endl;
1412 cout << "Minimum size: " << min_size << endl;
1413 }
1414
1415 GSregion* region = region_setup(this, pmask);
1416
1417 GSedge* edge = edge_setup(this, pmask, connect_type, max_edges, ne);
1418
1419 qsort((void *) edge, ne, sizeof(GSedge),
1420 (int (*)(const void *, const void *)) QsortSmallToLargeEdge);
1421
1422 if ( verbose )
1423 cout << "Number of edges: " << ne << endl;
1424
1425 long nr(imagesize), nrc(imagesize);
1426
1427 // Find segment memberships
1428 if ( type == 1 ) {
1429 for ( i=0; i<imagesize; i++ ) region[i].a = threshold;
1430 nrc = region_merging(region, edge, nr, ne, threshold);
1431 } else {
1432 nrc = statistical_region_merging(region, edge, imagesize, ne, threshold*threshold);
1433 }
1434
1435 // Merge small regions
1436 if ( min_size > 0 ) {
1437 if ( verbose )
1438 cout << "Regions before merging: " << nrc << endl;
1439 nrc = region_merge_small(region, edge, nrc, ne, min_size);
1440 }
1441
1442 delete[] edge;
1443
1444 if ( verbose )
1445 cout << "Number of regions: " << nrc << endl << endl;
1446
1447 Bimage* pseg = NULL;
1448
1449 if ( return_type < 1 ) {
1450 pseg = new Bimage(Integer, TSimple, size(), 1);
1451
1452 for ( nrc=i=0; i<imagesize; i++ )
1453 if ( region[i].p == i ) region[i].r = ++nrc;
1454
1455 for ( i=0; i<imagesize; i++ ) {
1456 j = region_find(region, i);
1457 pseg->set(i, region[j].r);
1458 }
1459 } else {
1460 pseg = new Bimage(Float, TSimple, size(), 1);
1461
1462 for ( i=0; i<imagesize; i++ )
1463 region[i].a = region[i].s = 0;
1464
1465 for ( i=0; i<imagesize; i++ ) {
1466 j = region_find(region, i);
1467 region[j].a += (*this)[i];
1468 region[j].s += 1;
1469 }
1470
1471 for ( i=0; i<imagesize; i++ )
1472 if ( region[j].s ) region[i].a /= region[i].s;
1473
1474 for ( i=0; i<imagesize; i++ ) {
1475 j = region_find(region, i);
1476 pseg->set(i, region[j].a);
1477 }
1478 }
1479
1480 delete[] region;
1481
1482 pseg->sampling(sampling());
1483 pseg->origin(image->origin());
1484 pseg->statistics();
1485
1486 return pseg;
1487 }
1488
1489 /*
1490 For a pixel i:
1491 calculate kernel extents, size=k
1492 calculate superpixel centers, O(k): (4+c)*add
1493 calculate superpixel weights, O(k): (c-1)*add + (c+1)*mul
1494 */
1495 int img_update_segment(long i, Bimage* p, Bimage* pmask, vector<long> vstep,
1496 double colorweight, vector<Bsuperpixel>& seg)
1497 {
1498 long j, xx, yy, zz;
1499 double d, icw(1/colorweight);
1500 double m(p->standard_deviation()*p->standard_deviation()/colorweight);
1501 vector<double> dvec = seg[i].coordinates();
1502 vector<long> vec(dvec.begin(), dvec.end());
1503
1504 vector<long> kmin = vec - vstep;
1505 kmin = vecmax(kmin, 0);
1506 // kmin = vecmin(kmin, p->size());
1507 if ( kmin[0] > p->sizeX() ) kmin[0] = p->sizeX();
1508 if ( kmin[1] > p->sizeY() ) kmin[1] = p->sizeY();
1509 if ( kmin[2] > p->sizeZ() ) kmin[2] = p->sizeZ();
1510
1511 vector<long> kmax = vec + vstep;
1512 // kmax = vecmin(kmax, p->size());
1513 if ( kmax[0] > p->sizeX() ) kmax[0] = p->sizeX();
1514 if ( kmax[1] > p->sizeY() ) kmax[1] = p->sizeY();
1515 if ( kmax[2] > p->sizeZ() ) kmax[2] = p->sizeZ();
1516
1517 seg[i].clear();
1518 seg[i].weight(m);
1519
1520 for ( zz=kmin[2]; zz<kmax[2]; zz++ ) {
1521 for ( yy=kmin[1]; yy<kmax[1]; yy++ ) {
1522 for ( xx=kmin[0]; xx<kmax[0]; xx++ ) {
1523 j = p->index(xx, yy, zz);
1524 if ( i == (*pmask)[j]) {
1525 seg[i].add(xx, yy, zz, p->values(j));
1526 }
1527 }
1528 }
1529 }
1530
1531 seg[i].average();
1532
1533 for ( zz=kmin[2]; zz<kmax[2]; zz++ ) {
1534 for ( yy=kmin[1]; yy<kmax[1]; yy++ ) {
1535 for ( xx=kmin[0]; xx<kmax[0]; xx++ ) {
1536 j = p->index(xx, yy, zz);
1537 if ( i == (*pmask)[j]) {
1538 d = seg[i].difference2(p->values(j));
1539 d *= icw;
1540 if ( seg[i].weight() < d ) seg[i].weight(d);
1541 }
1542 }
1543 }
1544 }
1545
1546 return 0;
1547 }
1548
1549 int Bimage::superpixels_update(Bimage* pmask, vector<long> vstep,
1550 double colorweight, vector<Bsuperpixel>& seg)
1551 {
1552 long nseg(seg.size());
1553
1554 #ifdef HAVE_GCD
1555 dispatch_apply(nseg, dispatch_get_global_queue(0, 0), ^(size_t i){
1556 img_update_segment(i, this, pmask, vstep, colorweight, seg);
1557 });
1558 #else
1559 #pragma omp parallel for
1560 for ( long i=0; i<nseg; i++ )
1561 img_update_segment(i, this, pmask, vstep, colorweight, seg);
1562 #endif
1563
1564 return 0;
1565 }
1566
1567 /*
1568 For a pixel i:
1569 For each neighboring superpixel center m:
1570 fom = wd * distance^2 + color_difference^2 / superpixel_weight
1571 set the mask to the minimum fom
1572 O(NNEIGHBOR)
1573 (6+c)*add + (7+c)*mul + 1*div
1574 */
1575 int img_assign_pixel(long i, Bimage* p, Bimage* pmask, double wd,
1576 vector<Bsuperpixel>& seg)
1577 {
1578 long j((*pmask)[i]), k, m;
1579 double dd, dc, d, fom(1e30);
1580 Vector3<long> coor3 = p->coordinates(i*p->channels());
1581 // vector<double> coor = {double(coor3[0]), double(coor3[1]), double(coor3[2])};
1582 vector<double> scoor;
1583
1584 vector<double> val = p->values(i);
1585
1586 // cout << i << endl;
1587
1588 for ( k=-1, m=j; k<NNEIGHBOR; ) {
1589 scoor = seg[m].coordinates() - coor3;
1590 dd = length2(scoor);
1591 dc = seg[m].difference2(val);
1592 d = dd*wd + dc/seg[m].weight();
1593 if ( fom >= d ) {
1594 fom = d;
1595 pmask->set(i, m);
1596 }
1597 if ( ++k == NNEIGHBOR || ( m = seg[j].neighbor(k) ) < 0 ) break;
1598 }
1599
1600 return 0;
1601 }
1602
1603 int img_assign_segments(Bimage* p, Bimage* pmask, vector<long> vstep,
1604 vector<Bsuperpixel>& seg)
1605 {
1606 long i, nc(0);
1607 double dr(volume(vstep)), wd(1.0L/dr);
1608
1609 Bimage* pmc = pmask->copy();
1610
1611 #ifdef HAVE_GCD
1612 dispatch_apply(p->image_size(), dispatch_get_global_queue(0, 0), ^(size_t i){
1613 img_assign_pixel(i, p, pmask, wd, seg);
1614 });
1615 #else
1616 #pragma omp parallel for
1617 for ( i=0; i<p->image_size(); i++ )
1618 img_assign_pixel(i, p, pmask, wd, seg);
1619 #endif
1620
1621 for ( i=0; i<pmask->image_size(); i++ ) if ( (*pmask)[i] - (*pmc)[i] ) nc++;
1622
1623 delete pmc;
1624
1625 return nc;
1626 }
1627
1628 int img_impose_segments(Bimage* p, Bimage* pmask, vector<Bsuperpixel>& seg)
1629 {
1630 long i, j, cc;
1631
1632 for ( i=j=0; i<p->image_size(); i++ )
1633 for ( cc=0; cc<p->channels(); cc++, j++ )
1634 p->set(j, seg[(long)(*pmask)[i]].channel(cc));
1635
1636 return 0;
1637 }
1638
1639 long segment_lowest_neighbor(vector<Bsuperpixel>& seg, long i, long cc)
1640 {
1641 long j, k, ln(i);
1642 double min(seg[i].channel(cc));
1643 for ( j=0; j<NNEIGHBOR && ( k = seg[i].neighbor(j) ) >= 0; ++j ) {
1644 if ( seg[k].channel(cc) < min ) {
1645 min = seg[k].channel(cc);
1646 ln = k;
1647 }
1648 }
1649 return ln;
1650 }
1651
1652 int img_impose_lowest_neighbor(Bimage* p, Bimage* pmask, vector<Bsuperpixel>& seg)
1653 {
1654 long i, j, is, cc;
1655
1656 for ( i=j=0; i<p->image_size(); i++ )
1657 for ( cc=0; cc<p->channels(); cc++, j++ ) {
1658 is = segment_lowest_neighbor(seg, (*pmask)[i], cc);
1659 p->set(j, seg[is].channel(cc));
1660 }
1661
1662 return 0;
1663 }
1664
1665 long segment_highest_neighbor(vector<Bsuperpixel>& seg, long i, long cc)
1666 {
1667 long j, k, ln(i);
1668 double max(seg[i].channel(cc));
1669 for ( j=0; j<NNEIGHBOR && ( k = seg[i].neighbor(j) ) >= 0; ++j ) {
1670 if ( seg[k].channel(cc) > max ) {
1671 max = seg[k].channel(cc);
1672 ln = k;
1673 }
1674 }
1675 return ln;
1676 }
1677
1678 int img_impose_highest_neighbor(Bimage* p, Bimage* pmask, vector<Bsuperpixel>& seg)
1679 {
1680 long i, j, is, cc;
1681
1682 for ( i=j=0; i<p->image_size(); i++ )
1683 for ( cc=0; cc<p->channels(); cc++, j++ ) {
1684 is = segment_highest_neighbor(seg, (*pmask)[i], cc);
1685 p->set(j, seg[is].channel(cc));
1686 }
1687
1688 return 0;
1689 }
1690
1691 int img_impose_difference_from_highest_neighbor(Bimage* p, Bimage* pmask, vector<Bsuperpixel>& seg)
1692 {
1693 long i, j, is, cc;
1694 double v;
1695
1696 for ( i=j=0; i<p->image_size(); i++ )
1697 for ( cc=0; cc<p->channels(); cc++, j++ ) {
1698 is = segment_highest_neighbor(seg, (*pmask)[i], cc);
1699 v = seg[(long)(*pmask)[i]].channel(cc);
1700 p->set(j, seg[is].channel(cc) - v);
1701 }
1702
1703 return 0;
1704 }
1705
1706 long segment_setup_neighbors(long i, vector<Bsuperpixel>& seg, double dmax)
1707 {
1708 long nseg(seg.size());
1709 long j, nn(0);
1710 double d;
1711
1712 for ( j=0; j<nseg; j++ ) if ( j != i ) {
1713 d = distance(seg[i].coordinates(), seg[j].coordinates());
1714 if ( d < dmax ) {
1715 seg[i].add_neighbor(j);
1716 nn++;
1717 }
1718 }
1719
1720 return nn;
1721 }
1722
1723 long segments_setup_neighbors(vector<Bsuperpixel>& seg, long step)
1724 {
1725 long nseg(seg.size());
1726 long i, j, nn(0);
1727 double dmax(1.9*step);
1728
1729 for ( i=0; i<nseg; i++ ) seg[i].clear_neighbors();
1730
1731 #ifdef HAVE_GCD
1732 dispatch_apply(nseg, dispatch_get_global_queue(0, 0), ^(size_t i){
1733 segment_setup_neighbors(i, seg, dmax);
1734 });
1735 #else
1736 #pragma omp parallel for
1737 for ( i=0; i<nseg; i++ )
1738 segment_setup_neighbors(i, seg, dmax);
1739 #endif
1740
1741 for ( i=0; i<nseg; i++ )
1742 for ( j=0; j<NNEIGHBOR && seg[i].neighbor(j) >= 0; ++j ) nn++;
1743
1744 if ( verbose & VERB_FULL ) {
1745 for ( i=0; i<nseg; i++ ) {
1746 cout << seg[i].index() << tab << seg[i].coordinates();
1747 for ( j=0; j<NNEIGHBOR && seg[i].neighbor(j) >= 0; ++j ) cout << tab << seg[i].neighbor(j);
1748 cout << endl;
1749 }
1750 }
1751
1752 return nn;
1753 }
1754
1761 vector<Bsuperpixel> Bimage::superpixels_from_mask(long cc, long step)
1762 {
1763 long nseg = (long) (max + 1.9);
1764
1765 if ( verbose )
1766 cout << "Setting up " << nseg << " segments" << endl;
1767
1768 vector<Bsuperpixel> seg(nseg);
1769
1770 long i, j, nn(0);
1771 Vector3<long> coor3;
1772 vector<double> v;
1773
1774 for ( i=0; i<nseg; i++ ) {
1775 seg[i].index(i);
1776 seg[i].channels(cc);
1777 }
1778
1779 for ( i=0; i<image_size(); i++ ) {
1780 j = (*this)[i];
1781 coor3 = coordinates(i);
1782 seg[j].add(coor3[0], coor3[1], coor3[2], v);
1783 }
1784
1785 for ( i=0; i<nseg; i++ )
1786 seg[i].average();
1787
1788 nn = segments_setup_neighbors(seg, step);
1789
1790 if ( verbose )
1791 cout << "Total neigbors: " << nn << endl << endl;
1792
1793 return seg;
1794 }
1795
1812 vector<Bsuperpixel> Bimage::superpixels(long step, double colorweight, long iterations, double stop)
1813 {
1814 Bimage* pmask = tile_mask(step);
1815
1816 long i, nc(image_size()), ncp(0), nstop(image_size()*stop/100);
1817
1818 if ( verbose ) {
1819 cout << "SLIC superpixel segmentation:" << endl;
1820 cout << "Step size: " << step << endl;
1821 cout << "Color weight: " << colorweight << endl;
1822 cout << "Maximum number of iterations: " << iterations << endl;
1823 cout << "Stopping condition: " << stop << " % (" << nstop << ")" << endl << endl;
1824 }
1825
1826 vector<Bsuperpixel> seg = pmask->superpixels_from_mask(c, step);
1827
1828 vector<long> vstep = {step,step,step};
1829 vstep *= 2;
1830 // vstep = vstep.min(size());
1831 if ( vstep[2] > z ) vstep[2] = z;
1832
1833 superpixels_update(pmask, vstep, colorweight, seg);
1834
1835 // write_img("t.tif", pmask);
1836
1837 time_t t = time(NULL);
1838
1839 if ( verbose )
1840 cout << "Iter\tChange\t∆\tTime" << endl;
1841
1842 for ( i=0; i<iterations && nc > nstop; i++ ) {
1843 nc = img_assign_segments(this, pmask, vstep, seg); // Slow step
1844 if ( verbose )
1845 cout << i+1 << tab << nc << tab << nc-ncp << tab << (long)(time(NULL) - t) << endl;
1846 // write_img("t.tif", pmask);
1847 ncp = nc;
1848 superpixels_update(pmask, vstep, colorweight, seg);
1849 segments_setup_neighbors(seg, step);
1850 }
1851
1852 next = pmask;
1853
1854 return seg;
1855 }
1856
1872 int Bimage::impose_superpixels(Bimage* pmask, vector<Bsuperpixel>& seg, int impose)
1873 {
1874 if ( impose < 1 ) return 0;
1875 if ( !pmask ) {
1876 cerr << "Error in impose_superpixels: No multi-level mask!" << endl;
1877 return -1;
1878 }
1879
1880 long i, j, cc, is, isn;
1881 double v;
1882
1883 pmask->information();
1884
1885 if ( verbose )
1886 cout << "Imposing segments using feature type " << impose << endl;
1887
1888 for ( i=j=0; i<image_size(); i++ ) {
1889 for ( cc=0; cc<channels(); cc++, j++ ) {
1890 is = isn = (long)(*pmask)[i];
1891 if ( impose == 2 || impose == 3 ) {
1892 isn = segment_lowest_neighbor(seg, is, cc);
1893 } else if ( impose == 4 || impose == 5 ) {
1894 isn = segment_highest_neighbor(seg, is, cc);
1895 }
1896 if ( impose == 3 || impose == 5 ) {
1897 v = seg[isn].channel(cc) - seg[is].channel(cc);
1898 } else {
1899 v = seg[isn].channel(cc);
1900 }
1901 set(j, v);
1902 }
1903 }
1904
1905 return 0;
1906 }
1907
1908
1915 /*Bimage* Bimage::region_color_by_size(Bimage* pmask)
1916 {
1917 Bimage* pcol = new Bimage(UCharacter, TRGB, size(), n);
1918 pcol->sampling(sampling());
1919 pcol->origin(image->origin());
1920 RGB<unsigned char>* color = (RGB<unsigned char> *) pcol->data_pointer();
1921
1922 if ( verbose )
1923 cout << "Coloring regions by size" << endl;
1924
1925 long i, j, nseg((long)(pmask->maximum() + 1.9));
1926 long vmin(datasize), vmax(0);
1927 double vavg(0), vstd(0);
1928 RGB<unsigned char> black(0,0,0);
1929 int* vol = new int[nseg];
1930
1931 for ( i=0; i<nseg; i++ ) vol[i] = 0;
1932
1933 for ( i=0; i<datasize; i++ )
1934 if ( (*pmask)[i] > -1 ) vol[(long)(*pmask)[i]]++;
1935
1936 for ( i=1; i<nseg; i++ ) {
1937 if ( vmin > vol[i] ) vmin = vol[i];
1938 if ( vmax < vol[i] ) vmax = vol[i];
1939 vavg += vol[i];
1940 vstd += vol[i] * vol[i];
1941 }
1942 vavg /= nseg - 1;
1943 vstd /= nseg - 1;
1944 vstd -= vavg * vavg;
1945 vstd = sqrt(vstd);
1946 if ( vmin < vavg - 3*vstd ) vmin = vavg - 3*vstd;
1947 if ( vmax > vavg + 3*vstd ) vmax = vavg + 3*vstd;
1948
1949 if ( verbose )
1950 cout << "Coloring range: " << vmin << " - " << vmax << endl;
1951
1952 for ( i=0; i<datasize; i++ ) {
1953 j = (*pmask)[i];
1954 if ( j > 0 )
1955 color[i].spectrum(vol[j], vmin, vmax);
1956 else
1957 color[i] = black;
1958 }
1959
1960 delete[] vol;
1961
1962 return pcol;
1963 }
1964 */
1965
Bimage::change_type
void change_type(char letter)
Get the data type indicated by a single letter code.
Definition: Bimage.cpp:1743
distance
double distance(vector< T1 > &v1, vector< T2 > &v2)
Definition: Vector3.h:536
VERB_STATS
#define VERB_STATS
Definition: utilities.h:108
Bimage::kernel_max_neigbor
long kernel_max_neigbor(long idx, long ksize)
Finds the highest value in a kernel excluding the central voxel.
Definition: Bimage.cpp:2929
Bimage::copy_header
Bimage * copy_header()
Definition: Bimage.h:650
vector3_random
Vector3< double > vector3_random(const double min, const double max)
Generates a random vector within a defined cube.
Definition: random_numbers.cpp:440
Bimage::kernel_high
Vector3< long > kernel_high(long i, long k=1)
Definition: Bimage.h:463
Bimage.h
Header file for image class.
random_seed
long random_seed()
Gets a random seed and sets the flag.
Definition: random_numbers.cpp:41
region_find
long region_find(GSregion *region, long i)
Definition: Bimage_segment.cpp:1164
Bimage::sampling
Vector3< double > sampling()
Definition: Bimage.h:505
Bimage::information
int information()
Prints out header information for an image.
Definition: Bimage.cpp:2489
Bimage::file_name
string & file_name()
Definition: Bimage.h:231
GSedge::u
long u
Definition: Bimage_segment.cpp:22
Bimage::image_size
long image_size()
Definition: Bimage.h:267
Bimage::regions
Bimage * regions(double threshold, int sign)
Segments an image into contiguous regions.
Definition: Bimage_segment.cpp:58
utilities.h
Header file for general utilities.
img_impose_difference_from_highest_neighbor
int img_impose_difference_from_highest_neighbor(Bimage *p, Bimage *pmask, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1691
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:112
statistical_region_merging
long statistical_region_merging(GSregion *region, GSedge *edge, long nr, long ne, double fac)
Definition: Bimage_segment.cpp:1314
GSregion::r
int r
Definition: Bimage_segment.cpp:31
Bimage::compound_type
CompoundType compound_type()
Definition: Bimage.h:351
Bimage::region_assign
long region_assign(Bimage *pmask, long idx, long region_number, double threshold, int sign)
Finds all the pixels that are part of the same region.
Definition: Bimage_segment.cpp:121
Bimage::impose_superpixels
int impose_superpixels(Bimage *pmask, vector< Bsuperpixel > &seg, int impose)
Impose superpixel features onto an image.
Definition: Bimage_segment.cpp:1872
GSregion::s
int s
Definition: Bimage_segment.cpp:32
Integer
Definition: utilities.h:154
Bimage::edge
int edge(int type, Vector3< long > rect, Vector3< double > start, double width, int fill_type=0, double fill=0)
Smooths the image edge with a soft rectangular function.
Definition: Bimage_edit.cpp:319
segments_setup_neighbors
long segments_setup_neighbors(vector< Bsuperpixel > &seg, long step)
Definition: Bimage_segment.cpp:1723
Bimage::index
long index(long nx, long ny) const
Definition: Bimage.h:383
region_setup
GSregion * region_setup(Bimage *p, Bimage *pmask)
Definition: Bimage_segment.cpp:1196
length2
double length2(vector< T > v)
Definition: Vector3.h:517
VERB_PROCESS
#define VERB_PROCESS
Definition: utilities.h:107
region_merge_small
long region_merge_small(GSregion *region, GSedge *edge, long nrc, long ne, int min_size)
Definition: Bimage_segment.cpp:1341
Bimage::truncate_to_min_max
int truncate_to_min_max(double minim, double maxim)
Truncates image data to a given minimum and maximum.
Definition: Bimage_rescale.cpp:331
Bimage::file_name
void file_name(string s)
Definition: Bimage.h:230
Bimage::superpixels_update
int superpixels_update(Bimage *pmask, vector< long > vstep, double colorweight, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1549
Bimage::blobs
long blobs(double threshold, double min_size, double max_size, double setvalue, int sign)
Identifies contiguous regions above a given threshold (blobs) and eliminate those less than a minimum...
Definition: Bimage_segment.cpp:551
Bimage::Bimage
Bimage()
Initializes an image.
Definition: Bimage.cpp:44
TSimple
Definition: Bimage.h:58
Float
Definition: utilities.h:157
Vector3::max
Type max()
Definition: Vector3.h:175
Bimage::region_threshold_series
int region_threshold_series(double threshold_first, double threshold_last, double threshold_step)
Segments a map through a series of thresholds and reports results.
Definition: Bimage_segment.cpp:202
Bimage
General image parameter class.
Definition: Bimage.h:163
Bimage::kernel_low
Vector3< long > kernel_low(long i, long k=1)
Definition: Bimage.h:457
Bimage::levelmask_average_region_size
double levelmask_average_region_size()
Calculates the average size of regions in a level mask.
Definition: Bimage_mask.cpp:1809
Bimage::data_alloc
unsigned char * data_alloc()
Definition: Bimage.h:256
GSedge::w
float w
Definition: Bimage_segment.cpp:23
linked_list.h
Header file for generalized linked list functions.
Bimage::region_flood
long region_flood(Bimage *pmask, double threshold_hi, double threshold_lo, double threshold_step, int fill_borders)
Creates and expands a region map from a starting to ending threshold value.
Definition: Bimage_segment.cpp:257
Bimage::maximum
double maximum()
Definition: Bimage.h:535
Bimage::statistics
long statistics()
Calculates the statistics for an image.
Definition: Bimage_stats.cpp:22
Bimage::mass_threshold
double mass_threshold(long img_num, double mol_weight, double rho)
Finds the density threshold associated with a particular molecular weight.
Definition: Bimage_segment.cpp:834
img_impose_lowest_neighbor
int img_impose_lowest_neighbor(Bimage *p, Bimage *pmask, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1652
Bimage::mass_at_threshold
double mass_at_threshold(long img_num, double threshold, double rho)
Calculates the mass from the density threshold.
Definition: Bimage_segment.cpp:918
GSedge::v
long v
Definition: Bimage_segment.cpp:22
Bimage::size
Vector3< long > size() const
Definition: Bimage.h:373
Bimage::internal_volume
double internal_volume(double threshold, int mask_out_freq)
Calculates the internal volume of a shell.
Definition: Bimage_segment.cpp:950
GSedge
Graph segmentation edge structure.
Definition: Bimage_segment.cpp:21
Bsub_image::origin
void origin(double x, double y, double z)
Definition: Bimage.h:127
Bimage::channels
long channels()
Definition: Bimage.h:371
Bimage::rgb
RGB< double > rgb(long j)
Returns a color value at the given index.
Definition: Bimage.cpp:1033
Bimage::voxel_size
double voxel_size()
Definition: Bimage.h:510
Bimage::get
double get(long nn, long xx, long yy, long zz, long cc=0)
Returns the data value at the given coordinates.
Definition: Bimage.cpp:937
Bimage::standard_deviation
double standard_deviation()
Definition: Bimage.h:537
img_assign_segments
int img_assign_segments(Bimage *p, Bimage *pmask, vector< long > vstep, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1603
Bimage::average
double average()
Definition: Bimage.h:536
Bimage::superpixels_from_mask
vector< Bsuperpixel > superpixels_from_mask(long cc, long step)
Create superpixels from a multilevel mask.
Definition: Bimage_segment.cpp:1761
Bimage::set
void set(long j, double v)
Sets a single value at the given index.
Definition: Bimage.cpp:1096
TRGB
Definition: Bimage.h:62
Bimage::next
Bimage * next
Definition: Bimage.h:165
Bimage::to_mask
long to_mask()
Definition: Bimage.h:1299
segment_lowest_neighbor
long segment_lowest_neighbor(vector< Bsuperpixel > &seg, long i, long cc)
Definition: Bimage_segment.cpp:1639
Bimage::check_neighbors
long check_neighbors(long idx)
Check neighbors in region map and assign a value if a neighbor is assigned.
Definition: Bimage_segment.cpp:419
Bimage::filter_extremes
int filter_extremes()
Filters the extremes out of a micrograph image.
Definition: Bimage_segment.cpp:634
img_impose_segments
int img_impose_segments(Bimage *p, Bimage *pmask, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1628
Bimage::kernel_max_wrap
long kernel_max_wrap(long idx, long ksize)
Finds the highest value in a kernel with wrapping.
Definition: Bimage.cpp:2963
volume
T volume(vector< T > v)
Definition: Vector3.h:545
Bstring
Definition: Bstring.h:29
Bimage::kmeans_segment
Bimage * kmeans_segment(long nregion=2, double ratio=1)
Segments an image based on K-means.
Definition: Bimage_segment.cpp:1067
Bimage::copy
Bimage * copy()
Copies the header information and data of an image into a new image structure.
Definition: Bimage.cpp:2695
region_merging
long region_merging(GSregion *region, GSedge *edge, long nrc, long ne, float threshold)
Definition: Bimage_segment.cpp:1291
Bimage::sizeX
void sizeX(long nx)
Definition: Bimage.h:377
kmin
long kmin(long i, long hk)
Definition: Bimage_filter.cpp:17
Bimage::values
vector< double > values(long i)
Definition: Bimage.h:284
GSregion::a
float a
Definition: Bimage_segment.cpp:33
kmax
long kmax(long i, long km, long m)
Definition: Bimage_filter.cpp:22
Bimage::sizeZ
void sizeZ(long nz)
Definition: Bimage.h:379
Bimage::write
int write(Bstring &fn)
Definition: Bimage.cpp:2320
Vector3< long >
edge_setup
GSedge * edge_setup(Bimage *p, Bimage *pmask, int connect_type, long &me, long &ne)
Definition: Bimage_segment.cpp:1223
vecmax
vector< T1 > vecmax(vector< T1 > v1, vector< T2 > v2)
Definition: Vector3.h:589
RHO
#define RHO
Definition: utilities.h:91
Vector3::min
Type min()
Definition: Vector3.h:169
Bimage::truncate_to_avg
int truncate_to_avg(double minim, double maxim)
Sets voxels in image data exceeding a given minimum and maximum to the average.
Definition: Bimage_rescale.cpp:349
segment_highest_neighbor
long segment_highest_neighbor(vector< Bsuperpixel > &seg, long i, long cc)
Definition: Bimage_segment.cpp:1665
QsortSmallToLargeEdge
int QsortSmallToLargeEdge(const void *x, const void *y)
Definition: Bimage_segment.cpp:1156
Bimage::check_if_same_size
bool check_if_same_size(Bimage *p)
Check if two images are the same size.
Definition: Bimage.cpp:536
GSregion::p
long p
Definition: Bimage_segment.cpp:30
Bimage::replace_maxima
long replace_maxima(double threshold)
Replaces maxima above a threshold using local averages.
Definition: Bimage_segment.cpp:692
NNEIGHBOR
#define NNEIGHBOR
Definition: Bsuperpixel.h:13
img_impose_highest_neighbor
int img_impose_highest_neighbor(Bimage *p, Bimage *pmask, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1678
Bimage::coordinates
void coordinates(long i, long &nx, long &ny, long &nz)
Definition: Bimage.h:416
segment_setup_neighbors
long segment_setup_neighbors(long i, vector< Bsuperpixel > &seg, double dmax)
Definition: Bimage_segment.cpp:1706
region_join
int region_join(GSregion *region, long i, long j)
Definition: Bimage_segment.cpp:1172
Bimage::region_peaks
Bimage * region_peaks(long kernel_size, double threshold, int flood=0, int wrap=0)
Generates a segmented image from peaks above a threshold value.
Definition: Bimage_segment.cpp:470
Bimage::kernel_max
long kernel_max(long idx, long ksize)
Finds the highest value in a kernel.
Definition: Bimage.cpp:2897
Vector3::volume
double volume()
Definition: Vector3.h:235
VERB_FULL
#define VERB_FULL
Definition: utilities.h:109
img_update_segment
int img_update_segment(long i, Bimage *p, Bimage *pmask, vector< long > vstep, double colorweight, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1495
Bimage::sizeY
void sizeY(long ny)
Definition: Bimage.h:378
VERB_LABEL
#define VERB_LABEL
Definition: utilities.h:106
Bimage::data_type
DataType data_type()
Definition: Bimage.h:349
img_assign_pixel
int img_assign_pixel(long i, Bimage *p, Bimage *pmask, double wd, vector< Bsuperpixel > &seg)
Definition: Bimage_segment.cpp:1575
Bimage::histogram_thresholds
int histogram_thresholds(double &tmin, double &tmax)
Calculates minimum and maximum thresholds for truncation.
Definition: Bimage_histogram.cpp:414
error_show
int error_show(string message, string file, int line)
Displays the error with file and line reference.
Definition: utilities.cpp:755
tab
ostream & tab(ostream &out)
Definition: utilities.cpp:21
Bimage::graph_segment
Bimage * graph_segment(int type=1, Bimage *pmask=NULL, int connect_type=0, double complexity=0, long min_size=0, int return_type=0)
Graph-based segmentation of an image.
Definition: Bimage_segment.cpp:1383
Bimage::superpixels
vector< Bsuperpixel > superpixels(long step, double colorweight=0.2, long iterations=10, double stop=1)
Segment the image into superpixels.
Definition: Bimage_segment.cpp:1812
Bimage::image
Bsub_image * image
Definition: Bimage.h:188
Bimage::origin
void origin(double ox, double oy, double oz)
Definition: Bimage.h:563
GSregion
Graph segmentation region structure.
Definition: Bimage_segment.cpp:29
verbose
int verbose
Bimage::tile_mask
Bimage * tile_mask(long step)
Converts a mask to a tiled multilevel mask.
Definition: Bimage_mask.cpp:1415