From 03e4284a1aba46696dfe591998027392ec30b84b Mon Sep 17 00:00:00 2001 From: Siger Ma Date: Sat, 13 Sep 2025 20:05:05 -0400 Subject: [PATCH] feat: fixed deformation vector per soma and morphological closing [RQ-0304] --- .../MIND/cellSegmentation_plugin.h | 58 +++++++++++++++++++ .../v3d_plugins/MIND/soma_simulation.cpp | 46 ++++++++------- .../v3d_plugins/MIND/soma_simulation.h | 2 + 3 files changed, 86 insertions(+), 20 deletions(-) diff --git a/released_plugins/v3d_plugins/MIND/cellSegmentation_plugin.h b/released_plugins/v3d_plugins/MIND/cellSegmentation_plugin.h index 2dd08cc24..3cc13a350 100644 --- a/released_plugins/v3d_plugins/MIND/cellSegmentation_plugin.h +++ b/released_plugins/v3d_plugins/MIND/cellSegmentation_plugin.h @@ -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(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(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(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(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(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(z, y); + } + } + /** * @brief Helper function to save the probabilistic model to a binary file. */ diff --git a/released_plugins/v3d_plugins/MIND/soma_simulation.cpp b/released_plugins/v3d_plugins/MIND/soma_simulation.cpp index c457a6852..4181418db 100644 --- a/released_plugins/v3d_plugins/MIND/soma_simulation.cpp +++ b/released_plugins/v3d_plugins/MIND/soma_simulation.cpp @@ -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; @@ -1385,6 +1388,17 @@ void extractAndDeformSomaShape( std::normal_distribution normalDist(0.0, deformationStrength); std::uniform_real_distribution 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++) { @@ -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 @@ -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(std::round(origX + deformX)) + - cubeSize / 2; - int finalY = static_cast(std::round(origY + deformY)) + - cubeSize / 2; - int finalZ = static_cast(std::round(origZ + deformZ)) + - cubeSize / 2; + int finalX = + static_cast(std::round(origX + scaledDeformX)) + + cubeSize / 2; + int finalY = + static_cast(std::round(origY + scaledDeformY)) + + cubeSize / 2; + int finalZ = + static_cast(std::round(origZ + scaledDeformZ)) + + cubeSize / 2; // Check bounds and place in arrays if (finalX >= 0 && finalX < cubeSize && finalY >= 0 && diff --git a/released_plugins/v3d_plugins/MIND/soma_simulation.h b/released_plugins/v3d_plugins/MIND/soma_simulation.h index 11e70a62d..0ebe98673 100644 --- a/released_plugins/v3d_plugins/MIND/soma_simulation.h +++ b/released_plugins/v3d_plugins/MIND/soma_simulation.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "basic_4dimage.h" #include "cellSegmentation_plugin.h"