|
11 | 11 |
|
12 | 12 | #include <list> |
13 | 13 |
|
| 14 | +#include "AutoParameters.hpp" |
14 | 15 | #include "data_structures/APR/APR.hpp" |
15 | 16 | #include "data_structures/APR/particles/ParticleData.hpp" |
16 | 17 | #include "data_structures/Mesh/PixelData.hpp" |
@@ -124,9 +125,6 @@ class APRConverter { |
124 | 125 |
|
125 | 126 | void generateDatastructures(APR& aAPR); |
126 | 127 |
|
127 | | - template<typename T,typename S> |
128 | | - void autoParametersLiEntropy(const PixelData<T> &image, const PixelData<T> &localIntensityScale, const PixelData<S> &grad); |
129 | | - |
130 | 128 | template<typename T> |
131 | 129 | bool check_input_dimensions(PixelData<T> &input_image); |
132 | 130 |
|
@@ -579,7 +577,7 @@ inline bool APRConverter<ImageType>::get_apr_cpu(APR &aAPR, PixelData<T> &input_ |
579 | 577 |
|
580 | 578 | if (par.auto_parameters) { |
581 | 579 | method_timer.start_timer("autoParameters"); |
582 | | - autoParametersLiEntropy(local_scale_temp2, local_scale_temp, grad_temp); |
| 580 | + autoParametersLiEntropy(par, local_scale_temp2, local_scale_temp, grad_temp, bspline_offset, verbose); |
583 | 581 | aAPR.parameters = par; |
584 | 582 | method_timer.stop_timer(); |
585 | 583 | } |
@@ -624,155 +622,6 @@ inline bool APRConverter<ImageType>::get_apr(APR &aAPR, PixelData<T> &input_imag |
624 | 622 | } |
625 | 623 |
|
626 | 624 |
|
627 | | -template<typename T> |
628 | | -void compute_means(const std::vector<T>& data, float threshold, float& mean_back, float& mean_fore) { |
629 | | - float sum_fore=0.f, sum_back=0.f; |
630 | | - size_t count_fore=0, count_back=0; |
631 | | - |
632 | | -#ifdef HAVE_OPENMP |
633 | | -#pragma omp parallel for default(none) shared(data, threshold) reduction(+:sum_fore, sum_back, count_fore, count_back) |
634 | | -#endif |
635 | | - for(size_t idx = 0; idx < data.size(); ++idx) { |
636 | | - if(data[idx] > threshold) { |
637 | | - sum_fore += data[idx]; |
638 | | - count_fore++; |
639 | | - } else { |
640 | | - sum_back += data[idx]; |
641 | | - count_back++; |
642 | | - } |
643 | | - } |
644 | | - mean_fore = sum_fore / count_fore; |
645 | | - mean_back = sum_back / count_back; |
646 | | -} |
647 | | - |
648 | | - |
649 | | -/** |
650 | | - * Compute threshold value by Li's iterative Minimum Cross Entropy method [1] |
651 | | - * |
652 | | - * Note: it is assumed that the input elements are non-negative (as is the case for the gradient and local intensity |
653 | | - * scale). To apply the method to data that may be negative, subtract the minimum value from the input, and then add |
654 | | - * that value to the computed threshold. |
655 | | - * |
656 | | - * [1] Li, C. H., & Tam, P. K. S. (1998). "An iterative algorithm for minimum cross entropy thresholding." |
657 | | - * Pattern recognition letters, 19(8), 771-776. |
658 | | - */ |
659 | | -template<typename T> |
660 | | -float threshold_li(const std::vector<T> &input) { |
661 | | - |
662 | | - if(input.empty()) { return 0.f; } // return 0 if input is empty |
663 | | - |
664 | | - const T image_min = *std::min_element(input.begin(), input.end()); |
665 | | - const T image_max = *std::max_element(input.begin(), input.end()); |
666 | | - |
667 | | - if(image_min == image_max) { return image_min; } // if all inputs are equal, return that value |
668 | | - |
669 | | - float tolerance = 0.5f; // tolerance 0.5 should suffice for integer inputs |
670 | | - |
671 | | - // For floating point inputs we set the tolerance to the lesser of 0.01 and a fraction of the data range |
672 | | - // This could be improved, by instead taking e.g. half the smallest difference between any two non-equal elements |
673 | | - if(std::is_floating_point<T>::value) { |
674 | | - float range = image_max - image_min; |
675 | | - tolerance = std::min(0.01f, range*1e-4f); |
676 | | - } |
677 | | - |
678 | | - // Take the mean of the input as initial value |
679 | | - float t_next = std::accumulate(input.begin(), input.end(), 0.f) / (float) input.size(); |
680 | | - float t_curr = -2.f * tolerance; //this ensures that the first iteration is performed, since t_next is non-negative |
681 | | - |
682 | | - // For integer inputs, we have to ensure a large enough initial value, such that mean_back > 0 |
683 | | - if(!std::is_floating_point<T>::value) { |
684 | | - // if initial value is <1, try to increase it to 1.5 unless the range is too narrow |
685 | | - if(t_next < 1.f) { |
686 | | - t_next = std::min(1.5f, (image_min+image_max)/2.f); |
687 | | - } |
688 | | - } |
689 | | - |
690 | | - // Perform Li iterations until convergence |
691 | | - while(std::abs(t_next - t_curr) > tolerance) { |
692 | | - t_curr = t_next; |
693 | | - |
694 | | - // Compute averages of values above and below the current threshold |
695 | | - float mean_back, mean_fore; |
696 | | - compute_means(input, t_curr, mean_back, mean_fore); |
697 | | - |
698 | | - // Handle the edge case where all values < t_curr are 0 |
699 | | - if(mean_back == 0) { |
700 | | - std::wcout << "log(0) encountered in APRConverter::threshold_li, returning current threshold" << std::endl; |
701 | | - return t_curr; |
702 | | - } |
703 | | - |
704 | | - // Update the threshold (one-point iteration) |
705 | | - t_next = (mean_fore - mean_back) / (std::log(mean_fore) - std::log(mean_back)); |
706 | | - } |
707 | | - return t_next; |
708 | | -} |
709 | | - |
710 | | - |
711 | | -template<typename ImageType> |
712 | | -template<typename T,typename S> |
713 | | -void APRConverter<ImageType>::autoParametersLiEntropy(const PixelData<T> &image, |
714 | | - const PixelData<T> &localIntensityScale, |
715 | | - const PixelData<S> &grad) { |
716 | | - |
717 | | - fine_grained_timer.start_timer("autoparameters: subsample buffers"); |
718 | | - |
719 | | - std::vector<S> grad_subsampled; |
720 | | - std::vector<T> lis_subsampled; |
721 | | - |
722 | | - { // intentional scope |
723 | | - /// First we extract the gradient and local intensity scale values at all locations where the image |
724 | | - /// intensity exceeds the intensity threshold. This allows better adaptation in certain cases, e.g. |
725 | | - /// when there is significant background AND signal noise/autofluorescence (provided that par.Ip_th |
726 | | - /// is set appropriately). |
727 | | - std::vector<S> grad_foreground(grad.mesh.size()); |
728 | | - std::vector<T> lis_foreground(localIntensityScale.mesh.size()); |
729 | | - |
730 | | - const auto threshold = par.Ip_th + bspline_offset; |
731 | | - size_t counter = 0; |
732 | | - for(size_t idx = 0; idx < grad.mesh.size(); ++idx) { |
733 | | - if(image.mesh[idx] > threshold) { |
734 | | - grad_foreground[counter] = grad.mesh[idx]; |
735 | | - lis_foreground[counter] = localIntensityScale.mesh[idx]; |
736 | | - counter++; |
737 | | - } |
738 | | - } |
739 | | - |
740 | | - const size_t num_foreground_pixels = counter; |
741 | | - |
742 | | - grad_foreground.resize(num_foreground_pixels); //setting size to non-zero elements. |
743 | | - lis_foreground.resize(num_foreground_pixels); |
744 | | - |
745 | | - /// Then we uniformly subsample these signals, as we typically don't need all elements to compute the thresholds |
746 | | - const size_t num_elements = std::min((size_t)32*512*512, num_foreground_pixels); //arbitrary number. |
747 | | - const size_t delta = num_foreground_pixels / num_elements; |
748 | | - grad_subsampled.resize(num_elements); |
749 | | - lis_subsampled.resize(num_elements); |
750 | | - |
751 | | -#ifdef HAVE_OPENMP |
752 | | -#pragma omp parallel for default(shared) |
753 | | -#endif |
754 | | - for(size_t idx = 0; idx < num_elements; ++idx) { |
755 | | - grad_subsampled[idx] = grad_foreground[idx*delta]; |
756 | | - lis_subsampled[idx] = lis_foreground[idx*delta]; |
757 | | - } |
758 | | - } |
759 | | - fine_grained_timer.stop_timer(); |
760 | | - |
761 | | - fine_grained_timer.start_timer("autoparameters: compute gradient threshold"); |
762 | | - par.grad_th = threshold_li(grad_subsampled); |
763 | | - fine_grained_timer.stop_timer(); |
764 | | - |
765 | | - fine_grained_timer.start_timer("autoparameters: compute sigma threshold"); |
766 | | - par.sigma_th = threshold_li(lis_subsampled); |
767 | | - fine_grained_timer.stop_timer(); |
768 | | - |
769 | | - if(verbose) { |
770 | | - std::cout << "Automatic parameter tuning found sigma_th = " << par.sigma_th << |
771 | | - " and grad_th = " << par.grad_th << std::endl; |
772 | | - } |
773 | | -} |
774 | | - |
775 | | - |
776 | 625 | /** |
777 | 626 | * Checks if the memory dimension (y) is filled |
778 | 627 | */ |
|
0 commit comments