La tâche de déterminer la présence d'une paume sur un scanner veineux

D'une manière ou d'une autre, je suis tombé entre les mains d'une tâche de test. L'intérêt académique a prévalu et j'ai décidé de m'asseoir sur cette tâche. Ma solution ne prétend pas être optimale et correcte. J'étais juste curieux de le résoudre.


Données source


L'essence de la tâche est d'écrire un programme qui détermine si la paume est attachée au scanner par l'image des images du scanner de la veine de la paume.


Données initiales - plusieurs images avec un résultat connu.



Résultat


Le programme avec une interface graphique avec la possibilité de sélectionner des images dans la liste. Après sélection, l'image est analysée et après analyse, le résultat est affiché sous la forme de l'inscription Bon ou Mauvais .




Algorithme


L'algorithme d'analyse d'image est assez simple. Pour commencer, j'ai créé la classe ImageAnalyser avec l'interface suivante


class ImageAnalyser { public: ImageAnalyser(); explicit ImageAnalyser(const QImage&); bool analyze(const QImage&); bool analyze(); std::vector<std::vector<int>> data(); virtual ~ImageAnalyser(); }; 

Dans cette classe, j'ai décidé de diviser conditionnellement l'image en 4 parties pour chaque source de lumière. Et pour chaque image, calculez la luminosité moyenne par rapport aux axes X et Y. Ceci est clairement démontré dans l'image ci-dessous.



En conséquence, nous obtenons huit graphiques avec un niveau de luminosité moyen.



Ensuite, vous devez analyser ces graphiques. J'ai décidé d'utiliser la fonction de corrélation en comparant les graphiques résultants avec un graphique «parfait». Le graphique idéal dans ce cas est juste un rectangle, que j'obtiens de la manière suivante:


 std::vector<int> ImageAnalyser::prepare_ideal_array(const std::vector<int>& array) { unsigned long min = static_cast<unsigned long>(array.size() * 0); unsigned long max = static_cast<unsigned long>(array.size() * 0.45); int ideal_value = 100; std::vector<int> ideal; ideal.resize(array.size()); for(unsigned long i = min; i < max; ++i) { ideal[i] = ideal_value; } return ideal; } 

Pour comparer les graphiques et, par conséquent, obtenir la valeur de corrélation, j'ai utilisé la fonction gsl_stats_correlation , dont j'ai honnêtement dérobé la mise en œuvre à la bibliothèque scientifique GNU .


 double ImageAnalyser::gsl_stats_correlation(const std::vector<int>& data) { std::vector<int> ideal = prepare_ideal_array(data); const int stride1 = 1; const int stride2 = 1; double sum_xsq = 0.0; double sum_ysq = 0.0; double sum_cross = 0.0; double mean_x = data[0]; double mean_y = ideal[0]; for (unsigned int i = 1; i < data.size(); ++i) { double ratio = i / (i + 1.0); double delta_x = data[i * stride1] - mean_x; double delta_y = ideal[i * stride2] - mean_y; sum_xsq += delta_x * delta_x * ratio; sum_ysq += delta_y * delta_y * ratio; sum_cross += delta_x * delta_y * ratio; mean_x += delta_x / (i + 1.0); mean_y += delta_y / (i + 1.0); } double r = sum_cross / (sqrt(sum_xsq) * sqrt(sum_ysq)); return r; } 

Ensuite, il vous suffit d'analyser les valeurs de corrélation. J'ai décidé que si au moins une valeur de corrélation est inférieure à 0,5, la paume n'est pas attachée au capteur ou est mal attachée.


 bool ImageAnalyser::is_good(const vector<double>& correlation, const vector<int>& maximums) { bool result = true; double min_corr = *std::min_element(correlation.begin(), correlation.end()); if (min_corr < 0.5) { result = false; } double min_val = *std::min_element(maximums.begin(), maximums.end()); if (min_val < 30) { result = false; } return result; } 

Il ressort également du code que l'analyse du niveau de luminosité est effectuée - si la valeur est inférieure à 30, nous pensons également que la paume n'est pas attachée.


Pile de technologies utilisées


  • C / c ++
  • Créateur Qt
  • QtCharts
  • Bibliothèque scientifique GNU

Code source


https://github.com/techlinked/PalmDetector.git

Source: https://habr.com/ru/post/fr472280/


All Articles