Программерская сигнализацияАндрей «LittleBudda» Шкрыль Хакер, номер #103, стр. 112 (ShkrylAndrei@rambler.ru, www.vr-online.ru) Использование веб-камеры в паранойяльных целях Еще несколько лет назад ныне забытый нынче Даниил Шеповалов советовал настоящим параноикам организовывать программную сигнализацию для компьютера, основанную на веб-камере и программерских талантах вышеупомянутого душевнобольного :). Может быть, кому-то это и показалось шуткой, но лично я воспринял эту информацию всерьез. Ты тоже хочешь, чтобы к твоему компьютеру никогда не получил несанкционированный доступ какой-нибудь космический пришелец с 40-сантиметровым фаллосом? Тогда читай эту статью! Первым делом Итак, нам потребуется web-камера. Для этой статьи я специально приобрел Genius VideoCam Look. Конечно, не самый лучший выбор, но по соотношению «цена/качество», достаточно оптимальный. После установки дров для нового девайса можно приступать к реализации самой системы контроля. Но для начала придется скачать DSPack - это надстройка над DirectShow и DirectX, состоящая из набора компонентов, позволяющих работать с потоками мультимедиа, в том числе и с устройствами видеозахвата (web-камера, ТВ-тюнер и т.д.). DSPack есть на нашем диске и на официальном сайте пакета: www.progdigy.com. Она абсолютно бесплатна и распространяется по лицензии MPL1.1 Установка DSPack - дело пары минут. Распакуй архив, далее выбери Delphi и укажи, что подключаемые модули твоего проекта нужно искать в каталогах \src\Directx9 и \src\DSPack. Теперь откомпилируй пакеты (каталог packages) DirectX9_Dx.dpk и DSPack_Dx.dpk, где x - номер используемой тобой версии Delphi. В качестве финального аккорда отработанным движением установи пакет DSPackDesign_Dx.dpk. Проектируем главную форму Создадим новый проект. Расположим на форме компонент TFilterGraph, назовем его FilterGraph. Свойства Mode компонента обязательно нужно установить в gmCapture, ведь мы будем работать с захватом видео. Теперь немного теории. Основное понятие DirectShow, а как ты помнишь, DSPack базируется именно на нем, - это «граф фильтров» (странное название, но с этим ничего не поделаешь), который включает набор элементов (фильтров), соединенных в определенном порядке и характеризующих источник аудио- и/или видеопотока, а также способ, которым он обрабатывается (например, декодирование потоковых данных). На рисунке ты можешь видеть пример графа фильтров, предназначенного для воспроизведения mp3-файла. Далее нам понадобится TVideoWindow - компонент, который используется для отображения картинки с устройства видеозахвата. В его свойстве FilterGraph установим значение FilterGraph. Обрати внимание на свойство FullScreen этого компонента, если его поставить в True, то видео будет транслироваться на весь экран. Теперь разместим на форме TFilter (компонент для управления фильтром), именно для него мы установим web-камеру в качестве источника видеосигнала. Последним нужным нам компонентом из набора будет TSampleGrabber. С помощью него осуществится захват видеопотока, в его свойство FitlerGraph необходимо установить значение FilterGraph. И последний штрих: разместим TComboBox и рядом с ним - метку, содержащую текст: «Выбери устройство». Главную форму будущей программы ты можешь увидеть на рисунке. Займемся этим Итак, пора подвинуть клавиатуру поближе и приняться за написание кода нашей будущей мегасофтины. Объявим глобальную переменную: VideoDevice: TSysDevEnum; Через нее мы получим список всех устройств (фильтров) видеозахвата, присутствующих в системе. Теперь подключим модули DSUtil и DirectShow9 и для события OnCreate формы напишем следующий обработчик: Определение устройств видеозахвата procedure TForm1.FormCreate(Sender: TObject); var i: integer; begin VideoDevice:= TSysDevEnum.Create(CLSID_VideoInputDeviceCategory); if VideoDevice.CountFilters > 0 then for i := 0 to VideoDevice.CountFilters - 1 do ComboBox1.Items.Add(VideoDevice.Filters[i].FriendlyName); end; Первым делом здесь произойдет инициализация нужного нам интерфейса - CLSID_VideoInputDeviceCategory, описанного в модуле DirectShow9. Затем мы формируем список девайсов в TComboBox. Стоит отметить, что если ты поменяешь первую строчку обработчика на «VideoDevice:= TSysDevEnum.Create(CLSID_VideoCompressorCategory);», то в TComboBox появится список кодеков, установленных в системе. А вот таким способом мы получим описание устройств обработки звука: AudioDevice:= TSysDevEnum.Create(CLSID_CWaveinClassManager); Идем дальше. Нам потребуется обработчик OnChange для компонента TComboBox. Таким образом, после того как пользователь выберет, откуда он хочет получать видео, оно начнет транслироваться. Обращение к устройству видеозахвата procedure TForm1.ComboBox1Change(Sender: TObject); begin FilterGraph.ClearGraph; FilterGraph.Active := false; //Задаем устройство, с которым будем работать Filter1.BaseFilter.Moniker := VideoDevice.GetMoniker(ComboBox1.ItemIndex); FilterGraph.Active := true; //Задаем, что откуда будем получать и куда оно должно выводиться with FilterGraph as ICaptureGraphBuilder2 do RenderStream(@PIN_CATEGORY_PREVIEW, nil, Filter1 as IBaseFilter, SampleGrabber1 as IBaseFilter, VideoWindow1 as IbaseFilter); //Производим вывод изображения FilterGraph.Play; end; В этом участке кода мы вызываем метод GetMoniker() объекта VideoDevice, для того чтобы установить устройство захвата (в DirectShow используется термин «фильтр»). GetMoniker() описан в модуле DSUtil следующим образом: function TSysDevEnum.GetMoniker(index: integer): IMoniker; В качестве результата он возвращает интерфейс IMoniker. Далее происходит активизация графа фильтров (компонент TFilterGraph) и вызывается метод RenderStream(), принадлежащий интерфейсу ICaptureGraphBuilder2. Посредством него мы определяем, какой видеопоток мы хотим обрабатывать и куда он будет выводиться. Описание метода представлено ниже: Интерфейс IcaptureGraphBuilder2 и входящий в него метод RenderStream() ICaptureGraphBuilder2 = interface(IUnknown) ['{93E5A4E0-2D50-11d2-ABFA-00A0C9C6E38D}'] (*** ICaptureGraphBuilder2 methods ***) function SetFiltergraph(pfg: IGraphBuilder): HResult; stdcall; ... ... ... function RenderStream(pCategory, pType: PGUID; pSource: IUnknown; pfCompressor, pfRenderer: IBaseFilter): HResult; stdcall; И последнее, что мы делаем, - это начинаем показ видео с помощью метода Play() компонента TFilterGraph. Размещаем на форме кнопку «Остановить видео», даем ей имя ButtonStopPlay, делаем ее недоступной, а в ее обработчике пишем следующий код: Остановка/возобновление трансляции видео procedure TForm1.ButtonStopPlayClick(Sender: TObject); begin if ButtonStopPlay.Caption='Смотреть видео' then begin FilterGraph.Play; ButtonStopPlay.Caption:='Остановить видео'; end else begin FilterGraph.Stop; ButtonStopPlay.Caption:='Смотреть видео'; end; end; Теперь в обработчике TComboBox последней строчкой добавим: ButtonStopPlay.Enabled:=True; Запустим программу и с гордостью посмотрим на то, что у нас получилось (смотри рисунок). Контролируем периметр Разместим на форме TImage и кнопку «Сделать скриншот», для которой будет задан следующий обработчик: SampleGrabber1.GetBitmap(Image1.Picture.Bitmap); Теперь дело за малым: через равные промежутки времени мы будем получать две картинки, отделенные небольшим интервалом, и проверять, разные ли они. Определим еще один TImage рядом с первым, а под ним - TCheckBox с текстом: «Контроль периметра». Еще потребуется TTimer со свойством Enabled, равным False, и свойством Interval, равным 5000 (5 секунд). Для TCheckBox мы напишем вот такой код: if CheckBox1.Checked then Timer1.Enabled:=true else Timer1.Enabled:=false; Для TTimer создадим обработчик, в котором две картинки будут сравниваться попиксельно и будет считаться количество различий. Если ты теперь запустишь программу, то тебя ждет большой сюрприз. Наведи web-камеру на обычную стену и активизируй функцию контроля периметра. Тебе покажется, что две картинки стены, полученные через разные промежутки времени, практически идентичны, а вот по версии программы они будут отличаться более чем на 60%. Странно, но факт. Честно сказать, меня это очень удивило. Выходом из ситуации здесь является проверка каждого пикселя по системе RGB, то есть перевод цвета из TColor в три составляющие - Red, Green, Blue - и сравнение каждой из них по отдельности для обеих картинок. Если изменения незначительны, можно считать, что их нет вовсе. Код для обработчика TTimer в последнем случае представлен во врезке (полный его вариант ты сможешь найти на диске). Последнее, что тебе потребуется сделать, - это создать в каталоге программы подкаталог Log, в котором будут сохраняться все подозрительные движения по периметру твоего рабочего стола. Запускай программу и наслаждайся результатом. Послесловие Высокими технологиями сейчас мало кого удивишь, хотя при желании это по силам даже обычному программисту. На днях, копаясь в интернете, я нашел отличную библиотеку, позволяющую по фото человека или даже в режиме реального времени по видео с web-камеры определить, кто он. Сразу вспомнились шпионские боевики, и перспектива сотворить нечто подобное на своем домашнем компе, считавшаяся ранее чем-то невозможным и фантастичным, показалась очень заманчивой. Тебе интересно? Тогда посети www.neurotechnologija.com и обязательно загляни в раздел Download. Неплохое продолжение темы работы с web-камерой, не правда ли? А еще это отличная фишка, которой можно удивить коллег по работе или даже босса (по крайне мере их внимание в течении дня тебе обеспечено). Для эксперимента можешь скачать программу VeriLook algorithm demo (www.neurotechnologija.com/download/vlook.zip), в ней все элементарно: пункт меню «оооо\аааааа» сохраняет фото человека в базе, а пункт «аааа\аааа» сравнивает нужную тебе картинку с эталонными изображениями, полученными на предыдущем шаге. DVD На DVD лежат полные исходные коды программы, рассмотренной в статье, а также набор компонентов DSPack. WWW www.progdigy.com - официальный сайт DSPack. http://directshow.wonderu.com – ресурс, полностью посвященный DirectShow. http://vlafy.iulabs.com/rus/index.htm - информация о захвате и обработке видео на компьютере. www.delphiworld.narod.ru/dw.html - более 5000 статей по Delphi самой разнообразной тематики. Функция контроля периметра procedure TForm1.Timer1Timer(Sender: TObject); var //i-координата пикселя по горизонтали i:integer; //j-координата пикселя по вертикали j:integer; //Количество различий k:integer; r1,g1,b1:Byte; r2,g2,b2:Byte; FirstColor,SecondColor:Integer; Color:TColor; PriznakChange:byte; begin //Делаем первый снимок if Timer1.Tag=0 then begin SampleGrabber1.GetBitmap(Image1.Picture.Bitmap); Timer1.Tag:=1; exit; end; //Через некоторое время - второй, с которым будем сверять SampleGrabber1.GetBitmap(Image2.Picture.Bitmap); Timer1.Tag:=0; k:=0; //Начинаем попиксельное сравнение for i := 1 to Image1.Picture.Bitmap.Height do begin for j := 1 to Image1.Picture.Bitmap.Width do begin PriznakChange:=0; //Получаем цвет текущего пикселя первой картинки FirstColor:=Image1.Picture.Bitmap.Canvas.Pixels[i,j]; //Получаем составляющие RGB r1:=GetRValue(FirstColor); g1:=GetGValue(FirstColor); b1:=GetBValue(FirstColor); SecondColor:=Image2.Picture.Bitmap.Canvas.Pixels[i,j]; r2:=GetRValue(SecondColor); g2:=GetGValue(SecondColor); b2:=GetBValue(SecondColor); //Начинаем проверку различий между двумя картинками if Abs(r1-r2)>20 then inc(PriznakChange); if Abs(g1-g2)>20 then inc(PriznakChange); if Abs(b1-b2)>20 then inc(PriznakChange); //Если изменения существенные, то увеличиваем счетчик if PriznakChange=3 then k:=k+1; Application.ProcessMessages; end; end; //Если изменений больше 2000 if k>2000 then begin Memo1.Lines.Add(FormatDateTime('hh:nn:ss',Now)+' зафиксированы изменения по периметру'); Image2.Picture.Bitmap.SaveToFile('log\'+FormatDateTime('hhnnss',Now)+'.bmp'); end; end; Экскурс в историю История web-камеры берет свое начало в компьютерной лаборатории Кембриджа в 90-х годах XX века. Группа ученых лаборатории работала над проектом в области высоких технологий, и все бы хорошо, да вот только кофеварка у них была одна и располагалась она этажом выше. Таким образом, часто возникала ситуация, когда сотрудник, жаждущий насладиться ароматным напитком, сталкивался с банальным фактом отсутствия кофе, что наверняка его порядком расстраивало, так как бегать с этажа на этаж не самое приятное и полезное времяпрепровождение для ученого. Разрешить ситуацию удалось очень просто: один из компьютеров имел камеру, которую и направили на так необходимую всем кофеварку. В результате желающие знать, есть ли смысл идти за кофе, запускали на своем компьютере специальное ПО, позволяющее получать картинку с камеры, и решали, стоит ли им подниматься или нет. |