Русский
Русский
English
Статистика
Реклама

Recovery mode Распознавание временного ряда в изображении на основе нейросети

Доброго времени суток, хаброжители.

Давно хотел запостить что-нибудь годное на хабр, да не было идеи.

И тут я вспомнил об одном своём проекте, который канул в лету вместе с хранилищем на котором был записан. Это упрощенная модель моей курсовой работы, когда я ее сделал, знаний было в голове ого-го. А теперь приходится все заново вспоминать и делать.

Вообщем в данном проекте будет два различных изображения, которые программа будет распознавать. Оба изображения генерируются программно, с помощью фреймворка qt и c++.

В сумме около 300 строчек кода.

Вот данные изображения:

И второе:

Они размером 400 на 300 пикселей.

Далее в помощь нам будет нейронная сеть состоящая из нейронов, количество нейронов на входе будет столько, сколько классов изображений, количество нейронов на выходе тоже должно соответствовать количеству классов, а поскольку они просты, то всего будет 2 слоя, входящий и выходящий, то есть первый слой будет просто передавать входящий сигнал на входе следующему слою и он будет решать какому классу принадлежит первое или второе изображение.

Какие же сигналы программа будет учитывать?

Поскольку картинки черно-белые, то можно в структуру данных вектор вносить "y" координату встречающегося по пути сверху-вниз первого пикселя не белого цвета, а координата "x" будет и так записана в порядке поступления координат в вектор (400 значений временного ряда). По сути будет одномерный образец изображения, который потом с помощью "квартальной метрики" мы и будем определять у кого меньше, тот нейрон и победил.

Обучать нейроны 2 слоя будем с помощью алгоритма обучения карт Кохонена:

w(t+1)=w(t)-k*|x[i]-w(t)|

k - коэффициент обучения, x[i] - значения по ординате "y" как бы не было смешно, w(t)-весовой коэффициент на данной итерации обучения,w(t+1) - на следующей. Нейроны первого слоя будут передавать входные сигналы каждый своему нейрону 2 слоя, без скрещивания, также функция активации будет отсутствовать(на самом деле она будет тождественна если что x->f(x)->x).

Как полагается создадим нейроны и инициализируем их случайными значениями:

тут точками разбросанными по картинке и есть случайные значения.

Для второго класса:

Далее начнем обучать нейроны по данному алгоритму при коэффициенте обучения k = 0,75 и 2-х итерация обучения:

Как видите точки начали сгущаться около целевого по сути графика

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

При увеличении коэффициента обучения k и увеличении количества итераций случайные величины сольются с графиком и их не будет видно, что даст ошибку в районе 10^-6 и меньше.

Протестируем нашу нейросеть:

sum1 и sum2 - это прямая линия в нулевых координатах "y" слева-направо (добавлена чисто по фану)

v-v - это сработал нейрон обучающийся на V-картинке, дал значение выходного параметра для v 2533.56, что соответственно меньше чем дал нейрон обучающийся w-v 39032.4 поэтому первый нейрон правильно распознал. А в обратном случае тоже правильно: обучающийся нейрон на w дал меньший результат для w чем его коллега. Как видно по итогу прямая линия хуже всего.

А вот результат для 10 итераций обучения и того же коэффициента обучения:

Уже три сотых, что радует.

А вот если прямую провести по центру по горизонтали, то она распознает оба класса лучше, чем нейроны при ошибках 1го рода:

Далее идет код программы main.cpp:

#include <iostream>#include <QtWidgets/QApplication>#include "MainWindow.h"int main(int argc,char*argv[]){    QApplication a(argc, argv);    QWidget qw;    MainWindow mw(&qw);    mw.show();    mw.CreateImage("");    mw.CreateImage2("");    mw.OpenImage("");    mw.OpenImage2("");    return a.exec();}

Neuron.h:

