mirror of
https://github.com/dgirardeau/q3DMASC.git
synced 2026-08-31 01:20:53 +08:00
ConfusionMatrix
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
#include "confusionmatrix.h"
|
||||
#include "ui_confusionmatrix.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
ConfusionMatrix::ConfusionMatrix(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::ConfusionMatrix)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
ConfusionMatrix::~ConfusionMatrix()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConfusionMatrix::compute_precision_recall_f1_score(cv::Mat& confusion_matrix, cv::Mat& precision_recall_f1_score)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ConfusionMatrix::compute(std::vector<ScalarType> &reality, std::vector<ScalarType> &predicted)
|
||||
{
|
||||
std::set<ScalarType> classes(reality.begin(), reality.end());
|
||||
int idx_actual;
|
||||
int idx_predicted;
|
||||
int nbClasses = classes.size();
|
||||
int actual_class;
|
||||
int predicted_class;
|
||||
cv::Mat confusion_matrix(nbClasses, nbClasses, CV_32S, cv::Scalar(0));
|
||||
cv::Mat precision_recall_f1_score(nbClasses, 3, CV_32F, cv::Scalar(0));
|
||||
|
||||
for (int i = 0; i < reality.size(); i++)
|
||||
{
|
||||
actual_class = reality.at(i);
|
||||
idx_actual = std::distance(classes.begin(), classes.find(actual_class));
|
||||
predicted_class = predicted.at(i);
|
||||
idx_predicted = std::distance(classes.begin(), classes.find(predicted_class));
|
||||
confusion_matrix.at<int>(idx_actual, idx_predicted)++;
|
||||
}
|
||||
// update the qTableWidget
|
||||
this->ui->tableWidget->setColumnCount(nbClasses + 2);
|
||||
this->ui->tableWidget->setRowCount(nbClasses + 2);
|
||||
for (uint row = 0; row < nbClasses; row++)
|
||||
for (uint column = 0; column < nbClasses; column++)
|
||||
{
|
||||
QTableWidgetItem *newItem = new QTableWidgetItem(QString::number(confusion_matrix.at<int>(row, column)));
|
||||
if (row == column)
|
||||
newItem->setBackground(QColor(37, 190, 147, 1)); // green
|
||||
else
|
||||
newItem->setBackground(QColor(255, 129, 129, 1));
|
||||
this->ui->tableWidget->setItem(row + 2, column + 2, newItem);
|
||||
}
|
||||
|
||||
std::set<ScalarType>::iterator itB = classes.begin();
|
||||
std::set<ScalarType>::iterator itE = classes.end();
|
||||
std::vector<ScalarType> vtr;
|
||||
vtr.assign(itB, itE);
|
||||
QTableWidgetItem *newItem = nullptr;
|
||||
|
||||
// set the row andd column names
|
||||
newItem = new QTableWidgetItem(QString::number(vtr[1]));
|
||||
this->ui->tableWidget->setItem(3, 1, newItem);
|
||||
this->ui->tableWidget->setSpan(0, 2, 1, 2);
|
||||
this->ui->tableWidget->setSpan(2, 0, 2, 1);
|
||||
newItem = new QTableWidgetItem("Predicted");
|
||||
QFont font(newItem->font());
|
||||
font.setBold(true);
|
||||
newItem->setFont(font);
|
||||
newItem->setBackground(Qt::lightGray);
|
||||
this->ui->tableWidget->setItem(0, 2, newItem);
|
||||
newItem = new QTableWidgetItem("True");
|
||||
newItem->setFont(font);
|
||||
newItem->setBackground(Qt::lightGray);
|
||||
this->ui->tableWidget->setItem(2, 0, newItem);
|
||||
|
||||
// add data to the QTableWidget
|
||||
for (int idx = 0; idx < vtr.size(); idx++)
|
||||
{
|
||||
QString str = QString::number(vtr[idx]);
|
||||
newItem = new QTableWidgetItem(str);
|
||||
newItem->setFont(font);
|
||||
this->ui->tableWidget->setItem(1, 2 + idx, newItem);
|
||||
newItem = new QTableWidgetItem(str);
|
||||
newItem->setFont(font);
|
||||
this->ui->tableWidget->setItem(2 + idx, 1, newItem);
|
||||
}
|
||||
|
||||
// compute precision recall F1-score
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef CONFUSIONMATRIX_H
|
||||
#define CONFUSIONMATRIX_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "CCTypes.h"
|
||||
|
||||
#include <opencv2/core/mat.hpp>
|
||||
|
||||
namespace Ui {
|
||||
class ConfusionMatrix;
|
||||
}
|
||||
|
||||
class ConfusionMatrix : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfusionMatrix(QWidget *parent = nullptr);
|
||||
~ConfusionMatrix();
|
||||
|
||||
void compute_precision_recall_f1_score(cv::Mat& confusion_matrix, cv::Mat &precision_recall_f1_score);
|
||||
void compute(std::vector<ScalarType>& reality, std::vector<ScalarType>& predicted);
|
||||
|
||||
private:
|
||||
Ui::ConfusionMatrix *ui;
|
||||
};
|
||||
|
||||
#endif // CONFUSIONMATRIX_H
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfusionMatrix</class>
|
||||
<widget class="QWidget" name="ConfusionMatrix">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>575</width>
|
||||
<height>260</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+18
-7
@@ -38,6 +38,8 @@
|
||||
#include <QProgressDialog>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "confusionmatrix.h"
|
||||
|
||||
using namespace masc;
|
||||
|
||||
Classifier::Classifier()
|
||||
@@ -123,13 +125,15 @@ bool Classifier::classify( const Feature::Source::Set& featureSources,
|
||||
//look for the classification field
|
||||
CCCoreLib::ScalarField* classificationSF = Tools::GetClassificationSF(cloud);
|
||||
// add a ccConfidence value if needed
|
||||
int cvConfidenceIdx = cloud->getScalarFieldIndexByName("cvConfidence");
|
||||
int cvConfidenceIdx = cloud->getScalarFieldIndexByName("Classification_confidence");
|
||||
if (cvConfidenceIdx > 0) // if the scalar field exists, delete it
|
||||
cloud->deleteScalarField(cvConfidenceIdx);
|
||||
else
|
||||
cvConfidenceIdx = cloud->addScalarField("cvConfidence");
|
||||
cvConfidenceIdx = cloud->addScalarField("Classification_confidence");
|
||||
CCCoreLib::ScalarField* cvConfidenceSF = cloud->getScalarField(cvConfidenceIdx);
|
||||
|
||||
ccScalarField* classifSFBackup = nullptr;
|
||||
|
||||
if (classificationSF)
|
||||
{
|
||||
//save previous classification field (if any)
|
||||
@@ -139,7 +143,7 @@ bool Classifier::classify( const Feature::Source::Set& featureSources,
|
||||
|
||||
try
|
||||
{
|
||||
ccScalarField* classifSFBackup = new ccScalarField(*static_cast<ccScalarField*>(classificationSF));
|
||||
classifSFBackup = new ccScalarField(*static_cast<ccScalarField*>(classificationSF));
|
||||
classifSFBackup->setName("Classification_prev");
|
||||
cloud->addScalarField(classifSFBackup);
|
||||
}
|
||||
@@ -200,8 +204,7 @@ bool Classifier::classify( const Feature::Source::Set& featureSources,
|
||||
CCCoreLib::NormalizedProgress nProgress(pDlg.data(), cloud->size());
|
||||
|
||||
bool success = true;
|
||||
cv::TermCriteria termCriteria = m_rtrees->getTermCriteria();
|
||||
int numberOfTrees = termCriteria.maxCount;
|
||||
int numberOfTrees = m_rtrees->getRoots().size();
|
||||
#ifndef _DEBUG
|
||||
#if defined(_OPENMP)
|
||||
#pragma omp parallel for
|
||||
@@ -235,13 +238,16 @@ bool Classifier::classify( const Feature::Source::Set& featureSources,
|
||||
m_rtrees->getVotes(test_data, result, cv::ml::DTrees::PREDICT_MAX_VOTE);
|
||||
int classIndex = -1;
|
||||
for (int col = 0; col < result.cols; col++)
|
||||
if (predictedClass == result.at<float>(0, col))
|
||||
if (predictedClass == result.at<int>(0, col))
|
||||
{
|
||||
classIndex = col;
|
||||
break;
|
||||
}
|
||||
if (classIndex != -1)
|
||||
cvConfidenceSF->setValue(i, static_cast<ScalarType>(result.at<float>(1, classIndex) / numberOfTrees));
|
||||
{
|
||||
float nbVotes = result.at<int>(1, classIndex);
|
||||
cvConfidenceSF->setValue(i, static_cast<ScalarType>(nbVotes / numberOfTrees));
|
||||
}
|
||||
else
|
||||
cvConfidenceSF->setValue(i, CCCoreLib::NAN_VALUE);
|
||||
|
||||
@@ -253,6 +259,7 @@ bool Classifier::classify( const Feature::Source::Set& featureSources,
|
||||
}
|
||||
}
|
||||
classificationSF->computeMinAndMax();
|
||||
cvConfidenceSF->computeMinAndMax();
|
||||
|
||||
//show the classification field by default
|
||||
{
|
||||
@@ -267,6 +274,10 @@ bool Classifier::classify( const Feature::Source::Set& featureSources,
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
ConfusionMatrix *confusionMatrix = new ConfusionMatrix();
|
||||
confusionMatrix->compute(*classifSFBackup, *classificationSF);
|
||||
confusionMatrix->show();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user