Спонсор: Intel
Опубликован: 23.08.2014 | Уровень: для всех | Доступ: платный | ВУЗ: Северный (Арктический) федеральный университет им. М.В. Ломоносова
Лабораторная работа 2:

Интеграция возможностей модулей Intel Perceptual Computing SDK для реализации многоуровневой системы информационной безопасности, основанной на биометрической информации

< Лекция 4 || Лабораторная работа 2: 123 || Лекция 5 >

Реализация метода распознавания речи

Для того чтобы создать метод распознавания речи нам потребуется новая форма Form2.cs. Добавьте на нее menuStrip1, три кнопки button1, button2, button3, а также treeView1 и treeView2. В menuStrip1 сделайте 1 пункт "Источник", который будет аналогом пункта меню "Devices" из MainForm.


Рис. 4.9.

По аналогии обработайте событие нажатия кнопки button4 формы mainmenu и button2 формы Form1 так, чтобы вызывалась форма Form2.

private void button2_Click(object sender, EventArgs e)
    {             
        PXCMSession session;
        pxcmStatus sts = PXCMSession.CreateInstance(out session);
        if (sts >= pxcmStatus.PXCM_STATUS_NO_ERROR)
        {
            Form2 f2 = new Form2(session,this);
            f2.Show();
            session.Dispose();
        }
    }
        
private void button4_Click(object sender, EventArgs e)
    {          
        PXCMSession session;
        pxcmStatus sts = PXCMSession.CreateInstance(out session);
        if (sts >= pxcmStatus.PXCM_STATUS_NO_ERROR)
        {
            Form2 f2 = new Form2(session,this);
            f2.Show();                
            session.Dispose();
        }
    }
        

Соответсвенно, форма Form2 должна иметь два конструктора:

        Form1 f1;
        mainmenu mm1;
        public Form2(PXCMSession session, Form1 form1) //recognition
        {
            InitializeComponent();
            this.session = session;
            this.f1 = form1;
            PopulateSource();
        }

        public Form2(PXCMSession session, mainmenu mainmenu1) // creating
        {
            InitializeComponent();
            this.session = session;
            this.mm1 = mainmenu1;
            PopulateSource();
        }
    

Функция PopulateSource() исходна функции PopulateDeviceMenu() MainForm, которая отображает список приборов, которые можно использовать.

private void PopulateSource()
        {
            PXCMSession.ImplDesc desc = new PXCMSession.ImplDesc();
            desc.group = PXCMSession.ImplGroup.IMPL_GROUP_SENSOR;
            desc.subgroup = PXCMSession.ImplSubgroup.IMPL_SUBGROUP_AUDIO_CAPTURE;
            ToolStripMenuItem sm = new ToolStripMenuItem("Источник");
            for (uint i = 0; ; i++)
            {
                PXCMSession.ImplDesc desc1;
                if (session.QueryImpl(ref desc, i, out desc1) < pxcmStatus.PXCM_STATUS_NO_ERROR) break;
                PXCMCapture capture;
                if (session.CreateImpl<PXCMCapture>(ref desc1, PXCMCapture.CUID, out capture) < pxcmStatus.PXCM_STATUS_NO_ERROR) 
                continue;
                for (uint j = 0; ; j++)
                {
                    PXCMCapture.DeviceInfo dinfo;
                    if (capture.QueryDevice(j, out dinfo) < pxcmStatus.PXCM_STATUS_NO_ERROR) break;
                    ToolStripMenuItem sm1 = new ToolStripMenuItem(dinfo.name.get(), null, new EventHandler(RadioCheck));
                    sm.DropDownItems.Add(sm1);
                }
                capture.Dispose();
            }
            if (sm.DropDownItems.Count > 0)
                (sm.DropDownItems[0] as ToolStripMenuItem).Checked = true;
            menuStrip1.Items.RemoveAt(0);
            menuStrip1.Items.Insert(0, sm);
        }
    

Для создания модуля распознавания речи нам понадобится создать свой класс MyUtilMPipeline.cs, наследника класса SDK UtilMPipeline, который имеет доступ к алгоритмам распознавания голоса. Основными функциями будут OnRecognized и OnAlert, для получения событий распознавания и сигналов предупреждения соответсвенно. Переопределим их под свои нужды.