#pragma once#include <ctime>#include <iostream>#include <vector>class Neuron{public:std::vector<double> x,  y, x0;double error;Neuron(std::vector<double> x, int length, int level);int level, length, min_, max_;std::vector<double>  Send();void Lerning(int steps);double Thinking(std::vector<double> xx);std::vector<double> SendW();};

Neuron.cpp:

#include "Neuron.h"Neuron::Neuron(std::vector<double> x,int length,int level){this->x = x;this->length = length;if (level == 2){srand(time(NULL));min_ = 0;max_ = 300;for (size_t i = 0; i < length; i++){x0.push_back(min_ + rand() % (max_ - min_ + 1)); y.push_back(x0[i]);//std::cout << x0[i] << std::endl;}}this->level = level;this->error = 0.0;}std::vector<double> Neuron::Send(){if (level == 1)return this->x;elsereturn this->y;}std::vector<double> Neuron::SendW(){return this->x0;}void Neuron::Lerning(int steps){float k = 0.75;for (size_t j = 0; j < steps; j++){for (size_t i = 0; i < length; i++){x0[i] = x0[i] + k* (x[i]-x0[i]);}}}double Neuron::Thinking(std::vector<double> xx){error = 0.0;for (size_t i = 0; i < length; i++){y[i] = abs(xx[i] - x0[i]);error += y[i];}return error;}

NeuralNet.h

#pragma once#include "Neuron.h"//#include <vector>class NeuralNet{public:std::vector<Neuron*> l1,l2;void InitNeurons(std::vector<double> x, int length);void LearnNeurons(int steps, int i);double TestNeurons(int i, std::vector<double> xx);};

NeuralNet.cpp

#include "NeuralNet.h"void NeuralNet::InitNeurons(std::vector<double> x,int length){l1.push_back(new Neuron(x,length,1));}void NeuralNet::LearnNeurons(int steps,int i){l2.push_back(new Neuron(l1[i]->Send(), l1[i]->length, 2));l2[i]->Lerning(steps);}double NeuralNet::TestNeurons(int i, std::vector<double> xx){double res = 0.0 ;res = l2[i]->Thinking(xx);return res;}

MainWindow.h

#pragma once#include <QtWidgets/qmainwindow.h>#include <QtGui/qpicture.h>#include <QtGui/qimage.h>#include <QtGui/qpainter.h>#include <QtCore/qdebug.h> #include <vector>#include <iostream>#include <fstream> // работа с файлами#include <iomanip> #include "NeuralNet.h"#pragma comment(lib,"Qt5Core.lib")#pragma comment(lib,"Qt5Widgets.lib")#pragma comment(lib,"Qt5Gui.lib")namespace Ui {    class MainWindow;}//Q_OBJECTclass MainWindow : public QMainWindow{    //Q_OBJECTpublic:    explicit MainWindow(QWidget* parent = 0);    void CreateImage(QString path);    void CreateImage2(QString path);    void OpenImage(QString path);    void OpenImage2(QString path);    std::vector<double> x1, x2, zeros1, zeros2;    QImage* image_t1, * image_t2 ;    NeuralNet net;    // ~MainWindow();protected:    void paintEvent(QPaintEvent*); // пееопределение виртуальной функции    private:    Ui::MainWindow* ui;    };

MainWindow.cpp

