Skip to content

Commit

Permalink
Cleanup, added model selection, improved version
Browse files Browse the repository at this point in the history
  • Loading branch information
CURTLab committed Mar 26, 2024
1 parent f4f9306 commit dd721d4
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 95 deletions.
19 changes: 12 additions & 7 deletions NanoMito3D/AnalyzeMitochondria.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void AnalyzeMitochondria::load(const QString &fileName, bool threaded)
m_fileName = fileName;
emit localizationsLoaded();
// increase axial range by 100 nm at each side to avoid clipping
m_locs.setAxialRange(m_locs.minZ() - 100.f, m_locs.maxZ() + 100.f);
//m_locs.setAxialRange(m_locs.minZ() - 100.f, m_locs.maxZ() + 100.f);
} catch(std::exception &e) {
qCritical().nospace() << tr("AnalyzeMitochondria::load Error: ") + e.what();
emit error(tr("Load localizations error"), e.what());
Expand Down Expand Up @@ -370,7 +370,7 @@ void AnalyzeMitochondria::classify(bool threaded)

emit progressRangeChanged(0, static_cast<int>(m_segments.size())-1);
for (size_t i = 0; i < m_segments.size(); ++i) {
cv::Mat dataSet(1, 14, CV_32FC1, &m_segments[i]->data);
cv::Mat dataSet(1, 14, CV_32FC1, m_segments[i]->data.values);
m_dtree->predict(dataSet, result, 0);

const int prediction = qRound(result.at<float>(0, 0));
Expand Down Expand Up @@ -405,8 +405,11 @@ void AnalyzeMitochondria::classify(bool threaded)
func();
}

void AnalyzeMitochondria::loadModel(const QString &fileName)
bool AnalyzeMitochondria::loadModel(const QString &fileName)
{
// clear model
m_dtree = {};

const auto fi = QFileInfo(fileName);
if (fi.completeSuffix().toLower() == "csv") {
// load header names from csv
Expand All @@ -418,7 +421,7 @@ void AnalyzeMitochondria::loadModel(const QString &fileName)
file.close();
} else {
emit error(tr("Load model"), tr("Could not load dataset! (%1)").arg(fileName));
return;
return false;
}

// generate training data from csv
Expand All @@ -438,7 +441,7 @@ void AnalyzeMitochondria::loadModel(const QString &fileName)
m_dtree->setMaxCategories(m_numClasses+1);
if (!m_dtree->train(trainData, cv::ml::ROW_SAMPLE, targetData)) {
emit error(tr("Load model"), tr("Could not train loaded dataset! (%1)").arg(fileName));
return;
return false;
}

// print variable importance
Expand All @@ -458,17 +461,19 @@ void AnalyzeMitochondria::loadModel(const QString &fileName)
m_numClasses = class_labels.size();
} else {
emit error(tr("Load model"), tr("Could not load dataset! (%1)").arg(fileName));
return;
return false;
}
// load model
m_dtree = cv::ml::StatModel::load<cv::ml::RTrees>(fileName.toStdString());
}

if (m_dtree.empty()) {
emit error(tr("Load model"), tr("Could not load model %1").arg(fileName));
return;
return false;
}

qDebug() << "Samples:" << m_dtree->getVarCount();
qDebug() << "Num classes:" << m_numClasses;

return true;
}
3 changes: 1 addition & 2 deletions NanoMito3D/AnalyzeMitochondria.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#include "Volume.h"
#include "Localizations.h"
#include "Segments.h"
#include "AnalyzeSkeleton.h"

