Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
:: build the MIND plugin in the v3d_plugins directory
:: build the MINDS plugin in the v3d_plugins directory
:: (window version) by Athmane Benarous
:: 2024-11-16
:: Best add release argument to make release\v3d.exe can recognize plugin
Expand All @@ -7,8 +7,8 @@
set PATH=%PATH%;
cd v3d_plugins

:: Automatically set the directory name to MIND
set DIR_NAME=MIND
:: Automatically set the directory name to MINDS
set DIR_NAME=MINDS

:: Check if the directory exists
if not exist %DIR_NAME% (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Machine Intelligence for Neuron Detection
# Machine Intelligence for Neuron Detection and Segmentation

## Introduction

Machine Intelligence for Neuron Detection (MIND) is a platform built with the aim of facilitating deep learning pipelines to automatically segment neuron somas in large scale images of the brain. Its capabilities and how to use the functions are clearly documented on its [wiki page](https://github.com/ImagiNeuron/vaa3d_tools/wiki). They include the following functions:
Machine Intelligence for Neuron Detection and Segmentation (MINDS) is a platform built with the aim of facilitating deep learning pipelines to automatically segment neuron somas in large scale images of the brain. Its capabilities and how to use the functions are clearly documented on its [wiki page](https://github.com/ImagiNeuron/vaa3d_tools/wiki). They include the following functions:

1. `Isotropic Correction` - Adjust the 3D view of images for the true dimensions of a voxel based on the microscopy technique.
2. `Soma Segmentation` - Automatically segments neuron somas that have been bounded within spheres around their center of mass with Vaa3D markers. Outputs a visualization of the segmentation, as well as the binary segmentation file, and a probabilistic model of Neuron Soma shape obtained through Principal Component Analysis (PCA) on the binary segmentation of somas. The PCA results are also output in a CSV file.
Expand All @@ -28,7 +28,7 @@ The initial code for this plugin was generated with the `_Vaa3D_plugin_creator`

### Build Files

- All build files in this repository, including the .pro files and the Makefile, were created by the `_Vaa3D_plugin_creator` plugin. We made minor modifications to them to adjust them for the tools we are using, but nothing significant. To build our plugin, simply run the `compile_mind.bat` script under the `\vaa3d_tools\released_plugins` folder.
- All build files in this repository, including the .pro files and the Makefile, were created by the `_Vaa3D_plugin_creator` plugin. We made minor modifications to them to adjust them for the tools we are using, but nothing significant. To build the MINDS plugin, use the compile script under `\vaa3d_tools\released_plugins` (rename your old `compile_mind.bat` to `compile_minds.bat` to keep the naming consistent).

## Contributions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <QCheckBox>
#include <QComboBox>
#include <QCommonStyle>
#include <QFileDialog>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
Expand Down Expand Up @@ -84,6 +85,9 @@ class dialogRun : public QDialog {
QLineEdit *
QLineEdit_medianFilteringRadius; // line edit for median filtering radius
double medianFilteringRadius; // radius for median filtering radius
QCheckBox
*QCheckBox_evaluateSegmentation; // checkbox for evaluate segmentation
bool evaluateSegmentation; // flag for evaluate segmentation
dialogRun(V3DPluginCallback2 &V3DPluginCallback2_currentCallback,
QWidget *QWidget_parent, int int_channelDim) {
// channel
Expand Down Expand Up @@ -180,6 +184,11 @@ class dialogRun : public QDialog {
QCheckBox_manualThresholding = new QCheckBox("Manual Thresholding", this);
QCheckBox_manualThresholding->setChecked(false); // default off
hLayout_segmentationTop->addWidget(QCheckBox_manualThresholding, 0);
// Evaluate Segmentation Checkbox
QCheckBox_evaluateSegmentation =
new QCheckBox("Evaluate Segmentation", this);
QCheckBox_evaluateSegmentation->setChecked(false); // default off
hLayout_segmentationTop->addWidget(QCheckBox_evaluateSegmentation, 0);
vLayout_segmentation->addLayout(hLayout_segmentationTop);
// Row 2: Median filtering, its radius, and marker constraint
QHBoxLayout *hLayout_segmentationBottom = new QHBoxLayout();
Expand Down Expand Up @@ -286,6 +295,8 @@ class dialogRun : public QDialog {
applyMarkerConstraint = QCheckBox_markerConstraint->isChecked();
// Retrieve manual threshold flag:
manualThresholding = QCheckBox_manualThresholding->isChecked();
// Retrieve evaluate segmentation flag:
evaluateSegmentation = QCheckBox_evaluateSegmentation->isChecked();

if (this->QRadioButton_shape_sphere->isChecked()) {
this->shape_type_selection = sphere;
Expand Down Expand Up @@ -375,14 +386,18 @@ class cellSegmentation : public QObject {
// marker constraint check
bool applyMarkerConstraint;
// manual thresholding check
bool manualThresholding;
bool manualThresholding; // evaluate segmentation check
bool evaluateSegmentation;
// callback for image operations
V3DPluginCallback2 *_V3DPluginCallback2_currentCallback;

// vector<V3DLONG> poss_segmentationResultCenterMerged;
#pragma endregion
class_segmentationMain() {
is_initialized = false;
applyMedianFiltering = true; // default to true
applyMarkerConstraint = false; // default: no marker constraint
_V3DPluginCallback2_currentCallback = nullptr;
}
~class_segmentationMain() {}

Expand Down Expand Up @@ -891,7 +906,6 @@ class cellSegmentation : public QObject {
cubeSize);

QString saveModelPath = fileName + "_probability_model.bin";

if (!saveProbabilityModel(saveModelPath.toStdString(), probabilisticModel,
cubeSize, cubeSize, cubeSize)) {
printf("Failed to save probabilistic model\n");
Expand All @@ -900,6 +914,88 @@ class cellSegmentation : public QObject {
// Free the allocated memory for the probabilistic model and segmentation.
delete[] somaSegmentation;
delete[] probabilisticModel;

// Evaluate segmentation if requested
if (this->evaluateSegmentation &&
this->_V3DPluginCallback2_currentCallback) {
// Prompt user to select ground truth file
QFileDialog fileDialog;
fileDialog.setWindowTitle("Select Ground Truth Segmentation File");
fileDialog.setFileMode(QFileDialog::ExistingFile);
fileDialog.setNameFilter("Image files (*.tif *.tiff *.v3draw)");

if (fileDialog.exec()) {
QStringList selectedFiles = fileDialog.selectedFiles();
if (!selectedFiles.isEmpty()) {
QString groundTruthPath = selectedFiles.first();
printf("Loading ground truth data from: %s\n",
groundTruthPath.toStdString()
.c_str()); // Load ground truth data
unsigned char *groundTruthData = nullptr;
V3DLONG gtDims[4];
int datatype = 0;

// Use pointer dereference to convert pointer to reference
if (this->_V3DPluginCallback2_currentCallback &&
simple_loadimage_wrapper(
*(V3DPluginCallback
*)(this->_V3DPluginCallback2_currentCallback),
groundTruthPath.toStdString().c_str(), groundTruthData,
gtDims, datatype)) {
// Check if dimensions match
if (gtDims[0] == this->dim_X && gtDims[1] == this->dim_Y &&
gtDims[2] == this->dim_Z) {
// Calculate Dice coefficient
double intersection = 0.0;
double segmentationVolume = 0.0;
double groundTruthVolume = 0.0;

for (V3DLONG i = 0; i < this->size_page; i++) {
// Binary comparison
if (this->binarySegImage[i] > 0) segmentationVolume += 1.0;
if (groundTruthData[i] > 0) groundTruthVolume += 1.0;
if (this->binarySegImage[i] > 0 && groundTruthData[i] > 0)
intersection += 1.0;
}

double diceCoefficient = 0.0;
if ((segmentationVolume + groundTruthVolume) > 0) {
diceCoefficient = 2.0 * intersection /
(segmentationVolume + groundTruthVolume);
}

// Print Dice score to CLI
printf("\n===== Segmentation Evaluation Results =====\n");
printf("Dice Coefficient: %.4f\n", diceCoefficient);
printf("Segmentation Volume: %.0f voxels\n",
segmentationVolume);
printf("Ground Truth Volume: %.0f voxels\n", groundTruthVolume);
printf("Intersection Volume: %.0f voxels\n", intersection);
printf("==========================================\n\n");
} else {
printf(
"Error: Ground truth dimensions (%ld, %ld, %ld) do not "
"match segmentation dimensions (%ld, %ld, %ld)\n",
gtDims[0], gtDims[1], gtDims[2], this->dim_X, this->dim_Y,
this->dim_Z);
}

// Free ground truth data
if (groundTruthData) {
delete[] groundTruthData;
}
} else {
printf("Error: Failed to load ground truth file from %s\n",
groundTruthPath.toStdString().c_str());
}
}
} else {
printf(
"Segmentation evaluation canceled: No ground truth file "
"selected\n");
}
}

this->memory_free_uchar2D(masks_page, count_exemplar);
return true;
}
Expand Down Expand Up @@ -3017,7 +3113,13 @@ class cellSegmentation : public QObject {
dialogRun1.applyMarkerConstraint;
// Set the manual thresholding flag from the dialog
this->class_segmentationMain1.manualThresholding =
dialogRun1.manualThresholding;
dialogRun1.manualThresholding; // Set the evaluate segmentation flag
// from the dialog
this->class_segmentationMain1.evaluateSegmentation =
dialogRun1.evaluateSegmentation;
// Set the callback for image operations
this->class_segmentationMain1._V3DPluginCallback2_currentCallback =
&_V3DPluginCallback2_currentCallback;
int idx_shape; // get shape parameters;
if (dialogRun1.shape_type_selection == sphere) {
idx_shape = 1;
Expand Down
Loading