Задача определения наличия ладони на сканере вен

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Как-то мне в руки попало тестовое задание. Академический интерес взял верх и я решил посидеть над этой задачкой. Мое решение не претендует на оптимальность и правильность. Мне просто интересно было ее решить.


Исходные данные


Суть задания заключается в следующем — написать программу, которая по изображению снимков со сканера вен ладоней определяет приложена ли ладонь к сканеру.


Исходные данные — несколько снимков с заранее известным результатом.



Результат


Программа с графическим интерфейсом с возможностью выбора изображения из списка. После выбора изображение анализируется и после анализа выдается результат в виде надписи Good или Bad.




Алгоритм


Алгоритм анализа изображения довольно простой. Для начала создал класс ImageAnalyser со следующим интерфейсом


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

Внутри этого класса решил условно разделить изображение на 4 части для каждого источника света. И для каждого изображения расчитать среднюю яркость относительно осей Х и У. Наглядно это продемонстрировано на изображении ниже.



В результате получим восемь графиков со средним уровнем яркости.



Далее нужно произвести анализ этих графиков. Я решил использовать функцию корреляции сравнив полученные графики с некоторым "идеальным" графиком. Идеальный график в данном случае это просто прямоугольник, который я получаю следующим способом:


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;
}

Для сравнения графиков и, соответственно, получения значения корреляции я использовал функцию gsl_stats_correlation, реализацию которого честно украл из GNU Scientific Library.


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;
}

Далее нужно просто проанализировать значения корреляции. Я решил, что если хоть одно значение корреляции меньше 0,5 то ладонь к сенсору не приложена или приложена плохо.


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;
}

Так же из кода видно, что производится анализ уровня яркости — если значение меньше 30, то так же считаем, что ладонь не приложена.


Стек используемых технологий


  • C/C++
  • Qt Creator
  • QtCharts
  • GNU Scientific Library

Исходники


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

Источник: https://habr.com/ru/post/472280/


Интересные статьи

Интересные статьи

Какой самый ценный ресурс на планете? Нефть, вода или может чистый воздух? Самый ценный ресурс, по мнению многих, это время. Его всегда не хватает, люди постоянно куда-то спешат, а лю...
Всем привет! Не так давно на работе в рамках тестирования нового бизнес-процесса мне понадобилась возможность авторизации под разными пользователями. Переход в соответствующий р...
Несмотря на то, что “в коробке” с Битриксом уже идут модули как для SOAP (модуль “Веб сервисы” в редакции “Бизнес” и старше), так и для REST (модуль “Rest API” во всех редакциях, начиная с...
В статье описаны необходимые параметры сервера для оптимальной работы сайта на платформе 1С-Битрикс.
Тут и демо, и документация: cardinfo.online Это API. Вы ему 6 первых цифр банковской карты, оно вам ссылку на логотип банка, его фирменные цвета, бренд (Visa, MasterCard, и т.д.) и прочее в ф...