class MyUtilMPipeline : UtilMPipeline
    {
        protected Form2 f2;

        public void SetForm(Form2 f2)
        {
            this.f2 = f2;
        }
        public override void OnRecognized(ref PXCMVoiceRecognition.Recognition data)
        {
            if (data.label < 0)            //если произнесена не команда
                f2.PrintWord(data.dictation);      //продиктованное предложение      
        }
        public override void OnAlert(ref PXCMVoiceRecognition.Alert data)
        {
            f2.PrintStatus(f2.GetStatus(data.label)); 
        }
    }
    

PXCMVoiceRecognition.Alert data.label может принимать значение из ограниченного множества:

public string GetStatus(PXCMVoiceRecognition.Alert.Label label)
        {
            switch (label)
            {
                case PXCMVoiceRecognition.Alert.Label.LABEL_SNR_LOW: return "Слишком сильный посторонний шум";
                case PXCMVoiceRecognition.Alert.Label.LABEL_SPEECH_UNRECOGNIZABLE: return "Не удалось распознать речь";
                case PXCMVoiceRecognition.Alert.Label.LABEL_VOLUME_HIGH: return "Громкость речи слишком высокая";
                case PXCMVoiceRecognition.Alert.Label.LABEL_VOLUME_LOW: return "Громкость речи слишком низкая";
            }
            return "Error";
        }
    

Чтобы продиктованное слово и соответствующий статус появлялись в treeView на форме Form2 используются функции PrintWord,PrintStatus, которые реализуем с помощью делегатов, похожими на функцию UpdateStatus формы MainForm

private delegate void TreeViewAddDelegate(string word);
        public void PrintWord(string word)
        {
            treeView1.Invoke(new TreeViewAddDelegate(delegate(string word1) { treeView1.Nodes.Add(word1).EnsureVisible(); }), 
            new object[] { word });
        }

        public void PrintStatus(string status)
        {            
            treeView2.Invoke(new TreeViewAddDelegate(delegate(string status1) { treeView2.Nodes.Add(status1); }), 
            new object[] { status });
        }
    

При нажатии на кнопку button1 формы Form2, аналогично кнопке Start формы MainForm, создадим новый поток, в котором будет выполняться функция по распознаванию речи.

private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button2.Enabled = true;
            menuStrip1.Enabled = false;
            stop = false;
            System.Threading.Thread thread = new System.Threading.Thread(VoiceRecognitionWork);
            thread.Start();
            System.Threading.Thread.Sleep(5);
        }
private delegate void VoiceRecognitionWorkCompleted();
        private void VoiceRecognitionWork()
        {
            voice_recognition.Listen(this);
            this.Invoke(new VoiceRecognitionWorkCompleted(
                delegate
                {
                    button1.Enabled = true;
                    button2.Enabled = false;
                    menuStrip1.Enabled = true;
                    if (closing) Close();
                }
                ));
        }
    

Осталось реализовать метод Listen нового класса voice_recognition.cs, который будет использовать экземпляр класса MyUtilMPipeline для работы с модулем распознавания речи.

class voice_recognition
    {
        public static void Listen(Form2 form2)
        {
            Form2 f2 = form2;            
            PXCMSession session;
            pxcmStatus sts = PXCMSession.CreateInstance(out session);  //создаем сессию         
            if (sts < pxcmStatus.PXCM_STATUS_NO_ERROR)
            {
                f2.PrintStatus("Не удалось загрузить сессию SDK");
                return;
            }

            MyUtilMPipeline myUMP = new MyUtilMPipeline();//создаем экземпляр класса
            myUMP.SetForm(f2); //устанавливаем форму            
            myUMP.QueryCapture().SetFilter(f2.GetSource());//выбираем отмеченное устройство

            //Loading Voice Recognition module
            PXCMSession.ImplDesc desc = new PXCMSession.ImplDesc();
            desc.cuids[0] = PXCMVoiceRecognition.CUID;
            PXCMSession.ImplDesc desc1;
            if (session.QueryImpl(ref desc, 0, out desc1) < pxcmStatus.PXCM_STATUS_NO_ERROR)
            {
                f2.PrintStatus("Не удалось загрузить модуль распознования речи");
                session.Dispose();
                return;
            }                   
          
            myUMP.EnableVoiceRecognition(desc1.friendlyName.get());// включаем распознавание голоса с выбранным устройством

            myUMP.SetProfileIndex(0); //выбираем профиль по умолчанию

            myUMP.SetVoiceDictation();// выбираем режим диктора

            f2.PrintStatus("Иницилизация...");
            if (myUMP.Init())
            {
                myUMP.QueryCapture().device.SetProperty(PXCMCapture.Device.Property.PROPERTY_AUDIO_MIX_LEVEL, 0.3f); // устанавливаем уровень записи микрофона (от 0 до 1)

                while (!f2.IsStop())
                {
                    if (!myUMP.AcquireFrame(true))
                        break;
                    myUMP.ReleaseFrame();
                }
            }
            else
            {
                f2.PrintStatus("Иницилизация закончилась неудачно");
            }

            myUMP.Close();
            myUMP.Dispose();
            f2.PrintStatus("Остановлено");

        }
    }
    
