ConfusionMatrix

This commit is contained in:
Paul Leroy
2022-12-14 11:37:29 +01:00
parent 6de0370073
commit 75288dbc52
4 changed files with 175 additions and 7 deletions
+94
View File
@@ -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
}
+29
View File
@@ -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
+34
View File
@@ -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
View File
@@ -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;
}