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


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


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


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



Результат


Программа с графическим интерфейсом с возможностью выбора изображения из списка. После выбора изображение анализируется и после анализа выдается результат в виде надписи 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

Комментарии (6)


  1. AntonSor
    20.10.2019 21:07
    +3

    Прошу прощения. А где на этих фото собственно рисунок вен?


    1. hakain Автор
      21.10.2019 06:09

      Я предполагаю, что рисунок вен делается отдельным датчиком уже после того, как будет определено наличие ладони на сканере. Ну а так, это же просто тестовое задание и практически никакого отношения к реальному сканеру вен не имеет.


      1. 32bit_me
        21.10.2019 15:04

        Тестовое задание в "Прософт-Биометрикс"?


        1. hakain Автор
          22.10.2019 05:49

          Да


  1. questor
    21.10.2019 09:04

    Нет ни одного примера, где расположение точек было бы не "Х", а "+" (и ещё лучше — промежуточные). Фигура должна быть симметричной, поэтому неплохо было бы понять погрешность определения в зависимости от угла наклона к оси абсцисс (от 0 до 90 45)


    Тоже чисто для интереса, ведь задание-то уже сделано и работает.


    1. hakain Автор
      21.10.2019 10:34

      Я решал задачу с учетом того, что расположение точек не может меняться, поскольку думаю, что источники света не меняют своего положения.