#include "MainWindow.h"MainWindow::MainWindow(QWidget* parent)    : QMainWindow(parent){    setWindowTitle(tr("Neural"));    setGeometry(0, 0, 1000, 700);}void MainWindow::paintEvent(QPaintEvent*){    QImage img("testImage.png"); // загружаем картинку    QPainter painter(this); // определяем объект painter, который обеспечивает рисование    painter.drawImage(0, 0, img.scaled(this->size())); // рисуем наше изображение от 0,0 и растягиваем по всему виджету}void MainWindow::CreateImage(QString path){    QImage image(QSize(400, 300), QImage::Format_RGB32);    QPainter painter(&image);    painter.fillRect(QRectF(0, 0, 400, 300), Qt::white);    painter.setPen(QPen(Qt::black));    painter.drawLine(0, 0, image.width() / 2, image.height());    painter.drawLine(image.width() / 2, image.height(), image.width(), 0);    image.save("testImage.png");}void MainWindow::CreateImage2(QString path){    QImage image(QSize(400, 300), QImage::Format_RGB32);    QPainter painter(&image);    painter.fillRect(QRectF(0, 0, 400, 300), Qt::white);    painter.setPen(QPen(Qt::black));    painter.drawLine(0, 0, image.width() / 4, image.height());    painter.drawLine(image.width() / 4, image.height() , image.width() / 2, 0);    painter.drawLine(image.width() / 2, 0, 3 * image.width() / 4, image.height());    painter.drawLine(3*image.width() / 4, image.height(), image.width() , 0);    image.save("testImage2.png");}void MainWindow::OpenImage(QString path){    image_t1 = new QImage("testImage.png");    QPoint qp;    std::ofstream fout("data.txt", std::ios_base::out | std::ios_base::trunc);    for (int i = 0; i < image_t1->width(); i++)    {        for (int j = 0; j < image_t1->height(); j++)        {            qp.setX(i);            qp.setY(j);            if (image_t1->pixel(qp) != 4294967295/* 4278190080*/)            {                x1.push_back(j);                zeros1.push_back(abs(150-j));                //qDebug() << j << " ";                fout << j<< std::endl;                break;            }        }    }    qDebug() <<"size:"<< x1.size() << " ";    int sum = 0;    for (int j = 0; j < zeros1.size(); j++)    {        sum += zeros1[j];    }    qDebug() << "sum1=" << sum << " ";    fout.close();        net.InitNeurons(x1, x1.size());    net.LearnNeurons(10,0);    //net.TestNeurons(0);    for (size_t i = 0; i < net.l2[0]->SendW().size(); i++)    {        qp.setX(i);        qp.setY(int(net.l2[0]->SendW()[i]));        image_t1->setPixel(qp, Qt::red);    }    image_t1->save("testImage1-1-1-1-000000.png");    }void MainWindow::OpenImage2(QString path){    image_t2 = new QImage("testImage2.png");    QPoint qp;    std::ofstream fout("data.txt", std::ios_base::out | std::ios_base::trunc);    for (int i = 0; i < image_t2->width(); i++)    {        for (int j = 0; j < image_t2->height(); j++)        {            qp.setX(i);            qp.setY(j);            if (image_t2->pixel(qp) != 4294967295/* 4278190080*/)            {                x2.push_back(j);                fout << j << std::endl;                zeros2.push_back(abs(150 - j));                //qDebug() << j << " ";                break;            }        }    }    qDebug() << "size:" << x2.size() << " ";    int sum = 0;    for (int j = 0; j < zeros2.size(); j++)    {        sum += zeros2[j];    }    qDebug()<<"sum2=" << sum << " ";    fout.close();        net.InitNeurons(x2, x2.size());    net.LearnNeurons(10,1);    qDebug() <<"v - v"<< net.TestNeurons(0, x1);    qDebug() <<"v - w"<< net.TestNeurons(0, x2);    qDebug() <<"w - v"<< net.TestNeurons(1, x1);    qDebug() <<"w - w"<< net.TestNeurons(1, x2);    for (size_t i = 0; i < net.l2[1]->SendW().size(); i++)    {        qp.setX(i);        qp.setY(int(net.l2[1]->SendW()[i]));        //qDebug() << int(net.l2[1]->SendW()[i]) << " ";// std::endl;        image_t2->setPixel(qp, Qt::red);    }    image_t2->save("testImage2-2-2-2-000000.png");    }

Спасибо за внимание!

Источник: habr.com
К списку статей
Опубликовано: 07.05.2021 06:10:51
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Программирование

Нейронная сеть кохонена

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru