Загрузка...

Подглядываем через веб-камеру: учимся использовать встроенную веб-камеру в своих целях

Тема в разделе Веб уязвимости создана пользователем Floda 18 май 2018. 705 просмотров

  1. Floda
    Floda Автор темы 18 май 2018 750 10 янв 2018
    Начинаем реализацию: первые досадные огорчения
    Я был очень удивлен и расстроен, когда узнал, что в великом и могучем .NET

    Framework напрочь отсутствует возможность простого взаимодействия с веб-камерами.

    В четвертой версии ситуация улучшилась (для SilverLight-проектов точно появились

    соответствующие классы), но протестировать я их не успел, поскольку пример для

    данной статьи я начал писать еще до официального выхода VS2010 и 4-го .NET’a.



    Практически отчаявшись, я плотно засел в гугле. Результаты поиска по рунету

    меня не вдохновили – все, что я нашел – это ссылки на MSDN и технологию

    DirectDraw. Я даже попробовал набросать простенький примерчик, но из-за

    отсутствия опыта работы с DirectDraw меня постиг облом. У меня получилось

    собрать совсем простенькое приложение, но я так и не смог выловить в нем все

    глюки.

    Еще больше отчаявшись, я принялся шерстить ресурсы наших западных товарищей.

    Проштудировав несколько десятков ссылок, я смог нарыть много вкусностей. Среди

    них были всевозможные примеры и небольшие статейки (американцы не любят много

    писать). Мне даже удалось найти рабочий пример на основе DirectDraw, но, когда я

    увидел код – ужаснулся. Разобраться в нем было тяжело. Поэтому я решил с ним не

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

    примером на DirectDraw, как на глаза мне попался еще один. Автор примера закодил

    целую библиотеку для работы с веб-камерами и другими устройствами видеозахвата,

    используя технологию VFW (Video For Windows).

    Жаль, что проект автора (я про библиотеку) был максимально кастрирован. Все,

    что позволяла сделать библиотека – вывести изображение с веб-камеры. Ни захвата

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

    И тем не менее, мое подсознание решительно сказало мне, что этот проект и

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

    увидел имена знакомых win-сообщений и не менее знакомых названий WinAPI функций.

    Когда-то давным-давно мне приходилось писать приложение для работы с веб-камерой

    на Delphi. Тогда я и столкнулся с этими функциями впервые.

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

    функционалом.





    Взвод, готовность №1
    Вполне возможно, что в одном компе/ноуте может быть несколько веб-камер. За

    примером далеко ходить не надо. Мне по работе часто приходится организовывать

    простенькие видеоконференции. Обычно в них участвуют два человека. Каждого из

    участников снимает отдельная камера. Сами камеры подключены к моему компу. Когда

    я начинаю съемку, то выбираю в программе для работы с видеокамерами нужную в

    настоящий момент камеру. Раз уж мы решили взять камеру под контроль, то обязаны

    разобраться, как получать список установленных устройств видеозахвата и выбрать

    то, с которым будем работать в настоящий момент.

    Для решения этой нехитрой задачи в WindowsAPI предусмотрена функция

    capGetDriverDescription(). Она принимает пять параметров:

    1. wDriverIndex – индекс драйвера видеозахвата. Значение индекса может
    2. варьироваться от 0 до 9;
    3. lpszName – указатель на буфер, содержащий соответствующее имя драйвера;
    4. cbName – размер (в байтах) буфера lpszName;
    5. lpszVer – указатель на буфер, содержащий описание определенного
    6. драйвера;
    7. cbVer – размер буфера (в байтах), в котором хранится описание драйвера.
    В случае успешного выполнения, функция вернет TRUE. Описание функции у нас

    есть, теперь посмотрим, как определить ее в C#. Делается это так:

    [DllImport("avicap32.dll")]

    protected static extern bool capGetDriverDescriptionA (short wDriverIndex, [MarshalAs(UnmanagedType.VBByRefStr)]

    ref String lpszName, int cbName, [MarshalAs(UnmanagedType.VBByRefStr)] ref

    String lpszVer, int cbVer);

    Обрати внимание, что перед тем, как указать имя подключаемой функции, в

    обязательном порядке требуется написать имя DLL, в которой она определена. В

    нашем случае это avicap32.dll.

    Так, функция импортирована, теперь можно написать класс, в котором она будет

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

    стану, покажу лишь код ключевого метода:

    public static Device[] GetAllCapturesDevices()

    {

    String dName = "".PadRight(100);

    String dVersion = "".PadRight(100);

    for (short i = 0; i < 10; i++)

    {

    if (capGetDriverDescriptionA(i,

    ref dName, 100, ref dVersion,

    100))

    {

    Device d = new Device(i);

    d.Name = dName.Trim();

    d.Version = dVersion.Trim();

    devices.Add(d);

    }

    }

    return (Device[])devices.ToArray

    (typeof(Device));

    }

    Код выглядит проще некуда. Самое интересное место в нем – цикл, в котором

    происходит вызов упомянутой выше функции capGetDriverDescription. Из MSDN мы

    знаем, что индекс (первый параметр функции capGetDriverDescription()) может

    варьироваться от 0 до 9, поэтому мы целенаправленно запускаем цикл в этом

    диапазоне. Результатом выполнения метода будет массив классов Device (этот класс

    я определил самостоятельно, смотри соответствующие исходники).

    С получением списка устройств разобрались, теперь позаботимся об отображении

    видеопотока с камеры. Тут нам сослужит хорошую службу функция

    capCreateCaptureWindow(), предназначенная для создания окна захвата.

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

    происходить путем банальной отправки сообщений окну захвата. Да, именно так,

    придется воспользоваться до боли знакомой windows-программисту (и приколисту)

    функцией SendMessage().

    Теперь присмотримся внимательнее к функции capCreateCaptureWindow(). Ей

    требуется передать шесть аргументов:

    1. lpszWindowName – нуль-терминальная строка, содержащая имя окна захвата;
    2. dwStyle – стиль окна;
    3. x – координата X;
    4. y – координата Y;
    5. nWidth – ширина окна;
    6. nHeight – высота окна;
    7. hWnd – handle родительского окна;
    8. nID – идентификатор окна.
    Результатом выполнения функции будет handle созданного окна или NULL в случае

    ошибки. Поскольку эта функция также относится к WinAPI, то ее опять-таки нужно

    импортировать. Код импортирования приводить не буду, поскольку он практически

    идентичен тому, что я писал для функции capGetDriverDescription(). Лучше сразу

    взглянем на процесс инициализации камеры:

    deviceHandle = capCreateCaptureWindowA (ref deviceIndex, WS_VISIBLE |

    WS_CHILD, 0, 0, windowWidth, windowHeight, handle, 0);

    if (SendMessage(deviceHandle, WM_CAP_DRIVER_CONNECT, this.index, 0) > 0)

    {

    SendMessage(deviceHandle, WM_CAP_SET_SCALE, -1, 0);

    SendMessage(deviceHandle, WM_CAP_SET_PREVIEWRATE, 0x42, 0);

    SendMessage(deviceHandle, WM_CAP_SET_PREVIEW, -1, 0);

    SetWindowPos(deviceHandle, 1, 0, 0, windowWidth, windowHeight, 6);

    }

    В этом коде сразу после создания окна производится попытка отправки сообщения

    WM_CAP_DRIVER_CONNECT. Отличный от нуля результат выполнения функции расскажет

    нам о ее успешности.

    Теперь представим, что сегодня боги на нашей стороне и произведем

    незамедлительную отправку нескольких сообщений: WM_CAP_SET_SCALE,

    WM_CAP_SET_PREVIEWRATE, WM_CAP_SET_PREVIEW. Увы, как и в случае с функциями, C#

    ничего не знает о существовании этих констант. Тебе опять придется определять их

    самостоятельно. Список всех необходимых констант с комментариями я привел ниже.

    //Пользовательское сообщение

    private const int WM_CAP = 0x400;

    //Соединение с драйвером устройства видеозахвата

    private const int WM_CAP_DRIVER_CONNECT = 0x40a;

    //Разрыв связи с драйвером видеозахвата

    private const int WM_CAP_DRIVER_DISCONNECT = 0x40b;

    //Копирование кадра в буффер обмена

    private const int WM_CAP_EDIT_COPY = 0x41e;

    //Включение/отключение режима предпосмотра

    private const int WM_CAP_SET_PREVIEW = 0x432;

    //Включение/отключение режима оверлей

    private const int WM_CAP_SET_OVERLAY = 0x433;

    //Скорость previewrate

    private const int WM_CAP_SET_PREVIEWRATE = 0x434;

    //Включение/отключение масштабирования

    private const int WM_CAP_SET_SCALE = 0x435;

    private const int WS_CHILD = 0x40000000;

    private const int WS_VISIBLE = 0x10000000;

    //Установка callback-функции для preview

    private const int WM_CAP_SET_CALLBACK_FRAME = 0x405;

    //Получение одиночного фрейма с драйвера видеозахвата

    private const int WM_CAP_GRAB_FRAME = 0x43c;

    //Сохранение кадра с камеры в файл

    private const int WM_CAP_SAVEDIB = 0x419;

    Дальнейшее описание класса для работы с веб-камерой я опущу. Каркас я

    рассмотрел, а со всем остальным ты легко разберешься путем раскуривания моего

    хорошо прокомментированного исходника. Единственное, что я не хотел бы оставлять

    за кадром – это пример использования библиотеки.

    Всего в библиотеке я реализовал (точнее, дописал) пару методов: GetAllDevices

    (уже рассматривали), GetDevice (получение драйвера устройства видеозахвата по

    индексу), ShowWindow (отображение изображения с веб-камеры), GetFrame (захват

    отдельного кадра в графический файл) и GetCapture (захват видеопотока).

    В качестве демонстрации работоспособности изготовленной либы я набросал

    небольшое приложение. На форме я расположил один компонент ComboBox

    (используется для хранения списка имеющихся устройств видеозахвата) и несколько

    кнопок – "Обновить", "Пуск", "Остановить" и "Скриншот". Ах да, еще на моей форме

    пестреет компонент Image. Его я применяю для отображения видео с камеры.

    [IMG]


    Разбор полетов начнем с кнопки "Обновить". По ее нажатию я получаю список

    всех установленных устройств видеозахвата. Начинка этого обработчика события:

    Device[] devices = DeviceManager.GetAllDevices();

    foreach (Device d in devices)

    {

    cmbDevices.Items.Add(d);

    }

    Правда, все просто? Разработанная нами библиотека берет на себя все черную

    работу и нам остается лишь наслаждаться объектно-ориентированным

    программированием. Еще проще выглядит код для включения отображения видеопотока

    с камеры:

    Device selectedDevice = DeviceManager.GetDevice(cmbDevices.SelectedIndex);

    selectedDevice.ShowWindow(this.picCapture);

    Опять же, все проще пареной репы. Ну и теперь взглянем на код кнопки "Скриншот":

    Device selectedDevice = DeviceManager.GetDevice(cmbDevices.SelectedIndex);

    selectedDevice.FrameGrabber();

    Я не стал уделять особого внимания методу FrameGrabber(). В моем исходнике

    вызов метода приводит к сохранению текущего кадра прямо в корень системного

    диска. Разумеется, это не очень корректно, поэтому перед боевым применением

    программы не забудь внести все необходимые поправки.





    Готовность № 3
    Теперь настало время поговорить о том, как соорудить простенькую, но надежную

    систему видеонаблюдения. Обычно такие системы базируются на двух алгоритмах:

    различие двух фреймов и простое моделирование фона. Их реализация (код)

    достаточно объемна, поэтому в самый последний момент я решил пойти по более

    простому пути. Под легким путем подразумевается использование мощного, но пока

    малоизвестного фреймворка для .NET – AForge.NET.

    AForge.NET в первую очередь предназначен для разработчиков и исследователей.

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

    проектов для следующих областей: нейросети, работа с изображениями (наложение

    фильтров, редактирование изображений, попиксельная фильтрация, изменение

    размера, поворот изображения), генетика, робототехника, взаимодействие с видео

    устройствами и т.д. С фреймворком поставляется хорошая документация. В ней

    описаны абсолютно все возможности продукта. Не поленись хорошенько с ней

    ознакомиться. Особенно мне хочется отметить качество кода этого продукта. Все

    написано цивильно и копаться в коде – одно удовольствие.

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

    фреймворка она решается как дважды два. "Тогда зачем ты мне парил мозг WinAPI

    функциями?" – недовольно спросишь ты. А за тем, чтобы ты не был ни в чем

    ограничен. Сам ведь знаешь, что проекты бывают разные. Где-то удобнее применить

    махину .NET, а где-то проще обойтись старым добрым WinAPI.

    Вернемся к нашей задачке. Для реализации детектора движений нам придется

    воспользоваться классом MotionDetector из вышеупомянутого фреймворка. Класс

    отлично оперирует объектами типа Bitmap и позволяет быстренько вычислить процент

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

    так:

    MotionDetector detector = new MotionDetector(

    new TwoFramesDifferenceDetector( ),

    new MotionAreaHighlighting( ) );

    //Обработка очередного кадра

    if ( detector != null )

    {

    float motionLevel = detector.ProcessFrame( image );

    if ( motionLevel > motionAlarmLevel )

    {

    flash = (int) ( 2 * ( 1000 / alarmTimer.Interval ) );

    }

    if ( detector.MotionProcessingAlgorithm is BlobCountingObjectsProcessing )

    {

    BlobCountingObjectsProcessing countingDetector = (BlobCountingObjectsProcessing)

    detector.MotionProcessingAlgorithm;

    objectsCountLabel.Text = "Objects: " + countingDetector.ObjectsCount.ToString(

    );

    }

    else

    {

    objectsCountLabel.Text = "";

    }

    }

    }

    [IMG]


    Вышеприведенный код (не считая инициализацию класса MotionDetector) у меня

    выполняется при получении очередного кадра с веб-камеры. Получив кадр, я

    выполняю банальное сравнение (метод ProcessFrame): если значение переменной

    motionlevel больше motionLevelAlarm (0.015f), то значит, надо бить тревогу!

    Движение обнаружено. На одном из скришотов хорошо видна работа демонстрация

    детектора движений.





    Готовность №4
    Веб-камеру можно запросто приспособить для распознавания лиц и создания

    продвинутого способа лог-она в систему? Если переварив весь этот материал, ты

    думаешь, что это сложно, то ты ошибаешься! В конце марта на сайте

    http://codeplex.com (хостинг

    для OpenSource проектов от MS) появился пример (а затем и ссылка на статью),

    демонстрирующий реализацию программы для распознавания лиц с использованием

    веб-камеры. Сам пример основан на использовании новых возможностей .NET и

    SilverLight. Разобрать этот пример в рамках журнальной статьи нереально, так как

    автор исходника постарался и сделал все максимально шикарно. Тут тебе и

    алгоритмы для работы с изображениями (фильтр размытия, уменьшения шума,

    попиксельное сравнение, растяжка и т.д.) и демонстрация новинок SilverLight и

    много чего еще. Одним словом, must use! Ссылку на проект и статью ищи ниже.





    Конец фильма
    Приведенные в статье примеры послужат тебе хорошей отправной точкой. На их

    основе легко сварганить как профессиональную утилиту для работы с веб-камерой, и

    поднимать на ее продаже несколько сотен баксов в квартал или написать хитрого и

    злобного трояна-шпиона.

    Вспомни статью про бэкап

    Skype-бесед. В ней я говорил, что времена клавиатурных шпионов уже прошли.

    Сейчас особенно актуальны аудио и видеоданные. Если учесть, что сегодня

    веб-камера – обязательный атрибут любого ноутбука, то нетрудно представить,

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

    программку"… Однако я тебе этого не говорил :). Удачи в программировании, а

    будут вопросы – пиши.





    WWW
    http://blogs.msdn.com/

    – Русская версия статьи "Silverlight 4 real-time Face Detection"

    (распознавание лиц в реальном времени при помощи SilverLight).



    http://facelight.codeplex.com/ – здесь хостится проект "Facelight",

    позволяющий распознавать лица в реальном времени. Если ты собрался закодить

    серьезную софтину для определения лиц или логона в систему, то посмотреть на

    этот проект просто обязан.



    http://www.aforgenet.com/framework/ – тут ты

    найдешь AForge .NET – отличный и простой в использовании фреймворк для работы с

    видео, изображениями и т.д.

    http://vr-online.ru

    – все исходники примеров, а также кучу дополнительной информации ты

    можешь слить с сайта проекта VR-Online.
     
  2. oraev21
    oraev21 18 май 2018 каво 139 24 фев 2018
    CRTL + C
    CRTL + V
     
  3. Floda
    Floda Автор темы 18 май 2018 750 10 янв 2018
    Ты прям свою жизнь описал
     
  4. erbola119
    erbola119 18 май 2018 AG13 34 6 фев 2018
    найс
     
  5. kyrenie_ybivaet
    Что так много текста:frog_sad:
     
  6. GoSteax
    GoSteax 18 май 2018 Выращиваю овощную грядку, у себя в профиле 43 4 май 2017
    Бля, многа букаф
     
Загрузка...
Top