EMAN2
boxingtools.cpp
Go to the documentation of this file.
1/*
2 * Author: David Woolford, 04/15/2008 (woolford@bcm.edu)
3 * Copyright (c) 2000-2006 Baylor College of Medicine
4 *
5 * This software is issued under a joint BSD/GNU license. You may use the
6 * source code in this file under either license. However, note that the
7 * complete EMAN2 and SPARX software packages have some GPL dependencies,
8 * so you are responsible for compliance with the licenses of these packages
9 * if you opt to use BSD licensing. The warranty disclaimer below holds
10 * in either instance.
11 *
12 * This complete copyright notice must be included in any revised version of the
13 * source code. Additional authorship citations may be added, but existing
14 * author citations must be preserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 * */
31
32
33#include "boxingtools.h"
34#include "exception.h"
35using namespace EMAN;
36
37
38#include <gsl/gsl_math.h>
39#include <gsl/gsl_vector.h>
40#include <gsl/gsl_linalg.h>
41
42// For random
43#include <cstdlib>
44#include <ctime>
45
46#include <iostream>
47using std::cerr;
48using std::cout;
49using std::endl;
50
51#include <string>
52using std::string;
53
54#include <algorithm>
55// find, min_element
56
57vector<Vec3f> BoxingTools::colors = vector<Vec3f>(); // static init
58BoxingTools::CmpMode BoxingTools::mode = SWARM_AVERAGE_RATIO;
59
60#define SVD_CLASSIFIER_DEBUG 0
61
62
63#if SVD_CLASSIFIER_DEBUG
64 void printMatrix( const gsl_matrix * const A, const unsigned int rows, const unsigned int cols, const string& title = "" )
65{
66 cout << "Printing matrix " << title << endl;
67 cout << "It has " << rows << " rows and " << cols << " columns " << endl;
68 for( unsigned int i = 0; i < rows; ++i )
69 {
70 for( unsigned int j = 0; j < cols; ++j )
71 {
72 cout << gsl_matrix_get(A,i,j) << " ";
73 }
74 cout << endl;
75 }
76
77}
78
79void printVector( const gsl_vector * const A, const unsigned int length, const string& title = "" )
80{
81 cout << "Printing vector " << title << endl;
82 for( unsigned int i = 0; i < length; ++i )
83 {
84 cout << gsl_vector_get(A,i) << " ";
85 }
86 cout << endl;
87}
88
89void print_map( const map<unsigned int, unsigned int>& mapping )
90{
91 for(map<unsigned int, unsigned int>::const_iterator it = mapping.begin(); it != mapping.end(); ++it)
92 {
93 cout << it->first << " " << it->second << endl;
94 }
95}
96#endif
97
98BoxSVDClassifier::BoxSVDClassifier(const vector<vector<float> >& data, const unsigned int& classes) :
99 mData(data), mClasses(classes)
100{
101 setDims( mData );
102}
103
104
106{
107
108}
109
110bool BoxSVDClassifier::setDims( const vector<vector<float> >& data )
111{
112 mColumns = mData.size();
113 vector<vector<float> >::const_iterator it = data.begin();
114 mRows = it->size();
115 it++;
116 for( ; it != data.end(); ++it )
117 {
118 if ( it->size() != mRows )
119 {
120 cerr << "ERROR: can not initial the BoxSVDClassifier with vectors of un-equal lengths " << endl;
121 cerr << "The vector lengths that did not agree were " << mRows << " and " << it->size() << endl;
122 return false;
123 }
124 }
125
126 return true;
127}
128
129
130map< unsigned int, unsigned int> BoxSVDClassifier::go()
131{
132 // This is done in the constructor
133 // setDims(mData);
134
135
136 unsigned int local_columns = mColumns;
137 if ( mRows < mColumns )
138 {
139// cerr << "Warning: gsl SVD works only when m > n, you have m = " << mRows << " and n = " << mColumns << endl;
140 // This local adaptation means things will proceed the same way even if there are more columns in A then rows
141 // Every input data is still classified, just the SVD eigenvectors are found using a subset of all the data
142 local_columns = mRows;
143 }
144
145 gsl_matrix * U = gsl_matrix_calloc( mRows, local_columns );
146 gsl_matrix * A = gsl_matrix_calloc( mRows, mColumns );
147 for ( unsigned int i = 0; i < mRows; ++i )
148 {
149 for ( unsigned int j = 0; j < mColumns; ++j )
150 {
151 gsl_matrix_set( A, i, j, mData[j][i] );
152 if ( j < local_columns )
153 gsl_matrix_set( U, i, j, mData[j][i] );
154 }
155 }
156#if SVD_CLASSIFIER_DEBUG
157 printMatrix( A, mRows, mColumns, "A" );
158#endif
159
160 gsl_matrix * V = gsl_matrix_calloc( local_columns, local_columns );
161 gsl_vector * S = gsl_vector_calloc( local_columns );
162 gsl_vector * work = gsl_vector_calloc( local_columns );
163
164 if ( gsl_linalg_SV_decomp (U, V, S, work) )
165 {
166 cerr << "ERROR: gsl returned a non zero value on application of the SVD" << endl;
167 }
168
169#if SVD_CLASSIFIER_DEBUG
170 printMatrix( U, mRows, local_columns, "U" );
171 printVector( S, local_columns, "S" );
172 printMatrix( V, local_columns, local_columns, "V");
173#endif
174
175 // normalize the columns of matrix A
176 for ( unsigned int j = 0; j < mColumns; ++j )
177 {
178 float norm = 0;
179 for ( unsigned int i = 0; i < mRows; ++i )
180 {
181 norm += (float)(gsl_matrix_get( A, i, j)*gsl_matrix_get( A, i, j));
182 }
183 norm = sqrtf(norm);
184 for ( unsigned int i = 0; i < mRows; ++i )
185 {
186 gsl_matrix_set( A, i, j, gsl_matrix_get(A,i,j)/norm);
187 }
188 }
189
190#if SVD_CLASSIFIER_DEBUG
191 for ( unsigned int j = 0; j < mColumns; ++j )
192 {
193 double norm = 0;
194 for ( unsigned int i = 0; i < mRows; ++i )
195 {
196 norm += gsl_matrix_get( A, i, j)*gsl_matrix_get( A, i, j);
197 }
198 cout << "For column " << j << " the squared norm is " << norm << endl;
199 }
200#endif
201
202
203 gsl_matrix * svd_coords = gsl_matrix_calloc( mColumns, mColumns );
204 // Correlate the columns of A with the columns of U and store the information in a martrix called svd_coords
205 for ( unsigned int i = 0; i < mColumns; ++i )
206 {
207 for ( unsigned int j = 0; j < local_columns; ++j )
208 {
209 double result = 0.0;
210 for ( unsigned int k = 0; k < mRows; ++k )
211 {
212 result += gsl_matrix_get(A,k,i)*gsl_matrix_get(U,k,j);
213 }
214 gsl_matrix_set( svd_coords, i, j, result);
215 }
216 }
217
218#if SVD_CLASSIFIER_DEBUG
219 printMatrix( svd_coords, mColumns, mColumns, "svd_coords" );
220#endif
221
222 map< unsigned int, unsigned int> grouping = randomSeedCluster(svd_coords, mColumns);
223
224 for ( unsigned int i = 0; i < 20; ++ i )
225 {
226 grouping = getIterativeCluster(svd_coords, grouping);
227 }
228
229 gsl_matrix_free(A);
230 gsl_matrix_free(U);
231 gsl_matrix_free(V);
232 gsl_vector_free(S);
233 gsl_vector_free(work);
234 gsl_matrix_free(svd_coords);
235
236 return grouping;
237}
238
239map< unsigned int, unsigned int> BoxSVDClassifier::getIterativeCluster(const gsl_matrix* const svd_coords, const map< unsigned int, unsigned int>& current_grouping)
240{
241 // Space to store the reference vectors
242 gsl_matrix * ref_coords = gsl_matrix_calloc( mClasses, mColumns );
243
244 // Assumes there are a total of mClasses in the current_groupings mapping
245 for(unsigned int i = 0; i < mClasses; ++i)
246 {
247 unsigned int tally = 0;
248 for (map< unsigned int, unsigned int>::const_iterator it = current_grouping.begin(); it != current_grouping.end(); ++it )
249 {
250 if ( it->second == i )
251 {
252 for( unsigned int j = 0; j < mColumns; ++j )
253 {
254 gsl_matrix_set(ref_coords, i, j, gsl_matrix_get( svd_coords, it->first, j ) + gsl_matrix_get( ref_coords, i, j));
255 }
256 ++tally;
257 }
258
259 }
260 // then normalize the the addition
261 if (tally != 0)
262 for( unsigned int j = 0; j < mColumns; ++j )
263 {
264 gsl_matrix_set(ref_coords, i, j, gsl_matrix_get( ref_coords, i, j )/((float) tally));
265 }
266 }
267
268 vector<vector<float> > distances = getDistances(svd_coords, ref_coords);
269
270#if SVD_CLASSIFIER_DEBUG
271 cout << "The distance matrix is " << endl;
272 for( unsigned int i = 0; i < distances.size(); ++i )
273 {
274 for( unsigned int j = 0; j < distances[i].size(); ++j )
275 {
276 cout << distances[i][j] << " ";
277 }
278 cout << endl;
279 }
280#endif
281
282
283 // Finally decide which of the randomly chosen vectors is closest to each of the input vectors
284 // and use that as the basis of the grouping
285 map< unsigned int, unsigned int> return_map = getMapping(distances);
286
287#if SVD_CLASSIFIER_DEBUG
288 cout << "Printing classification map" << endl;
289 print_map(return_map);
290#endif
291
292 gsl_matrix_free(ref_coords);
293
294 return return_map;
295}
296
297
298map< unsigned int, unsigned int> BoxSVDClassifier::randomSeedCluster(const gsl_matrix* const svd_coords, unsigned int matrix_dims)
299{
300 // Seed the random number generator
301 srand(static_cast<unsigned int>(time(0)));
302
303 vector<unsigned int> random_seed_indices;
304 while ( random_seed_indices.size() < mClasses )
305 {
306 unsigned int random_idx = static_cast<int>(((float)rand()/RAND_MAX)*matrix_dims);
307 if ( find( random_seed_indices.begin(), random_seed_indices.end(), random_idx ) == random_seed_indices.end() )
308 {
309 random_seed_indices.push_back( random_idx );
310 }
311 }
312
313 // Space to store the reference vectors
314 gsl_matrix * ref_coords = gsl_matrix_calloc( mClasses, mColumns );
315
316 // Put the reference vectors into a matrix to make the approach transparent to the reader
317 for(unsigned int i = 0; i < random_seed_indices.size(); ++i)
318 {
319 for( unsigned int j = 0; j < matrix_dims; ++j )
320 {
321 gsl_matrix_set(ref_coords, i, j, gsl_matrix_get( svd_coords, random_seed_indices[i], j ));
322 }
323 }
324
325#if SVD_CLASSIFIER_DEBUG
326 printMatrix( ref_coords, mClasses, matrix_dims, "Reference matrix in first grouping");
327#endif
328
329 // accrue the distance data - this could be done more concisely, but there shouldn't be much cost
330 // because the data should be fairl small. By more concisely I mean, the distance data would not need
331 // to be stored, it could be determined without storing it in distances.
332 vector<vector<float> > distances = getDistances(svd_coords, ref_coords);
333
334#if SVD_CLASSIFIER_DEBUG
335 cout << "The distance matrix is " << endl;
336 for( unsigned int i = 0; i < distances.size(); ++i )
337 {
338 for( unsigned int j = 0; j < distances[i].size(); ++j )
339 {
340 cout << distances[i][j] << " ";
341 }
342 cout << endl;
343 }
344#endif
345
346
347 // Finally decide which of the randomly chosen vectors is closest to each of the input vectors
348 // and use that as the basis of the grouping
349 map< unsigned int, unsigned int> return_map = getMapping(distances);
350
351#if SVD_CLASSIFIER_DEBUG
352 cout << "Printing classification map, randomly seeded" << endl;
353 print_map(return_map);
354#endif
355
356 gsl_matrix_free(ref_coords);
357
358 return return_map;
359}
360
361
362vector<vector<float> > BoxSVDClassifier::getDistances( const gsl_matrix* const svd_coords, const gsl_matrix* const ref_coords)
363{
364 // accrue the distance data - this could be done more concisely, but there shouldn't be much cost
365 // because the data should be fairl small. By more concisely I mean, the distance data would not need
366 // to be stored, it could be determined without storing it in distances.
367 vector<vector<float> > distances;
368 for (unsigned int i = 0; i < mColumns; ++i )
369 {
370 vector<float> ith_distances;
371 for( unsigned int random_seed_idx = 0; random_seed_idx < mClasses; ++random_seed_idx )
372 {
373 float distance = 0;
374 for (unsigned int j = 0; j < mColumns; ++j )
375 {
376 float value = (float)( (gsl_matrix_get( ref_coords, random_seed_idx, j) - gsl_matrix_get( svd_coords, i, j)) );
377 distance += value * value;
378 }
379 ith_distances.push_back(distance);
380 }
381 distances.push_back(ith_distances);
382 }
383
384 return distances;
385}
386
387map< unsigned int, unsigned int> BoxSVDClassifier::getMapping(const vector<vector<float> >& distances)
388{
389 // Finally decide which of the randomly chosen vectors is closest to each of the input vectors
390 // and use that as the basis of the grouping
391 map< unsigned int, unsigned int> return_map;
392 unsigned int vector_idx = 0;
393 for( vector<vector<float> >::const_iterator it = distances.begin(); it != distances.end(); ++it, ++vector_idx )
394 {
395 vector<float>::const_iterator mIt = it->begin();
396 float min = *mIt;
397 unsigned int min_idx = 0;
398 for ( unsigned int current_idx = 0; mIt != it->end(); ++mIt, ++current_idx )
399 {
400 if ( *mIt < min )
401 {
402 min = *mIt;
403 min_idx = current_idx;
404 }
405 }
406 return_map[vector_idx] = min_idx;
407 }
408
409 return return_map;
410}
411
412map< unsigned int, unsigned int> BoxSVDClassifier::colorMappingByClassSize( const map< unsigned int, unsigned int>& grouping )
413{
414
415 vector<unsigned int> current_mappings;
416 // Get the extent of the current mappings
417 for (map< unsigned int, unsigned int>::const_iterator it = grouping.begin(); it != grouping.end(); ++it )
418 {
419 if ( find( current_mappings.begin(), current_mappings.end(), it->second ) == current_mappings.end() )
420 {
421 current_mappings.push_back( it->second );
422 }
423 }
424
425 if ( current_mappings.size() < 2 )
426 {
427 cerr << "Error, cannot call colMappingByClassSize when less than 2 classes have been specified, I think you created " << current_mappings.size() << " classes " << endl;
428 throw;
429 }
430
431 // Record how many data points are in each class.
432 map<unsigned int, unsigned int> mappings_tally;
433 for( vector<unsigned int>::const_iterator it = current_mappings.begin(); it != current_mappings.end(); ++it )
434 {
435 // First initialize each total to zero
436 mappings_tally[*it] = 0;
437 }
438
439 // Now do the actual counting
440 for (map< unsigned int, unsigned int>::const_iterator it = grouping.begin(); it != grouping.end(); ++it )
441 {
442 mappings_tally[it->second] += 1;
443 }
444
445 // find the largest tally
446 unsigned int current_mapping_idx = 0;
447 map< unsigned int, unsigned int> return_map;
448 while ( mappings_tally.size() > 0 )
449 {
450#if SVD_CLASSIFIER_DEBUG
451 cout << "Printing mappings_tally" << endl;
452 print_map(mappings_tally);
453#endif
454
455 map< unsigned int, unsigned int>::iterator it = mappings_tally.begin();
456 map< unsigned int, unsigned int>::iterator track_it = mappings_tally.begin();
457 unsigned int current_max = it->second;
458 unsigned int current_idx = it->first;
459 ++it;
460 for (; it != mappings_tally.end(); ++it )
461 {
462 if ( it->second > current_max )
463 {
464 current_max = it->second;
465 current_idx = it->first;
466 track_it = it;
467 }
468 }
469
470#if SVD_CLASSIFIER_DEBUG
471 cout << "The mapping is " << current_idx << " to " << current_mapping_idx << endl;
472#endif
473 for (map< unsigned int, unsigned int>::const_iterator group_it = grouping.begin(); group_it != grouping.end(); ++group_it )
474 {
475 if ( group_it->second == current_idx )
476 {
477 return_map[group_it->first] = current_mapping_idx;
478 }
479 }
480
481 mappings_tally.erase( current_idx );
482
483 current_mapping_idx++;
484 }
485
486
487#if SVD_CLASSIFIER_DEBUG
488 cout << "Printing adjusted classification map" << endl;
489 print_map(return_map);
490#endif
491
492
493 return return_map;
494}
495
496
497
498vector<float> BoxingTools::get_min_delta_profile(const EMData* const image, int x, int y, int radius)
499{
500 float peakval = image->get_value_at(x,y);
501
502 vector<float> profile(radius,0); // this sets the vectors size to radius, and the values to 0
503 int radius_squared = radius*radius;
504
505 static vector<float> squared_numbers;
506 if ( (unsigned int)(radius+1) > squared_numbers.size() ) {
507 for(int i = squared_numbers.size(); i <= radius; ++i) {
508 squared_numbers.push_back((float)(i*i));
509 }
510 }
511
512 vector<unsigned int> tally;
513 if (mode == SWARM_AVERAGE_RATIO) tally.resize(profile.size(),0);
514
515 for(int k = -radius; k <= radius; ++k) {
516 for(int j = -radius; j <= radius; ++j) {
517 // Translate coordinates
518 int xx = x+j;
519 int yy = y+k;
520
521 // Protect against accessing pixels out of bounds
522 if ( xx >= image->get_xsize() || xx < 0 ) continue;
523 if ( yy >= image->get_ysize() || yy < 0 ) continue;
524
525 // We don't need to pay attention to the origin
526 if ( xx == x && yy == y) continue;
527
528 // Protect against vector accesses beyond the boundary
529 int square_length = k*k + j*j;
530 if (square_length > radius_squared ) continue;
531
532 // The idx is the radius, rounded down. This creates a certain type of pattern that
533 // can only really be explained visually...
534 int idx = -1;
535 // This little loop avoids the use of sqrtf
536 for(int i = 1; i < radius; ++i) {
537 if ( square_length >= squared_numbers[i] && square_length <= squared_numbers[i+1] ) {
538 idx = i;
539 }
540 }
541// int idx = (int) sqrtf(k*k + j*j);
542 // decrement the idx, because the origin information is redundant
543 idx -= 1;
544
545 if ( mode == SWARM_DIFFERENCE ) {
546 // Finally, get the drop relative to the origin
547 float val = peakval - image->get_value_at(xx,yy);
548
549 // Store it if the drop is smaller than the current value (or if there is no value)
550 if ( profile[idx] > val || profile[idx] == 0 ) profile[idx] = val;
551 }
552 else if (mode == SWARM_RATIO) {
553 // Finally, get the drop relative to the origin
554 float val = (peakval - image->get_value_at(xx,yy) ) / peakval;
555
556 // Store it if the drop is smaller than the current value (or if there is no value)
557 if ( profile[idx] > val || profile[idx] == 0 ) profile[idx] = val;
558 }
559 else if (mode == SWARM_AVERAGE_RATIO) {
560 profile[idx] += image->get_value_at(xx,yy);
561 tally[idx]++;
562 }
563
564 }
565 }
566
567 if (mode == SWARM_AVERAGE_RATIO) {
568 for(unsigned int i = 0; i < profile.size(); ++i) {
569 if (tally[i] != 0) {
570 profile[i] /= static_cast<float>(tally[i]);
571 profile[i] = (peakval - profile[i] ) / peakval;
572 }
573 }
574 }
575
576 return profile;
577}
578
579bool BoxingTools::is_local_maximum(const EMData* const image, int x, int y, int radius,EMData* exclusion_map)
580{
581 float peakval = image->get_value_at(x,y);
582 int radius_squared = radius*radius;
583 for(int k = -radius; k <= radius; ++k) {
584 for(int j = -radius; j <= radius; ++j) {
585 // Translate coordinates
586 int xx = x+j;
587 int yy = y+k;
588
589// // Protect against accessing pixel out of bounds
590 if ( xx >= image->get_xsize() || xx < 0 ) continue;
591 if ( yy >= image->get_ysize() || yy < 0 ) continue;
592
593 // We don't need to pay attention to the origin
594 if ( xx == x && yy == y) continue;
595
596 if ((k*k+j*j)>radius_squared) continue;
597
598 if ( image->get_value_at(xx,yy) > peakval) return false;
599 }
600 }
601
602 set_radial_non_zero(exclusion_map,x,y,radius);
603
604 return true;
605
606}
607
608vector<IntPoint> BoxingTools::auto_correlation_pick(const EMData* const image, float threshold, int radius, const vector<float>& profile, EMData* const exclusion, const int cradius, int mode)
609{
610 if (mode < 0 || mode > 2 ) {
611 throw InvalidValueException(mode,"Error, the mode can only be 0,1, or 2.");
612 }
613
614 if ( radius < 0) {
615 throw InvalidValueException(radius,"Radius must be greater than 1");
616 }
617
618 if ( cradius < 0) {
619 throw InvalidValueException(cradius,"CRadius must be greater than 1");
620 }
621
622
623 int nx = image->get_xsize();
624 int ny = image->get_ysize();
625
626 vector<IntPoint> solution;
627
628 int r = radius+1;
629
630 for(int j = r; j < ny-r;++j) {
631 for(int k = r; k < nx-r;++k) {
632
633 if (exclusion->get_value_at(k,j) != 0 ) continue;
634
635 if (image->get_value_at(k,j) < threshold) continue;
636 if ( mode == 0 ) {
637 solution.push_back(IntPoint(k,j));
638 set_radial_non_zero(exclusion,k,j,radius);
639 continue;
640 }
641
642 vector<float> p(r,0);
643
644 if (hi_brid(image,k,j,r,exclusion,p)) {
645 if ( mode == 1 ) {
646 if (p[cradius] >= profile[cradius]) {
647 solution.push_back(IntPoint(k,j));
648 set_radial_non_zero(exclusion,k,j,radius);
649 continue;
650 }
651 }
652 else /* mode == 2 */{
653 bool bad = false;
654 for (int ii = 0; ii <= cradius; ++ii) {
655 if (p[ii] < profile[ii]) {
656 bad = true;
657 break;
658 }
659 }
660 if (bad) continue;
661 solution.push_back(IntPoint(k,j));
662 set_radial_non_zero(exclusion,k,j,radius);
663 }
664
665
666 }
667 }
668 }
669 return solution;
670}
671
672
673bool BoxingTools::hi_brid(const EMData* const image, int x, int y, int radius,EMData* const exclusion_map, vector<float>& profile)
674{
675
676 float peakval = image->get_value_at(x,y);
677
678 int radius_squared = radius*radius;
679
680 static vector<float> squared_numbers;
681 if ( (unsigned int)(radius+1) > squared_numbers.size() ) {
682 for(int i = squared_numbers.size(); i <= radius; ++i) {
683 squared_numbers.push_back((float)(i*i));
684 }
685 }
686
687 vector<unsigned int> tally;
688 if (mode == SWARM_AVERAGE_RATIO) tally.resize(profile.size(),0);
689
690 for(int k = -radius; k <= radius; ++k) {
691 for(int j = -radius; j <= radius; ++j) {
692 // Translate coordinates
693 int xx = x+j;
694 int yy = y+k;
695
696 // Protect against accessing pixels out of bounds
697 if ( xx >= image->get_xsize() || xx < 0 ) continue;
698 if ( yy >= image->get_ysize() || yy < 0 ) continue;
699
700 // We don't need to pay attention to the origin
701 if ( xx == x && yy == y) continue;
702
703 // Protect against vector accesses beyond the boundary
704 int square_length = k*k + j*j;
705 if (square_length > radius_squared ) continue;
706
707 // It's not a local maximum!
708 if ( image->get_value_at(xx,yy) > peakval) return false;
709
710 // The idx is the radius, rounded down. This creates a certain type of pattern that
711 // can only really be explained visually...
712 int idx = -1;
713 // This little loop avoids the use of sqrtf
714 for(int i = 1; i < radius; ++i) {
715 if ( square_length >= squared_numbers[i] && square_length <= squared_numbers[i+1] ) {
716 idx = i;
717 }
718 }
719// int idx = (int) sqrtf(k*k + j*j);
720 // decrement the idx, because the origin information is redundant
721 idx -= 1;
722
723 if (mode == SWARM_DIFFERENCE) {
724 // Finally, get the drop relative to the origin
725 float val = peakval - image->get_value_at(xx,yy);
726
727 // Store it if the drop is smaller than the current value (or if there is no value)
728 if ( profile[idx] > val || profile[idx] == 0 ) profile[idx] = val;
729 }
730 else if (mode == SWARM_RATIO) {
731 // Finally, get the drop relative to the origin
732 float val = (peakval - image->get_value_at(xx,yy) ) / peakval;
733
734 // Store it if the drop is smaller than the current value (or if there is no value)
735 if ( profile[idx] > val || profile[idx] == 0 ) profile[idx] = val;
736 }
737 else if (mode == SWARM_AVERAGE_RATIO) {
738 profile[idx] += image->get_value_at(xx,yy);
739 tally[idx]++;
740 }
741
742 }
743 }
744
745 if (mode == SWARM_AVERAGE_RATIO) {
746 for(unsigned int i = 0; i < profile.size(); ++i) {
747 if (tally[i] != 0) {
748 profile[i] /= static_cast<float>(tally[i]);
749 profile[i] = (peakval - profile[i] ) / peakval;
750 }
751 }
752 }
753
754 set_radial_non_zero(exclusion_map,x,y,radius);
755
756 return true;
757}
758
759
760void BoxingTools::set_radial_non_zero(EMData* const exclusion, int x, int y, int radius)
761{
762 int radius_squared = radius*radius;
763 for(int k = -radius; k <= radius; ++k) {
764 for(int j = -radius; j <= radius; ++j) {
765 // Translate coordinates
766 int xx = x+j;
767 int yy = y+k;
768
769 if ((k*k+j*j)>radius_squared) continue;
770 // Protect against accessing pixel out of bounds
771 if ( xx >= exclusion->get_xsize() || xx < 0 ) continue;
772 if ( yy >= exclusion->get_ysize() || yy < 0 ) continue;
773
774 exclusion->set_value_at(xx,yy,1);
775 }
776 }
777}
778
779IntPoint BoxingTools::find_radial_max(const EMData* const map, int x, int y, int radius)
780{
781 float currentmax = map->get_value_at(x,y);
782
783 IntPoint soln(x,y);
784
785 int radius_squared = radius*radius;
786 for(int k = -radius; k <= radius; ++k) {
787 for(int j = -radius; j <= radius; ++j) {
788 // Translate coordinates
789 int xx = x+j;
790 int yy = y+k;
791
792 // Protect against accessing pixels out of bounds
793 if ( xx >= map->get_xsize() || xx < 0 ) continue;
794 if ( yy >= map->get_ysize() || yy < 0 ) continue;
795
796 // Protect against vector accesses beyond the boundary
797 int square_length = k*k + j*j;
798 if (square_length > radius_squared ) continue;
799
800 float val = map->get_value_at(xx,yy);
801
802 if (val > currentmax) {
803 currentmax = val;
804 soln[0] = xx;
805 soln[1] = yy;
806 }
807 }
808 }
809
810 return soln;
811}
812
813
814void BoxingTools::set_region( EMData* const image, const EMData* const mask, const int x, const int y, const float& val) {
815
816 // Works only in 2D
817 int inx = image->get_xsize();
818 int iny = image->get_ysize();
819 int mnx = mask->get_xsize();
820 int mny = mask->get_ysize();
821
822 int startx = x-mnx/2;
823 int endx =startx + mnx;
824 int xoffset = 0;
825 if (startx < 0) {
826 xoffset = abs(startx);
827 startx = 0;
828 }
829 if (endx > inx) endx = inx;
830
831 int starty = y-mny/2;
832 int endy =starty + mny;
833 int yoffset = 0;
834 if (starty < 0) {
835 yoffset = abs(starty);
836 starty = 0;
837 }
838 if (endy > iny) endy = iny;
839
840
841 for (int j = starty; j < endy; ++j ) {
842 for (int i = startx; i < endx; ++i) {
843 if (mask->get_value_at(xoffset+i-startx,yoffset+j-starty) != 0 ) {
844 image->set_value_at(i,j,val);
845 }
846 }
847 }
848}
849
850map<unsigned int, unsigned int> BoxingTools::classify(const vector<vector<float> >& data, const unsigned int& classes)
851{
852 BoxSVDClassifier classifier(data, classes);
853 map< unsigned int, unsigned int> mapping = classifier.go();
854
856
857 return mapping;
858
859}
860
861
862Vec3f BoxingTools::get_color( const unsigned int index )
863{
864 if ( colors.size() == 0 ) {
865 colors.push_back(Vec3f(0,0,0));
866 colors.push_back(Vec3f(0,0,1));
867 colors.push_back(Vec3f(0,1,0));
868 colors.push_back(Vec3f(1,0,0));
869 colors.push_back(Vec3f(1,1,0));
870 colors.push_back(Vec3f(1,0,1));
871 colors.push_back(Vec3f(0,1,1));
872 colors.push_back(Vec3f(1,1,1));
873 }
874 if ( index >= colors.size() )
875 {
876 while ( colors.size() <= index )
877 {
878 bool found = false;
879 while ( !found )
880 {
881 unsigned int random_idx = rand() % colors.size();
882 unsigned int random_idx2 = rand() % colors.size();
883 while ( random_idx2 == random_idx )
884 {
885 random_idx2 = rand() % colors.size();
886 }
887
888 Vec3f result = (colors[random_idx] + colors[random_idx2])/2.0;
889 if ( find( colors.begin(), colors.end(), result ) == colors.end() )
890 {
891 colors.push_back( result );
892 found = true;
893 }
894 }
895 }
896 }
897 return colors[index];
898}
899
#define V(i, j)
Definition: analyzer.cpp:697
unsigned int mColumns
Definition: boxingtools.h:132
const vector< vector< float > > & mData
Definition: boxingtools.h:130
map< unsigned int, unsigned int > getIterativeCluster(const gsl_matrix *const svd_coords, const map< unsigned int, unsigned int > &current_grouping)
map< unsigned int, unsigned int > go()
unsigned int mClasses
Definition: boxingtools.h:135
bool setDims(const vector< vector< float > > &data)
map< unsigned int, unsigned int > randomSeedCluster(const gsl_matrix *const svd_coords, unsigned int matrix_dims)
static map< unsigned int, unsigned int > colorMappingByClassSize(const map< unsigned int, unsigned int > &grouping)
map< unsigned int, unsigned int > getMapping(const vector< vector< float > > &distances)
vector< vector< float > > getDistances(const gsl_matrix *const svd_coords, const gsl_matrix *const ref_coords)
static IntPoint find_radial_max(const EMData *const map, int x, int y, int radius)
static vector< float > get_min_delta_profile(const EMData *const image, int x, int y, int radius)
Gets a pixel minimum delta radial profile about some pixel focal point.
static map< unsigned int, unsigned int > classify(const vector< vector< float > > &data, const unsigned int &classes=4)
static void set_region(EMData *const image, const EMData *const mask, const int x, const int y, const float &val)
static void set_radial_non_zero(EMData *const exclusion, int x, int y, int radius)
static vector< Vec3f > colors
Definition: boxingtools.h:112
static vector< IntPoint > auto_correlation_pick(const EMData *const image, float threshold, int radius, const vector< float > &profile, EMData *const exclusion, const int cradius, int mode=1)
static Vec3f get_color(const unsigned int index)
static bool hi_brid(const EMData *const image, int x, int y, int radius, EMData *const exclusion_map, vector< float > &profile)
static CmpMode mode
Definition: boxingtools.h:113
static bool is_local_maximum(const EMData *const image, int x, int y, int radius, EMData *const exclusion_map)
Determines if a given pixel is the maximum in local radial neighborhood Useful for automated correlat...
EMData stores an image's data and defines core image processing routines.
Definition: emdata.h:82
IntPoint defines an integer-coordinate point in a 1D/2D/3D space.
Definition: geometry.h:192
#define InvalidValueException(val, desc)
Definition: exception.h:285
E2Exception class.
Definition: aligner.h:40
Vec3< float > Vec3f
Definition: vec3.h:693
double length(const Vector3 &v)
Definition: vecmath.h:313
#define y(i, j)
Definition: projector.cpp:1516
#define x(i)
Definition: projector.cpp:1517