Skip to content

Commit

Permalink
Merge pull request #231 from JesseMckinzie/nontrivial_focus_score
Browse files Browse the repository at this point in the history
Add nontrivial Focus Score implementation for Image Qaulity
  • Loading branch information
sameeul authored Aug 16, 2024
2 parents 46b8b14 + 6b4b6a8 commit 362f642
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 9 deletions.
120 changes: 115 additions & 5 deletions src/nyx/features/focus_score.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

using namespace Nyxus;

int FocusScoreFeature::kernel[9] = { 0, 1, 0,
1, -4, 1,
0, 1, 0 };

FocusScoreFeature::FocusScoreFeature() : FeatureMethod("FocusScoreFeature") {
provide_features(FocusScoreFeature::featureset);
}
Expand Down Expand Up @@ -70,13 +74,122 @@ void FocusScoreFeature::reduce (size_t start, size_t end, std::vector<int>* ptrL
}
}

void FocusScoreFeature::osized_calculate(LR& r, ImageLoader& imloader) {

// Skip calculation in case of noninformative data
if (r.aux_max == r.aux_min) return;

WriteImageMatrix_nontriv Im0 ("FocusScoreFeature-osized_calculate-Im0", r.label);
Im0.allocate_from_cloud (r.raw_pixels_NT, r.aabb, false);

focus_score_ = get_focus_score_NT(Im0, 1);

save_value(r.fvals);
}

void FocusScoreFeature::save_value(std::vector<std::vector<double>>& feature_vals) {

feature_vals[(int)FeatureIMQ::FOCUS_SCORE][0] = focus_score_;
feature_vals[(int)FeatureIMQ::LOCAL_FOCUS_SCORE][0] = local_focus_score_;

}

double FocusScoreFeature::get_focus_score_NT(WriteImageMatrix_nontriv& Im, int ksize) {

int n = 3; // size of kernel nxn

if (ksize != 1) {

kernel[0] = 2;
kernel[1] = 0;
kernel[2] = 2;

kernel[3] = 0;
kernel[4] = -8;
kernel[5] = 0;

kernel[6] = 2;
kernel[7] = 0;
kernel[8] = 2;
}

auto width = Im.get_width(),
height = Im.get_height();
auto xy0 = (int)ceil(double(n) / 2.);

// Window (N-fold kernel size)
int winX = n * 10,
winY = n * 10;
std::vector<unsigned int> W (winY * winX);

// Convolution result buffer
std::vector<double> conv_buffer ((winY + n - 1) * (winX + n - 1) * 2);

// Iterate the image window by window
int n_winHor = width / winX, //ceil (float(width) / float(win)),
n_winVert = height / winY; //ceil (float(height) / float(win));


// ROI smaller than kernel?
if (n_winVert == 0 || n_winHor == 0)
{
// Fill the window with data
for (int row=0; row < height; row++) {
for (int col = 0; col < width; col++)
{
size_t idx = row * width + col;
W[idx] = Im.get_at(idx);
}
}

// Convolve
laplacian (W, conv_buffer, width, height, ksize);

return variance(conv_buffer);
}

// Variables for Welford Algorithm for calculating variance
double mean = 0.;
double M2 = 0.; // sum of squared distance
int count = 0;

std::vector<std::tuple<double, double, int>> tile_variance; // vector of tuples containing 0: abs sum of tile, 1: variance of tile, 2: buffer size

// ROI larger than kernel
// Calculate laplacian of window and then use Welford algorithm to calculate variance of image
for (int winVert = 0; winVert < n_winVert; winVert++)
{
for (int winHor = 0; winHor < n_winHor; winHor++)
{

// Fill the window with data
for (int row=0; row<winY; row++) {
for (int col = 0; col < winX; col++)
{
size_t imIdx = winVert * n_winHor * winY * winX // skip whole windows above
+ row * n_winHor * winX // skip 'row' image-wide horizontal lines
+ winHor * n_winHor * winX // skip winHor-wide line
+ col;
W[row * winX + col] = Im.get_at(imIdx);
}
}

// Convolve
laplacian (W, conv_buffer, winY, winX, ksize);

// Calculate count, mean, and sum of squared differences (M2)
for (const auto& pixel: conv_buffer) {
++count;
double delta = pixel - mean;
mean += delta / count;
M2 += delta * (pixel - mean);
}
}
}

return M2 / count; // Return variance
}

double FocusScoreFeature::get_local_focus_score(const std::vector<PixIntens>& image, int height, int width, int ksize, int scale) {

double local_focus_score = 0;
Expand Down Expand Up @@ -113,18 +226,15 @@ void FocusScoreFeature::laplacian(const std::vector<PixIntens>& image, std::vect
int m_kernel = 3;
int n_kernel = 3;

// use c-style array for compile time initialization
int kernel[9] = { 0, 1, 0,
1, -4, 1,
0, 1, 0 };

if (ksize != 1) {
kernel[0] = 2;
kernel[1] = 0;
kernel[2] = 2;

kernel[3] = 0;
kernel[4] = -8;
kernel[5] = 0;

kernel[6] = 2;
kernel[7] = 0;
kernel[8] = 2;
Expand Down
4 changes: 3 additions & 1 deletion src/nyx/features/focus_score.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class FocusScoreFeature: public FeatureMethod

//=== Non-trivial ROIs ===
void osized_add_online_pixel(size_t x, size_t y, uint32_t intensity) {}
void osized_calculate(LR& r, ImageLoader& imloader){};
void osized_calculate(LR& r, ImageLoader& imloader);
double get_focus_score_NT(WriteImageMatrix_nontriv& Im, int ksize);

// Result saver
void save_value(std::vector<std::vector<double>>& feature_vals);
Expand All @@ -50,5 +51,6 @@ class FocusScoreFeature: public FeatureMethod

static double variance(const std::vector<double>& image);

static int kernel[9];
};

5 changes: 2 additions & 3 deletions src/nyx/python/nyxus/nyxus.py
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,7 @@ def __init__(
'neighbor_distance', 'pixels_per_micron', 'coarse_gray_depth',
'n_feature_calc_threads', 'n_loader_threads', 'ibsi',
'gabor_kersize', 'gabor_gamma', 'gabor_sig2lam', 'gabor_f0',
'channel_signature', 'min_intensity', 'max_intensity'
'channel_signature', 'min_intensity', 'max_intensity', 'ram_limit',
}

# Check for unexpected keyword arguments
Expand All @@ -1316,6 +1316,7 @@ def __init__(
dynamic_range = kwargs.get('dynamic_range', 10000)
min_intensity = kwargs.get('min_intensity', 0.0)
max_intensity = kwargs.get('max_intensity', 1.0)
ram_limit = kwargs.get('ram_limit', -1)

if neighbor_distance <= 0:
raise ValueError("Neighbor distance must be greater than zero.")
Expand All @@ -1339,8 +1340,6 @@ def __init__(
if(using_gpu > -1 and not gpu_available()):
print("No gpu available.")
using_gpu = -1

ram_limit = -1

initialize_environment(
2, # 2D
Expand Down

0 comments on commit 362f642

Please sign in to comment.