enum class ThresholdMethods {
LocalISOData,
Expand Down Expand Up @@ -61,7 +60,7 @@ class AnalyzeMitochondria : public QObject
void classify(bool threaded = true);

// load model eighter from csv training dataset or pretrained json model file
void loadModel(const QString &fileName);
bool loadModel(const QString &fileName);

inline constexpr const QString &fileName() const { return m_fileName; }
inline constexpr const Localizations &localizations() const { return m_locs; }
Expand Down
12 changes: 5 additions & 7 deletions NanoMito3D/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ project(NanoMito3D VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CUDA_SUPPORT ON CACHE BOOL "Use CUDA support")
set(RELEASE_VERSION OFF CACHE BOOL "Build as release version (No test paths)")

if (CUDA_SUPPORT)
enable_language(CUDA)
Expand All @@ -25,6 +20,10 @@ endif()

set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../cmake ${CMAKE_MODULE_PATH})

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
find_package(VTK 8.0 REQUIRED COMPONENTS
Expand Down Expand Up @@ -105,7 +104,6 @@ if (CUDA_SUPPORT)
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
endif()


if (RELEASE_VERSION)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE -DRELEASE_VERSION)
else()
Expand All @@ -118,7 +116,7 @@ vtk_module_autoinit(
MODULES ${VTK_LIBRARIES}
)

target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE -D_USE_MATH_DEFINES -DNOMINMAX)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE -D_USE_MATH_DEFINES -DNOMINMAX -DUSE_OPENCV)

set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
Expand Down
2 changes: 1 addition & 1 deletion NanoMito3D/LocalThreshold.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ enum Method {
HOST_DEV uint8_t otsuThreshold(const uint16_t hist[256], int numPixels);
HOST_DEV uint8_t isoDataThreshold(const uint16_t hist[256], int numPixels);

void localThrehsold_gpu(Method method, const Volume &input, Volume &output, int windowSize);
void localThrehsold_gpu(Method method, const Volume &input, Volume &output, int windowSize, bool original = false);
void localThrehsold_cpu(Method method, const Volume &input, Volume &output, int windowSize, std::function<void(uint32_t, uint32_t)> cb = {});

}
Expand Down
25 changes: 21 additions & 4 deletions NanoMito3D/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,20 @@ MainWindow::MainWindow(QWidget *parent)
m_ui->actionExportSkeleton->setEnabled(false);
m_ui->actionExportSegmentation->setEnabled(false);

m_ui->comboThreshold->addItem("Local IsoData", QVariant::fromValue(ThresholdMethods::LocalISOData));
m_ui->comboThreshold->addItem("Local Otsu", QVariant::fromValue(ThresholdMethods::LocalOtsu));

#ifndef CUDA_SUPPORT
m_ui->checkUseGPU->setVisible(false);
#endif // CUDA_SUPPORT

setWindowTitle(tr("NanoMito3D r%1").arg(GIT_REVISION));
setWindowTitle("NanoMito3D " APP_VERSION);

m_analyis.loadModel("mitoTrainDataSet.csv");
const QString modelFile = "mitoTrainDataSet.csv";
if (QFile(modelFile).exists()) {
if (m_analyis.loadModel(modelFile))
m_ui->editModel->setText(QFileInfo(modelFile).absoluteFilePath());
}