Листинг .

Функция AcquireFrame ждет нового доступного кадра, затем блокирует его для обработки приложением. Приложение должно снять блокировку, вызвав функцию ReleaseFrame. После этого начинается обработка последующих кадров.

Чтобы остановить процесс, необходимо обработать событие нажатия кнопки button2 формы Form2 аналогично кнопки Stop формы MainForm

private void button2_Click(object sender, EventArgs e)
        {
            stop = true;
        }

        public bool IsStop()
        {
            return stop;
        }
    

Продиктованное слово или короткое предложение будет появляться в treeView1.


Рис. 4.10.

Теперь необходимо, чтобы при нажатии кнопки button3, выбранное слово сохранялось. В случае создания пользователя передавалось в форму mainmenu, в случае авторизации - на форму Form1.

private void button3_Click(object sender, EventArgs e)
        {
            //проверить на выбранное слово
            if (treeView1.SelectedNode == null)
            {
                MessageBox.Show("Выберите слово из списка распознанных");
                return;
            }
            else
            {
                button2_Click(sender, e); //останавливаем
                //проверяем каким конструктором создан экземпляр формы
                if (f1 == null) //creating
                {
                    mm1.UpdateSecretword(treeView1.SelectedNode.Text);
                }
                else
                { //auth
                    string word = treeView1.SelectedNode.Text;
                    f1.UpdateDataFromVoiceRecognition(word);                
                }    
                stop = true;
                closing = true;
            }
        }
    

Объединение модулей в программе

Последним шагом создания приложения будет завершения процесса создания нового пользователя, путем собрания всех данных и созданием записи в базе данных, а также проверки организация процесса авторизации.

За процесс создания нового пользователя отвечает событие нажатия на кнопку button5 формы mainmenu:

private void button5_Click(object sender, EventArgs e)
        {
            username = textBox1.Text;
            password = textBox2.Text;
            //проверка на наличие букв и добавления кодового слова            
            if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password) || string.IsNullOrWhiteSpace(secretword))
            {
                MessageBox.Show("Заполните все поля и данные");
                return;
            }
            //создадим хэш от пароля и кодового слова, чтобы не хранить их в БД в //открытом виде, а также приведя строки к длине в 44 символа, в независимости от длины //исходной строки
            password = GetSHA256Hash(password);
            secretword = GetSHA256Hash(secretword);
            
            /* Нахождение строки источника данных БД для подключения, указываем ту, что появилась при создании БД.
Альтернативно можно прописать абсолютный путь к БД, например:
conString = @"Data Source=C:\Users\1\Desktop\intel perceptual computing sdk\practice 2\MyDB1.sdf"; */
            string conString = practice_2.cs.Properties.Settings.Default.MyDatabase_1ConnectionString;
            using (SqlCeConnection con = new SqlCeConnection(conString))            
            {
                con.Open();
                var rowId = new SqlCeCommand("SELECT TOP(1) id FROM users ORDER BY Id DESC", con).ExecuteScalar();//выбирем максимыльнай id в таблице
                using (SqlCeCommand com = new SqlCeCommand("INSERT INTO users VALUES(@Id,@Username,@Password,@Secretword)", con))//создадим запись с новым пользователм
                {
                    int newid = Convert.ToInt32(rowId) + 1;                   
                    com.Parameters.AddWithValue("@Id", newid);
                    com.Parameters.AddWithValue("@Username", username);
                    com.Parameters.AddWithValue("@Password", password);
                    com.Parameters.AddWithValue("@Secretword", secretword);
                    com.ExecuteNonQuery();
                }
                label2.Text = username;
            }
            this.Width = 265;
        }

