/** * \file image_processing.cpp * \brief image processing for EM * Copyright 2007-2010 IMP Inventors. All rights reserved. **/ #include "IMP/em2d/image_processing.h" //#include "IMP/em2d/internal/radon.h" #include "IMP/em/Image.h" #include "IMP/em/SpiderReaderWriter.h" #include "IMP/em/filters.h" #include "IMP/algebra/eigen_analysis.h" #include "IMP/exception.h" #include "IMP/macros.h" #include #include #include #include IMPEM2D_BEGIN_NAMESPACE void wiener_filter_2D(algebra::Matrix2D_d &m, algebra::Matrix2D_d &result, const unsigned int kernel_rows, const unsigned int kernel_cols) { unsigned int rows=m.get_size(0); unsigned int cols=m.get_size(1); algebra::Matrix2D_d mean(rows,cols),variance(rows,cols); // mean.resize(rows,cols); // variance.resize(rows,cols); result.resize(rows,cols); // save origins and set to zero Pixel origin(m.get_start(0),m.get_start(1)); Pixel zero(0,0); m.set_start(zero); result.set_start(zero); // Set kernel init and end Pixel k_init((int)floor(kernel_rows/2),(int)floor(kernel_cols/2)); Pixel k_end(kernel_rows-k_init[0], kernel_cols-k_init[1]); double NM=(double)(kernel_rows*kernel_cols); // useful later for (unsigned int i=k_init[0];i max_val) { max_val = marker(neighbors[k]); } } // Reconstruction marker(p)=std::min(max_val,mask(p)); } } std::queue > propagated_pixels; // Scan in anti-raster order for (int i=rows-1;i>=0;--i) { for (int j=cols-1;j>=0;--j) { Pixel p(i,j); // current pixel Pixels neighbors =compute_neighbors_2D(p,mask,neighbors_mode,-1); // Compute maximum double pixel_val = marker(p); double max_val = pixel_val; for (unsigned int k=0;k max_val) { max_val = marker(neighbors[k]); } // Check if propagation is required if( (marker(neighbors[k]) < pixel_val) && (marker(neighbors[k]) < mask(neighbors[k]) ) ) { propagated_pixels.push(p); } } // Reconstruction marker(p)=std::min(max_val,mask(p)); } } // Propagation step while(propagated_pixels.empty() == false ) { Pixel p = propagated_pixels.front(); propagated_pixels.pop(); Pixels neighbors=compute_neighbors_2D(p,mask,neighbors_mode,0); // Reconstruction and propagation for (unsigned int k=0;km.get_finish(0) ) { q[0] = m.get_start(0); } if( q[1]m.get_finish(1) ) { q[1] = m.get_start(1); } final_neighbors.push_back(q); } } else { // Clean neighbors with indexes out of the matrix for(unsigned int i=0;i=m.get_start(0) && q[1]>=m.get_start(1) && q[0]<=m.get_finish(0) && q[1]<=m.get_finish(1)) { final_neighbors.push_back(q); } } } return final_neighbors; } void fill_holes(algebra::Matrix2D_d &m, algebra::Matrix2D_d &result,double h) { algebra::Matrix2D_d mask; double max_m = m.compute_max(); double max_plus_h = max_m +h; mask = max_plus_h - m; // The result is the marker. It should be max_plus_m - m - h, but is the same result = max_m - m; morphological_reconstruction(mask,result,8); result = max_plus_h - result; } void get_domes(algebra::Matrix2D_d &m,algebra::Matrix2D_d &result,double h) { result = m - h; morphological_reconstruction(m,result,8); result = m - result; } void preprocess_em2d(algebra::Matrix2D_d &m, algebra::Matrix2D_d &result, double n_stddevs) { m.normalize(); fill_holes(m,result,1.0); // no standard devs. Fill holes of depth 1 result.normalize(); em::FilterByThreshold thres; thres.set_parameters(0,0); // Threshold 0, clean everything below // thres.set_parameters(1,0); // Threshold 1, clean everything below thres.apply(result); result.normalize(); } void dilation(const algebra::Matrix2D_d &m, algebra::Matrix2D_d &kernel, algebra::Matrix2D_d &result) { // Prepare the kernel Pixel korigin(kernel.get_start(0),kernel.get_start(1)); kernel.centered_start(); // Do the dilation for (int i=m.get_start(0);i<=m.get_finish(0);++i) { for (int j=m.get_start(1);j<=m.get_finish(1);++j) { double max_val=m(i,j)+kernel(0,0); for (int ki=kernel.get_start(0);ki<=kernel.get_finish(0);++ki) { for (int kj=kernel.get_start(1);kj<=kernel.get_finish(1);++kj) { Pixel p(i+ki,j+kj); if(m.is_logical_element(p)) { double val = m(p)+kernel(ki,kj); if(val>max_val) { max_val = val;} } } } result(i,j)=max_val; } } // Set the origins to the previous values kernel.set_start(korigin); } void erosion(const algebra::Matrix2D_d &m, algebra::Matrix2D_d &kernel, algebra::Matrix2D_d &result) { // Prepare the kernel Pixel korigin(kernel.get_start(0),kernel.get_start(1)); kernel.centered_start(); // Do the dilation for (int i=m.get_start(0);i<=m.get_finish(0);++i) { for (int j=m.get_start(1);j<=m.get_finish(1);++j) { double min_val=m(i,j)-kernel(0,0); for (int ki=kernel.get_start(0);ki<=kernel.get_finish(0);++ki) { for (int kj=kernel.get_start(1);kj<=kernel.get_finish(1);++kj) { Pixel p(i+ki,j+kj); if(m.is_logical_element(p)) { double val = m(p)-kernel(ki,kj); if(valthreshold) || (mode == -1 && m.data()[i] &mask,double value) { IMP_USAGE_CHECK((m.get_number_of_rows()==result.get_number_of_rows()) && (m.get_number_of_columns()==result.get_number_of_columns()), "em2d::masking: Matrices have different size."); for (unsigned int i=0;i srw; /********/ unsigned int size_in_pixels,new_size_in_pixels; do { size_in_pixels=0; for (unsigned int i=0;ibackground) { size_in_pixels++; } } // Dilate to get a new mask dilation(temp,kernel,mask); /********/ // em::Image xxx; // xxx.set_data(mask); // xxx.write_to_floats("mask.spi",srw); /********/ // Compute mean of the grayscale inside the mask and its size double mean=0.0; new_size_in_pixels = 0; for (unsigned int i=0;ibackground) { new_size_in_pixels++; mean += greyscale.data()[i]; } } mean /= (double)new_size_in_pixels++; boundary = mask - temp; // xxx.set_data(boundary); // xxx.write_to_floats("boundary.spi",srw); // Erode the mask if pixels in the grayscale are below the mean // and are in the boundary for (unsigned int i=0;i1); // } while( new_size_in_pixels != size_in_pixels); m.copy(temp); } void histogram_stretching(algebra::Matrix2D_d &m, int boxes,int offset) { // Number of possible values for the histogram and maximum value for // the stretched image double max_val = m.compute_max(); double min_val = m.compute_min(); double maxmin = max_val-min_val; // Histogram of boxes posible values std::vector hist(boxes); for (unsigned i=0;i::iterator it; it = std::max_element(hist.begin(),hist.end()); double h_mode_val = (double)*it; // cut value double h_cut = 0.01*h_mode_val; // indexes of the histogram for the cut value int i_min=0,i_max=0; for (unsigned i=0;i h_cut) { i_min=i; break; } } for (unsigned i=hist.size()-1;i>=0;--i ) { if(hist[i] > h_cut) { i_max=i; break; } } // Allow for some offset i_min -= offset; if(i_min <0) { i_min=0;} i_max += offset; if(i_max > (boxes-1)) { i_max=boxes-1; } // Min and max values for the new image max_val=min_val+(maxmin/(boxes-1))*((double)i_max); min_val=min_val+(maxmin/(boxes-1))*((double)i_min); maxmin = max_val-min_val; // Stretch for (unsigned i=0;i 1) { val = 1; } m.data()[i] = ((double)boxes-1)*val; } } std::vector get_histogram(em2d::Image &img, int bins) { return get_histogram(img.get_data(),bins); } std::vector get_histogram(const cv::Mat &m, int bins) { std::vector histogram(bins); // Step double min,max; cv::minMaxLoc(m, &min,&max,NULL,NULL); double step = (max-min)/(double)bins; double n_points= (double)m.rows*(double)m.cols; for(cv::MatConstIterator_ it = m.begin(); it != m.end(); ++it ) { int index = floor((*it -min)/step); histogram[index] += 1.f/n_points; } return histogram; } void apply_variance_filter(em2d::Image &input, em2d::Image &filtered,int kernelsize) { apply_variance_filter(input.get_data(),filtered.get_data(),kernelsize); } void apply_variance_filter( const cv::Mat &input,cv::Mat &filtered,int kernelsize) { // Compute the mean for each value with a filter cv::Size ksize(kernelsize,kernelsize); cv::Point anchor(-1,-1); // cv::boxFilter(input, filtered,input.depth(), // ksize,anchor,true,cv::BORDER_WRAP); // Get the squared means IMP_LOG(IMP::VERBOSE,"Getting squared means" << std::endl); cv::Mat means; cv::boxFilter(input, means,input.depth(),ksize,anchor,true); cv::Mat squared_means = means.mul(means); // Get the the means of squares IMP_LOG(IMP::VERBOSE,"Getting means of the squares" << std::endl ); cv::Mat squares = input.mul(input); // make filtered contain the means of the squares cv::boxFilter(squares, filtered,squares.depth(),ksize,anchor,true); // Variance filtered = filtered - squared_means; IMP_LOG(IMP::VERBOSE, "Adjusting variance for numerical instability " << std::endl); for (CVDoubleMatIterator it=filtered.begin(); it!=filtered.end();++it) { if(*it < 0) { *it = 0; } } } IMPEM2D_END_NAMESPACE