connect(m_ui->actionExportVolume, &QAction::triggered,
this, [this]() {
Expand Down Expand Up @@ -129,7 +136,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(m_ui->buttonSelectFile, &QAbstractButton::released,
this, [this]() {
m_bar->setVisible(false);
QString fileName = QFileDialog::getOpenFileName(this, "Open localization file", m_currentFile, "TSF File (*.tsf)");
QString fileName = QFileDialog::getOpenFileName(this, "Open localization file", m_currentFile, "TSF file (*.tsf)");
if (!fileName.isEmpty()) {
m_ui->statusbar->showMessage(tr("Load %1").arg(QFileInfo(fileName).fileName()));
m_ui->frame->setEnabled(false);
Expand All @@ -148,6 +155,16 @@ MainWindow::MainWindow(QWidget *parent)
}
});

// model selection
connect(m_ui->buttonSelectModel, &QAbstractButton::released,
this, [this]() {
QString fileName = QFileDialog::getOpenFileName(this, "Open model file", m_ui->editModel->text(), "Model file (*.json *.csv)");
if (fileName.isEmpty())
return;
if (m_analyis.loadModel(fileName))
m_ui->editModel->setText(QFileInfo(fileName).absoluteFilePath());
});

connect(&m_analyis, &AnalyzeMitochondria::localizationsLoaded, this, [this]() {
// reset UI
m_bar->setVisible(false);
Expand Down Expand Up @@ -218,7 +235,7 @@ MainWindow::MainWindow(QWidget *parent)
m_ui->frame->setEnabled(false);
m_bar->setVisible(true);
m_ui->statusbar->showMessage(tr("Analyzing volume ..."));
m_analyis.analyze(m_ui->spinGaussianSigma->value(), (ThresholdMethods)m_ui->comboThreshold->currentIndex(), m_ui->checkUseGPU->isChecked());
m_analyis.analyze(m_ui->spinGaussianSigma->value(), m_ui->comboThreshold->currentData().value<ThresholdMethods>(), m_ui->checkUseGPU->isChecked());
});

connect(&m_analyis, &AnalyzeMitochondria::volumeAnalyzed, this, [this]() {
Expand Down
38 changes: 24 additions & 14 deletions NanoMito3D/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -317,33 +317,43 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboThreshold">
<item>
<property name="text">
<string>Local IsoData</string>
</property>
</item>
<item>
<property name="text">
<string>Local Otsu</string>
</property>
</item>
</widget>
<widget class="QComboBox" name="comboThreshold"/>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QPushButton" name="buttonAnalyse">
<property name="text">
<string>Analyze</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QPushButton" name="buttonClassify">
<property name="text">
<string>Classify</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="editModel"/>
</item>
<item>
<widget class="QToolButton" name="buttonSelectModel">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Model:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down
36 changes: 19 additions & 17 deletions NanoMito3D/Segments.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,31 @@

#include <vector>
#include <string>
#include <opencv2/opencv.hpp>

#include "Volume.h"
#include "SkeletonGraph.h"
#include "Bounds.h"

struct SegmentData
union SegmentData
{
float numBranches;
float numEndPoints;
float numJunctionVoxels;
float numJunctions;
float numSlabs;
float numTriples;
float numQuadruples;
float averageBranchLength;
float maximumBranchLength;
float shortestPath;
float voxels;
float width;
float height;
float depth;
float signalCount;
struct {
float numBranches;
float numEndPoints;
float numJunctionVoxels;
float numJunctions;
float numSlabs;
float numTriples;
float numQuadruples;
float averageBranchLength;
float maximumBranchLength;
float shortestPath;
float voxels;
float width;
float height;
float depth;
float signalCount;
};
float values[15];
};

struct Segment
Expand Down
7 changes: 6 additions & 1 deletion NanoMito3D/Volume.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@
#include <hdf5.h>
#endif // USE_H5

#ifdef USE_OPENCV
#include <opencv2/opencv.hpp>
#endif

#include <stdexcept>
#include <assert.h>
#include <opencv2/opencv.hpp>
#include <filesystem>

class VolumeData
Expand Down Expand Up @@ -114,6 +117,7 @@ void Volume::fill(uint8_t value)
std::fill_n(d->data, d->voxels, value);
}

#ifdef USE_OPENCV
Volume Volume::loadTif(const std::string &fileName, std::array<float, 3> voxelSize, std::array<float, 3> origin)
{
std::vector<cv::Mat> stack;
Expand Down Expand Up @@ -161,6 +165,7 @@ void Volume::saveTif(const std::string &fileName) const
if (!cv::imwritemulti(fileName, stack))
throw std::runtime_error("Could not save tif stack at " + fileName);
}
#endif // USE_OPENCV

#ifdef USE_H5
Volume Volume::loadH5(const std::string &fileName, std::string name)
Expand Down
2 changes: 2 additions & 0 deletions NanoMito3D/Volume.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ class Volume final
// fill the volume with value
void fill(uint8_t value);

#ifdef USE_OPENCV
// load a tiff stack as volume
static Volume loadTif(const std::string &fileName, std::array<float,3> voxelSize = {1.f,1.f,1.f}, std::array<float,3> origin = {0.f});
void saveTif(const std::string &fileName) const;
#endif // USE_OPENCV

#ifdef USE_H5
// load and save volume as h5 file
Expand Down
Loading

0 comments on commit dd721d4

Please sign in to comment.