private string GetSHA256Hash(string s) //создания хэша от строки
        {
            if (string.IsNullOrEmpty(s))
            {
                throw new ArgumentException("An empty string value cannot be hashed.");
            }

            Byte[] data = System.Text.Encoding.UTF8.GetBytes(s);
            Byte[] hash = new SHA256CryptoServiceProvider().ComputeHash(data);
            return Convert.ToBase64String(hash);
        }
    
Листинг .

Подключите соответствующие пространства имен

using System.Data.SqlServerCe;
using System.Security.Cryptography;
    

За процесс авторизации отвечает функция обработки события нажатия кнопки button3 формы Form1:

private void button3_Click(object sender, EventArgs e)
        {
            username = textBox1.Text;
            password = textBox2.Text;
            //проверка на получение информации с модуля распознавания лиц и модуля //распознвания голоса
            if (nameFromFaceRegognition == null || wordFromVoiceRegognition == null || password == null || username == "Guest")
            {
                MessageBox.Show("Недостаточно данных для авторизации");
                return;
            }

            password = GetSHA256Hash(password);
            wordFromVoiceRegognition = GetSHA256Hash(wordFromVoiceRegognition);
            string nameFromVoiceRecognition = null;
            /* Нахождение строки источника данных БД для подключения, указываем ту, что появилась при создании БД.
Альтернативно можно прописать абсолютный путь к БД, например:
conString = @"Data Source=C:\Users\1\Desktop\intel perceptual computing sdk\practice 2\MyDB1.sdf"; */
            string conString = practice_2.cs.Properties.Settings.Default.MyDatabase_1ConnectionString;
            using (SqlCeConnection con = new SqlCeConnection(conString))                      {
                con.Open();
          //поиск пользователя на основе пароля и информации с модуля распознавания речи  
                using (SqlCeCommand com1 = new SqlCeCommand("SELECT Username FROM users WHERE Password=@Password AND Secretword=@Secretword", con))
                {                    
                    com1.Parameters.AddWithValue("@Password", password);
                    com1.Parameters.AddWithValue("@Secretword", wordFromVoiceRegognition);
                    SqlCeDataReader reader = com1.ExecuteReader();
                    while (reader.Read())
                    {
                        nameFromVoiceRecognition = reader.GetString(0);                        
                    }
                }
            }
//сравнивание имен пользователей
            if (nameFromFaceRegognition != null && nameFromVoiceRecognition != null)
            {
                if (nameFromFaceRegognition == nameFromVoiceRecognition)
                {
                    textBox1.Text = nameFromFaceRegognition;
                    MessageBox.Show("Вы успешно авторизованы как " + nameFromFaceRegognition);
                    mm1.SetAuthUsername(nameFromFaceRegognition);
                    Close();
                    return;
                }

            }
            MessageBox.Show("Ошибка авторизации. Не верные данные");
        }
    
Листинг .

Дополнительные задания:

  1. Введите дополнительный параметр в метод идентификации человека, такой как "уровень соответсвия"
  2. Введите дополнительную характеристику "Жест" при создании и авторизации пользователя на основе модуля распознавания жестов
< Лекция 4 || Лабораторная работа 2: 123 || Лекция 5 >
Дмитрий Юнушкин
Дмитрий Юнушкин

В лабораторной работе №2 (идентификация лица) сказано:

в FaceTracking.cs: удалим или закомментируем функцию SimplePipelineкласс MyUtilMPipeline и изменим функцию AdvancedPipeline...

Класса MyUtilMPipeline  нет в проекте вообще;

Функции AdvancedPipeline так же нет. Материалов к лабораторной  №2 в начале работы (по ссылке открывается та же страница) тоже нет.Это ошибки или используется другая версия примера?

Анатолий Федоров
Анатолий Федоров
Россия, Москва, Московский государственный университет им. М. В. Ломоносова, 1989
Дмитрий Юнушкин
Дмитрий Юнушкин
Россия, г. Пенза