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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions released_plugins/v3d_plugins/MIND/cellSegmentation_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,64 @@ class cellSegmentation : public QObject {
ax2, ax3);
}

/**
* @brief Helper function to do 3D morphological closing on binary
* segmentation
*/
void morphologicalClosing3D(double *segmentation, V3DLONG cubeSize,
int kernelSize = 3) {
// Z axis (XY slices)
for (int z = 0; z < cubeSize; ++z) {
cv::Mat slice(cubeSize, cubeSize, CV_8UC1);
for (int y = 0; y < cubeSize; ++y)
for (int x = 0; x < cubeSize; ++x)
slice.at<uchar>(y, x) =
segmentation[z * cubeSize * cubeSize + y * cubeSize + x];
cv::Mat closed;
cv::morphologyEx(slice, closed, cv::MORPH_CLOSE,
cv::getStructuringElement(
cv::MORPH_RECT, cv::Size(kernelSize, kernelSize)));
for (int y = 0; y < cubeSize; ++y)
for (int x = 0; x < cubeSize; ++x)
segmentation[z * cubeSize * cubeSize + y * cubeSize + x] =
closed.at<uchar>(y, x);
}

// Y axis (XZ slices)
for (int y = 0; y < cubeSize; ++y) {
cv::Mat slice(cubeSize, cubeSize, CV_8UC1);
for (int z = 0; z < cubeSize; ++z)
for (int x = 0; x < cubeSize; ++x)
slice.at<uchar>(z, x) =
segmentation[z * cubeSize * cubeSize + y * cubeSize + x];
cv::Mat closed;
cv::morphologyEx(slice, closed, cv::MORPH_CLOSE,
cv::getStructuringElement(
cv::MORPH_RECT, cv::Size(kernelSize, kernelSize)));
for (int z = 0; z < cubeSize; ++z)
for (int x = 0; x < cubeSize; ++x)
segmentation[z * cubeSize * cubeSize + y * cubeSize + x] =
closed.at<uchar>(z, x);
}

// X axis (YZ slices)
for (int x = 0; x < cubeSize; ++x) {
cv::Mat slice(cubeSize, cubeSize, CV_8UC1);
for (int z = 0; z < cubeSize; ++z)
for (int y = 0; y < cubeSize; ++y)
slice.at<uchar>(z, y) =
segmentation[z * cubeSize * cubeSize + y * cubeSize + x];
cv::Mat closed;
cv::morphologyEx(slice, closed, cv::MORPH_CLOSE,
cv::getStructuringElement(
cv::MORPH_RECT, cv::Size(kernelSize, kernelSize)));
for (int z = 0; z < cubeSize; ++z)
for (int y = 0; y < cubeSize; ++y)
segmentation[z * cubeSize * cubeSize + y * cubeSize + x] =
closed.at<uchar>(z, y);
}
}

/**
* @brief Helper function to save the probabilistic model to a binary file.
*/
Expand Down
46 changes: 26 additions & 20 deletions released_plugins/v3d_plugins/MIND/soma_simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,9 @@ void simulate_soma_data(V3DPluginCallback2 &callback, QWidget *parent) {
segMain.rotateSegmentation(tempIntensity, cubeSize, randomVec1, randomVec2,
randomVec3);

// Apply morphological closing to the synthetic segmentation
segMain.morphologicalClosing3D(tempSegmentation, cubeSize);

// Calculate intensity statistics from the extracted soma
double somaIntensitySum = 0.0;
double somaIntensityMin = 255.0;
Expand Down Expand Up @@ -1385,6 +1388,17 @@ void extractAndDeformSomaShape(
std::normal_distribution<double> normalDist(0.0, deformationStrength);
std::uniform_real_distribution<double> uniformDist(0.0, 1.0);

// Apply soma eigenvector-based deformation
double deformX = normalDist(gen) * somaEigenvector1[0] +
normalDist(gen) * somaEigenvector2[0] +
normalDist(gen) * somaEigenvector3[0];
double deformY = normalDist(gen) * somaEigenvector1[1] +
normalDist(gen) * somaEigenvector2[1] +
normalDist(gen) * somaEigenvector3[1];
double deformZ = normalDist(gen) * somaEigenvector1[2] +
normalDist(gen) * somaEigenvector2[2] +
normalDist(gen) * somaEigenvector3[2];

for (int z = 0; z < cubeSize; z++) {
for (int y = 0; y < cubeSize; y++) {
for (int x = 0; x < cubeSize; x++) {
Expand All @@ -1407,24 +1421,13 @@ void extractAndDeformSomaShape(
double distance =
sqrt(origX * origX + origY * origY + origZ * origZ);

// Apply soma eigenvector-based deformation
double deformX = normalDist(gen) * somaEigenvector1[0] +
normalDist(gen) * somaEigenvector2[0] +
normalDist(gen) * somaEigenvector3[0];
double deformY = normalDist(gen) * somaEigenvector1[1] +
normalDist(gen) * somaEigenvector2[1] +
normalDist(gen) * somaEigenvector3[1];
double deformZ = normalDist(gen) * somaEigenvector1[2] +
normalDist(gen) * somaEigenvector2[2] +
normalDist(gen) * somaEigenvector3[2];

// Scale deformation based on distance from center (less
// deformation at edges)
double radialFactor =
std::max(radialFactorMin, 1.0 - distance / radius);
deformX *= radialFactor;
deformY *= radialFactor;
deformZ *= radialFactor;
double scaledDeformX = deformX * radialFactor;
double scaledDeformY = deformY * radialFactor;
double scaledDeformZ = deformZ * radialFactor;

// Sample from probabilistic model to determine if this voxel
// should be kept, convert position to model coordinates
Expand All @@ -1450,12 +1453,15 @@ void extractAndDeformSomaShape(
// Keep voxel if probability is high enough
if (uniformDist(gen) < probability) {
// Apply deformation to final position
int finalX = static_cast<int>(std::round(origX + deformX)) +
cubeSize / 2;
int finalY = static_cast<int>(std::round(origY + deformY)) +
cubeSize / 2;
int finalZ = static_cast<int>(std::round(origZ + deformZ)) +
cubeSize / 2;
int finalX =
static_cast<int>(std::round(origX + scaledDeformX)) +
cubeSize / 2;
int finalY =
static_cast<int>(std::round(origY + scaledDeformY)) +
cubeSize / 2;
int finalZ =
static_cast<int>(std::round(origZ + scaledDeformZ)) +
cubeSize / 2;

// Check bounds and place in arrays
if (finalX >= 0 && finalX < cubeSize && finalY >= 0 &&
Expand Down
2 changes: 2 additions & 0 deletions released_plugins/v3d_plugins/MIND/soma_simulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include <memory>
#include <random>
#include <vector>
#include <opencv2/imgproc.hpp>
#include <opencv2/core.hpp>

#include "basic_4dimage.h"
#include "cellSegmentation_plugin.h"
Expand Down