ХАКЕР 04 /171/ 2013 Кодим для Kinect под Windows105Аудиосенсор Кинекта позволяет записать 16-битныйзвук с частотой 16 000 герц в секунду. Не CD(там частота 44 100 герц), но тоже неплохотаких значения. И в зависимости от него наша прога краситпиксель определенным цветом. Если значение глубины равноUnknownDepth (неопределенная глубина), пиксель закрашиваетсякрасным: depthColorImage[depthColorImagePos++]= 255;. Обрати внимание: в этой строчке кода, используяпостфиксный инкремент, мы присваиваем значение текущемубайту и сразу же переходим на следующий. Если значениеглубины равно TooFarDepth (слишком далеко), пиксельзакрашивается синим, а если значение равно TooNearDepth(слишком близко), то зеленым. В ином случае, если значениеглубины не равно никакому предопределенному значению,значит, в нем содержатся полезные данные. И в последнейветке условного оператора мы, преобразовав это значение,присваиваем его каждому байту пикселя. Обработка заключаетсяв следующем. Мы имеем значение глубины размером13 бит, этого много для цвета, поэтому надо отбросить 5 бит.В таком случае мы будем иметь недостаточную точность, поэтомуможно сдвинуть только 4 бита. Теперь это значение надовычесть из 255, поскольку данное значение будет слишкомярким, а его вычитание из максимального значения позволитполучить обратный результат, то есть серый, и данный результатбудет значением компонента цвета для пикселя. Послетого как весь цветовой массив глубины будет заполнен,на его основе происходит создание и/или обновление объектакласса WriteableBitmap, который затем выводится на форму.Не буду повторяться, описание этого процесса приведенов предыдущем проекте.АудиопотокДля демонстрации возможностей Кинекта работы со звуком напишемпрогу, которая будет сохранять звуковой поток в файл,а затем по команде пользователя воспроизводить его. Проигрываниезвука осуществим стандартными средствами WPF.Аудиосенсор Кинекта позволяет записать 16-битный звукс частотой 16 000 герц в секунду. Это, конечно, не звук с компакта(там частота 44 100 герц), но все равно довольно высокоекачество. Кстати, четыре встроенных микрофона Кинекта не записываютмногоканальный звук. Множество микрофонов используетсядля определения и удаления шумов из звука, а такжедля определения расположения его источника.Создадим новое WPF-приложение. На форме размести двекнопки: Rec и Play. Также на будущее нам понадобится компонентMediaElement для проигрывания звука. Нам будут нужныследующие глобальные переменные: объект Кинекта, строка —имя файла и буфер для временного хранения звука, размером«время продолжительности (5 секунд), умноженное на частоту (16 000)». В методезагрузки формы нам надо только получить первый Кинект и стартовать его работу,никакие потоки в данном случае привязывать не надо. Не забудь остановитьКинект во время завершения работы. Для простоты будем сохранять звук в WAVфайле— это самое простое средство для хранения звука, которое есть в Windows,так как на диск в данном случае без всякой обработки записывается область памяти.Для приличия к ним присоединяется заголовок (см. исходник). Этот кодне представляет собой ничего нового, поэтому я не буду тратить на него времяи место. Теперь напишем обработчик события нажатия на кнопке «Rec», разместив нем такой код:if (File.Exists(fname)) File.Delete(fname);Thread soundThread = new Thread(new ThreadStart(captureSound));soundThread.Priority = ThreadPriority.Highest;soundThread.IsBackground = true;soundThread.Start();В первой строке проверяем, существует ли файл с таким именем, если да,то удаляем; во второй строке создаем параллельный поток и привязываем к немувыполнение функции captureSound, передавая ссылку на нее конструктору потокав качестве параметра. Таким образом, должны передаваться функции, не принимающиеи не возвращающие аргументов, как в нашем случае. Затем задаютсясвойства потока: назначается наивысший приоритетвыполнения среди потоков данного приложения,свойство IsBackground в значении trueгарантирует завершение дополнительного потокавместе с родительским процессом, в ином случаепришлось бы предусматривать прекращение выполненияданного потока при завершении работыприложения. Последним оператором прога запускаетпоток.Как только начинается его выполнение, он сразу вызывает функциюcaptureSound. Далее приведен ее код и описание:Stream kinectAudioStream = kinect.AudioSource.Start();kinectAudioStream.Read(soundSampleBuffer, 0, soundSampleBuffer.Length);using (var fileStream = new FileStream(fname, FileMode.Create)){WriteWavHeader(fileStream, recordBuffer);fileStream.Write(soundSampleBuffer, 0, soundSampleBuffer.Length);}Сначала запускается прием звуковых данных с Кинекта, плюс метод Start возвращаетссылку на принимаемый поток. Обрати внимание на разницу: видеоданные передавалисьКинектом последовательно — кадр за кадром (со скоростью 30 кадровв секунду), тогда как звук передается непрерывно — потоком. Следующим операторомпрограмма читает данные из приходящего потока и помещает их в массив байт,от его начала заполняя по всей длине. Далее в конструкции using безопасно, с гарантиейзакрытия, создается файл, и в этот файл сперва записывается стандартныйзаголовок WAV-файла, а затем сами данные из байтового массива.В итоге файл под именем wave.wav сохраняется в папке с экзешником. При нажатиикнопки «Play» производится проверка на его существование, при успешномраскладе срабатывает такой код:player.Source = new Uri(fname, UriKind.RelativeOrAbsolute);player.LoadedBehavior = MediaState.Play;где player — это объект класса MediaElement; здесь указывается путь к файлу и задаетсядействие, выполняемое при успешной его загрузке, то есть его проигрывание.Еще один важный момент: когда проигрывание файла завершается (через5 секунд), свойство Source объекта player обнуляется (происходит в событии), чтобыосвободить файл. Это необходимо для дальнейшей работы программы, потомучто она не сможет удалить и/или заменить используемый файл.Рис. 4. Вывод глубиныИТОГИНам удалось затронуть лишь малую часть возможностей Kinect for Windows SDK.Правда, часть эта очень значительна, ведь она играет важную роль в работе устройства.Мы рассмотрели все три присутствующих в Кинекте потока данных. Однакорамки статьи не позволили нам глубже окунуться в программирование для Кинекта— за бортом осталась еще масса материала: слежение за телом, обработка скелета,распознавание голосовых команд, слежение за лицом, определение жестов,реагирование на них и другое. А ведь все это довольно сложные темы, требующиеотдельного изучения. Данная статья изначально задумывалась как вводная, и будемнадеяться, что я останусь в здравом уме и трезвой памяти после ее написания,а редактор выделит мне место под следующую :).
106КодингСЕРИАЛИЗАЦИЯСериализация без напрягаБЕЗ НАПРЯГАPROTOBUF VS. BOOST::SERIALIZATION.НА САМОМ ДЕЛЕ ЗДЕСЬ ТОЛЬКОПРО PROTOBUF, ВЕДЬ У НИХМИЛЛИАРДЫ!ХАКЕР 04 /171/ 2013Все программы работают сданными. Эти данные надо гдетохранить и иногда куда-нибудьпередавать. Для того и другогопридумали много полезного.Но вот часто в самой программемы работаем с этими даннымисовсем в другом виде и намприходится писать много кода,чтобы засейвить состояниеобъектов в ПО. Сегодня мыузнаем, как избежать написаниякилобайтов вспомогательногокода сериализации.deeonisdeeonis@gmail.comДля начала небольшой ликбез. Сериализация —это процесс перевода какой-либо структурыданных в последовательность байт. Эта последовательностьможет быть как бинарнымпредставлением этих данных, так и текстовым.В большинстве случаев сериализация нужна для сохранениясостояния программы на жесткий диск или пересылки какихлибосообщений по сети. Распаковка сериализованных данныхназывается десериализацией.СЕРИАЛИЗАЦИЯ СВОИМИ РУКАМИКогда перед программистом встает задача упаковки структурданных, например для их последующей передачи по сети,у него есть несколько путей, по которым он может пойти. Одиниз них — написать все самому, с нуля. Но и тут перед ним открываетсяразвилка из трех дорог.Самый простой и довольно популярный способ — это представитьвсе данные в виде строк. В этом случае на выходе мыполучим поток ASCII-символов (а может быть, и не ASCII), которыйзатем будет передан по сети или записан в файл. Еслипопробовать набросать схематичный код, то он будет выглядетьпримерно так:Сериализация в строкиclass MyClass{int x;int y;std::string str;public:void MyClass(){x = 120;y = 23;str = "some string"}}std::string save(){std::stringstream out;out