save traces

When the option is selected, overall accuracy, features and classifiers are saved
This commit is contained in:
Paul Leroy
2023-03-22 23:45:19 +01:00
parent 2dd6e19c55
commit ec5507be5b
8 changed files with 244 additions and 54 deletions
+10
View File
@@ -259,6 +259,16 @@
</column> </column>
</widget> </widget>
</item> </item>
<item row="3" column="1">
<widget class="QCheckBox" name="checkBox_keepTraces">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If checked, a directory is created near the parameters file. Each time you click on Run, the features used to train the random forest will be stored and an entry will be created in a specific file to save the metrics associated with the classifier.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Keep traces</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
+15 -4
View File
@@ -89,7 +89,9 @@ float ConfusionMatrix::computeOverallAccuracy(cv::Mat& matrix)
int nbClasses = matrix.rows; int nbClasses = matrix.rows;
float totalTrue = 0; float totalTrue = 0;
float totalFalse = 0; float totalFalse = 0;
float overallAccuracy = 0.;
m_overallAccuracy = 0.0;
for (int realIdx = 0; realIdx < nbClasses; realIdx++) for (int realIdx = 0; realIdx < nbClasses; realIdx++)
{ {
for (int predictedIdx = 0; predictedIdx< nbClasses; predictedIdx++) for (int predictedIdx = 0; predictedIdx< nbClasses; predictedIdx++)
@@ -101,11 +103,11 @@ float ConfusionMatrix::computeOverallAccuracy(cv::Mat& matrix)
} }
} }
if ((totalTrue + totalFalse) != 0) if ((totalTrue + totalFalse) != 0)
overallAccuracy = totalTrue / (totalTrue + totalFalse); m_overallAccuracy = totalTrue / (totalTrue + totalFalse);
else else
overallAccuracy = CCCoreLib::NAN_VALUE; m_overallAccuracy = CCCoreLib::NAN_VALUE;
return overallAccuracy; return m_overallAccuracy;
} }
void ConfusionMatrix::compute(std::vector<ScalarType>& actual, std::vector<ScalarType>& predicted) void ConfusionMatrix::compute(std::vector<ScalarType>& actual, std::vector<ScalarType>& predicted)
@@ -219,3 +221,12 @@ void ConfusionMatrix::compute(std::vector<ScalarType>& actual, std::vector<Scala
this->ui->tableWidget->setItem(2 + realIdx, 2 + nbClasses + F1_SCORE, newItem); this->ui->tableWidget->setItem(2 + realIdx, 2 + nbClasses + F1_SCORE, newItem);
} }
} }
void ConfusionMatrix::setSessionRun(QString session, int run)
{
QString label;
label = session + " / " + QString::number(run);
this->ui->label_sessionRun->setText(label);
}
+2
View File
@@ -29,6 +29,8 @@ public:
void computePrecisionRecallF1Score(cv::Mat& matrix, cv::Mat& precisionRecallF1Score); void computePrecisionRecallF1Score(cv::Mat& matrix, cv::Mat& precisionRecallF1Score);
float computeOverallAccuracy(cv::Mat& matrix); float computeOverallAccuracy(cv::Mat& matrix);
void compute(std::vector<ScalarType>& actual, std::vector<ScalarType>& predicted); void compute(std::vector<ScalarType>& actual, std::vector<ScalarType>& predicted);
void setSessionRun(QString session, int run);
float m_overallAccuracy;
private: private:
Ui::ConfusionMatrix *ui; Ui::ConfusionMatrix *ui;
+14 -49
View File
@@ -13,8 +13,8 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout" rowminimumheight="1,0"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="7"> <item row="0" column="0" colspan="5">
<widget class="QTableWidget" name="tableWidget"> <widget class="QTableWidget" name="tableWidget">
<property name="verticalScrollBarPolicy"> <property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum> <enum>Qt::ScrollBarAlwaysOff</enum>
@@ -36,25 +36,6 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Overall accuracy</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_overallAccuracy">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item row="1" column="2"> <item row="1" column="2">
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
@@ -68,51 +49,35 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="1" column="3"> <item row="1" column="1">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_overallAccuracy">
<property name="enabled">
<bool>false</bool>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Session</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_session">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text"> <property name="text">
<string>-</string> <string>-</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="5"> <item row="1" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label">
<property name="enabled">
<bool>false</bool>
</property>
<property name="font"> <property name="font">
<font> <font>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>Run</string> <string>Overall accuracy</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="6"> <item row="1" column="3">
<widget class="QLabel" name="label_run"> <widget class="QLabel" name="label_sessionRun">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="font">
<font>
<bold>false</bold>
</font>
</property>
<property name="text"> <property name="text">
<string>-</string> <string>-</string>
</property> </property>
+21
View File
@@ -390,6 +390,7 @@ void q3DMASCPlugin::doTrainAction()
trainDlg.minSampleCountSpinBox->setValue(s_params.rt.minSampleCount); trainDlg.minSampleCountSpinBox->setValue(s_params.rt.minSampleCount);
trainDlg.testDataRatioSpinBox->setValue(static_cast<int>(s_params.testDataRatio * 100)); trainDlg.testDataRatioSpinBox->setValue(static_cast<int>(s_params.testDataRatio * 100));
trainDlg.testDataRatioSpinBox->setEnabled(testCloud == nullptr); trainDlg.testDataRatioSpinBox->setEnabled(testCloud == nullptr);
trainDlg.setInputFilePath(inputFilename);
//display the loaded features and let the user select the ones to use //display the loaded features and let the user select the ones to use
trainDlg.setResultText("Select features and press 'Run'"); trainDlg.setResultText("Select features and press 'Run'");
@@ -689,6 +690,26 @@ void q3DMASCPlugin::doTrainAction()
} }
trainDlg.sortByFeatureImportance(); trainDlg.sortByFeatureImportance();
// if the checkbox "Save traces" is checked
if (trainDlg.getSaveTrace())
{
//save the classifier in the trace directory with a generic name depending on the run
QString tracePath = trainDlg.getTracePath();
if (!tracePath.isEmpty())
{
QString outputFilename = tracePath + "/run_" + QString::number(trainDlg.getRun()) + ".txt";
if (masc::Tools::SaveClassifier(outputFilename, features, mainCloudLabel, classifier, m_app->getMainWindow()))
{
m_app->dispToConsole("Classifier succesfully saved to " + outputFilename, ccMainAppInterface::STD_CONSOLE_MESSAGE);
trainDlg.setClassifierSaved();
}
else
{
m_app->dispToConsole("Failed to save classifier file");
}
}
}
} }
} }
+1 -1
View File
@@ -51,7 +51,7 @@ bool Tools::SaveClassifier( QString filename,
const masc::Classifier& classifier, const masc::Classifier& classifier,
QWidget* parent/*=nullptr*/) QWidget* parent/*=nullptr*/)
{ {
//first save the classifier data (same base filename but with the ymal extension) //first save the classifier data (same base filename but with the yaml extension)
QFileInfo fi(filename); QFileInfo fi(filename);
QString yamlFilename = fi.baseName() + ".yaml"; QString yamlFilename = fi.baseName() + ".yaml";
QString yamlAbsoluteFilename = fi.absoluteDir().absoluteFilePath(yamlFilename); QString yamlAbsoluteFilename = fi.absoluteDir().absoluteFilePath(yamlFilename);
+160
View File
@@ -23,6 +23,10 @@
#include <QFileDialog> #include <QFileDialog>
#include <QSettings> #include <QSettings>
#include <QTextStream> #include <QTextStream>
#include <QStandardPaths>
#include <QDateTime>
#include <ccLog.h>
//System //System
#include <assert.h> #include <assert.h>
@@ -36,14 +40,43 @@ Train3DMASCDialog::Train3DMASCDialog(QWidget* parent/*=nullptr*/)
, Ui::Train3DMASCDialog() , Ui::Train3DMASCDialog()
, classifierSaved(false) , classifierSaved(false)
, saveRequested(false) , saveRequested(false)
, traceFileConfigured(false)
, m_traceFile(nullptr)
{ {
setupUi(this); setupUi(this);
QDateTime dateTime = QDateTime::currentDateTime();
m_baseName = "3dmasc_" + dateTime.toString("yyyyMMdd") + "_" + dateTime.toString("hh") + "h" + dateTime.toString("mm");
run = 0;
readSettings();
connect(closePushButton, SIGNAL(clicked()), this, SLOT(onClose())); connect(closePushButton, SIGNAL(clicked()), this, SLOT(onClose()));
connect(savePushButton, SIGNAL(clicked()), this, SLOT(onSave())); connect(savePushButton, SIGNAL(clicked()), this, SLOT(onSave()));
connect(exportToolButton, SIGNAL(clicked()), this, SLOT(onExportResults())); connect(exportToolButton, SIGNAL(clicked()), this, SLOT(onExportResults()));
} }
Train3DMASCDialog::~Train3DMASCDialog()
{
writeSettings();
closeTraceFile();
}
void Train3DMASCDialog::readSettings()
{
QSettings settings;
settings.beginGroup("3DMASC");
bool saveTrace = settings.value("saveTrace", false).toBool();
setCheckBoxSaveTrace(saveTrace);
}
void Train3DMASCDialog::writeSettings()
{
QSettings settings;
settings.beginGroup("3DMASC");
settings.setValue("saveTrace", checkBox_keepTraces->isChecked());
}
void Train3DMASCDialog::clearResults() void Train3DMASCDialog::clearResults()
{ {
resultLabel->clear(); resultLabel->clear();
@@ -189,5 +222,132 @@ void Train3DMASCDialog::onExportResults()
void Train3DMASCDialog::addConfusionMatrix(std::unique_ptr<ConfusionMatrix>& ptr) void Train3DMASCDialog::addConfusionMatrix(std::unique_ptr<ConfusionMatrix>& ptr)
{ {
run++; // increment the run number
ptr->setSessionRun(m_baseName, run);
saveTraces(*ptr);
m_confusionMatrices.push_back(std::move(ptr)); m_confusionMatrices.push_back(std::move(ptr));
} }
void Train3DMASCDialog::setInputFilePath(QString filePath)
{
m_parameterFilePath = filePath;
}
void Train3DMASCDialog::setCheckBoxSaveTrace(bool state)
{
checkBox_keepTraces->setChecked(state);
}
bool Train3DMASCDialog::openTraceFile()
{
QString traceFileName;
QString traceFilePath;
// get currentPath
QFileInfo info(m_parameterFilePath);
QDir parameterDir = QDir(info.path());
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::DirectoryOnly);
dialog.setWindowTitle("Choose a valid directory for the traces");
dialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).at(0));
if (!m_traceFile) // create trace file if it does not exists already
{
m_tracePath = parameterDir.absolutePath() + "/" + m_baseName;
traceFileName = m_baseName + ".txt";
if (!parameterDir.mkdir(m_baseName)) // create a specific directory to store the traces
{
ccLog::Error("impossible to save in the default directory: " + m_tracePath);
// impossible to save in the default directory, you have to propose another path
if(dialog.exec())
m_tracePath = dialog.selectedFiles().at(0);
else
return false;
}
else
ccLog::Print("directory for traces created: " + m_tracePath);
traceFilePath = m_tracePath + "/" + traceFileName;
m_traceFile = new QFile(traceFilePath);
if(!m_traceFile->open(QIODevice::WriteOnly | QIODevice::Text))
{
ccLog::Error("impossible to open trace file: " + traceFilePath);
delete m_traceFile;
m_tracePath.clear();
return false;
}
}
if (m_traceFile && m_traceFile->isOpen())
{
traceFileConfigured = true;
ccLog::Print("save trace in: " + traceFilePath);
m_traceStream.setDevice(m_traceFile);
m_traceStream << "run overallAccuracy\n";
return true;
}
else
return false;
}
bool Train3DMASCDialog::closeTraceFile()
{
if (m_traceFile)
if (m_traceFile->isOpen())
{
ccLog::Print("[3DMASC] traces stored in: " + m_traceFile->fileName());
m_traceFile->close();
}
return true;
}
void Train3DMASCDialog::saveTraces(ConfusionMatrix &confusionMatrix)
{
if (checkBox_keepTraces->isChecked())
{
if (!traceFileConfigured) // if the trace file is not configured yet, do it
{
if (!openTraceFile())
return;
}
else // save the trace
{
// save the run number and the overall accuracy
if (m_traceStream.device())
m_traceStream << run << " " << confusionMatrix.m_overallAccuracy << Qt::endl;
// save the confusion matrix
// save the features
// save the classifier
}
}
}
bool Train3DMASCDialog::getSaveTrace()
{
return checkBox_keepTraces->isChecked();
}
QString Train3DMASCDialog::getTracePath()
{
if (traceFileConfigured)
{
QFileInfo fi(*m_traceFile);
return fi.absoluteDir().absolutePath();
}
else if (openTraceFile())
{
QFileInfo fi(*m_traceFile);
return fi.absoluteDir().absolutePath();
}
else
return QString();
}
int Train3DMASCDialog::getRun()
{
return run;
}
+21
View File
@@ -19,6 +19,8 @@
//Qt //Qt
#include <QDialog> #include <QDialog>
#include <QFile>
#include <QTextStream>
#include <ui_Train3DMASCDialog.h> #include <ui_Train3DMASCDialog.h>
@@ -33,6 +35,10 @@ public:
//! Default constructor //! Default constructor
Train3DMASCDialog(QWidget* parent = nullptr); Train3DMASCDialog(QWidget* parent = nullptr);
~Train3DMASCDialog();
void readSettings();
void writeSettings();
void clearResults(); void clearResults();
@@ -54,6 +60,14 @@ public:
inline bool shouldSaveClassifier() const { return saveRequested; } inline bool shouldSaveClassifier() const { return saveRequested; }
void addConfusionMatrix(std::unique_ptr<ConfusionMatrix>& ptr); void addConfusionMatrix(std::unique_ptr<ConfusionMatrix>& ptr);
void setInputFilePath(QString filename);
void setCheckBoxSaveTrace(bool state);
bool openTraceFile();
bool closeTraceFile();
void saveTraces(ConfusionMatrix &confusionMatrix);
bool getSaveTrace();
QString getTracePath();
int getRun();
protected slots: protected slots:
@@ -66,4 +80,11 @@ protected: //members
bool classifierSaved; bool classifierSaved;
bool saveRequested; bool saveRequested;
std::vector<std::unique_ptr<ConfusionMatrix>> m_confusionMatrices; std::vector<std::unique_ptr<ConfusionMatrix>> m_confusionMatrices;
bool traceFileConfigured;
QFile *m_traceFile;
QString m_tracePath;
QTextStream m_traceStream;
QString m_parameterFilePath;
QString m_baseName;
uint run;
}; };