Довольно часто возникает необходимость определения движения в видеопотоке (например, в охранных целях — это гораздо дешевле и надёжнее, чем ставить живого оператора). Сегодня я вам расскажу, как написать простенький детектор движения, используя только веб камеру.
Так как у нас, программистов, принято разбивать задачи на подзадачи, то у нас есть две подзадачи: первая — научиться захватывать видео с камеры (для простоты возьмём Web-камеру), а вторая, собственно — определять движение.
Скажу сразу, что писать я буду на Delphi. Кому не нравится — могут не читать.
Итак, без лишних слов, приступим.
Захват видео
Всё зависит от типа вашей камеры. Самые распространённые — это web-камеры. Сегодня они есть почти в каждом ноутбуке. Для захвата видео с веб-камеры существует множество инструментов. Наиболее часто используемый — библиотека AVICAP32.DLL, хотя есть и другие.
Создадим и добавим в проект модуль AviCap32Unit.pas, где опишем внешние функции и константы библиотеки AVICAP32.DLL. Нам понадобятся две функции: capGetDriverDescriptionA и capCreateCaptureWindowA. Для чего они нужны — расскажу позже. Ещё нам нужны 4 сообщения: WM_CAP_START, WM_CAP_DRIVER_CONNECT, WM_CAP_GRAB_FRAME и WM_CAP_STOP.
Код модуля AviCap32Unit:
unit AviCap32Unit;
interface
uses windows,Messages;
const
WM_CAP_START = WM_USER;
WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
WM_CAP_STOP = WM_CAP_START + 68;
function capCreateCaptureWindowA(
lpszWindowName : PAnsiCHAR;
dwStyle : longint;
x : integer;
y : integer;
nWidth : integer;
nHeight : integer;
ParentWin : HWND;
nId : integer): HWND; stdcall external 'AVICAP32.DLL';
function capGetDriverDescriptionA(
wDriverIndex : UINT;
lpszName : LPSTR;
cbName : Integer;
lpszVer : LPSTR;
cbVer : Integer): BOOL; stdcall; external 'AVICAP32.DLL';
implementation
end.
Ну, у нас есть две функции и четыре константы. «Что же с ними делать?» – спросите вы. Можно уже использовать готовые функции, а можно создать класс для работы с Web-камерой. Второй вариант предпочтительней, поскольку вы можете унаследовать ещё класс (например, для IP-камер), в котором механизм захвата устроен по-другому, а нам только надо получить кадр. Напишем модуль CamCaptureUnit. Я думаю, там всё понятно. Если что не понятно — пишите в комментарии.
Код модуля CamCaptureUnit:
unit CamCaptureUnit;
interface
uses Windows,Graphics,AviCap32Unit;
type TCamera=class
protected
FWidth : integer;
FHeight : integer;
FCamIndex : integer;
Fh : THandle;
FName : string;
FVer : string;
public
Constructor Create;
Destructor Destroy; override;
function Start():boolean;
function CaptureBMP(bmp:TBitmap):boolean;
property CamIndex:integer read FCamIndex write FCamIndex;
property Name:string read FName write FName;
property Ver:string read FVer write FVer;
end;
TCamList=class
protected
FList : array of TCamera;
function FGetCount:integer;
function FGetItem(index:integer):TCamera;
public
procedure Emumerate();
property count:integer read FGetCount;
property List[index:integer]:TCamera read FGetItem; default;
end;
implementation
Constructor TCamera.Create;
begin
inherited;
Fh:=0;
FWidth:=640;
FHeight:=480;
end;
Destructor TCamera.Destroy;
begin
if(Fh<>0)then CloseHandle(Fh);
inherited;
end;
function TCamera.Start():boolean;
begin
Fh:=capCreateCaptureWindowA('test',
WS_VISIBLE or WS_CHILD,
10000,
10000,
FWidth,
FHeight,
GetDesktopWindow,
0);
if(fh<>0)then
begin
SendMessage(Fh, WM_CAP_DRIVER_CONNECT, 0, 0);
result:=true;
end else
begin
result:=false;
end;
end;
function TCamera.CaptureBMP(bmp:TBitmap):boolean;
var tdc: HDC;
begin
SendMessage(Fh, WM_CAP_GRAB_FRAME,0,0);
bmp.Width:=FWidth;
bmp.Height:=FHeight;
tdc := GetDC(Fh);
BitBlt(bmp.Canvas.Handle, 0, 0, FWidth, FHeight, tdc, 0, 0, SRCCOPY);
ReleaseDC(Fh, tdc);
result:=true;
end;
function TCamList.FGetCount:integer;
begin
result:=length(FList);
end;
function TCamList.FGetItem(index:integer):TCamera;
begin
result:=FList[index];
end;
procedure TCamList.Emumerate();
var i : integer;
name : array[0..255]of AnsiChar;
ver : array[0..255]of AnsiChar;
cam : TCamera;
begin
for i:=0 to 9 do
begin
if(capGetDriverDescriptionA(i,@name,SizeOf(name),@ver,SizeOf(ver)))then
begin
cam:=TCamera.Create;
cam.Name:=string(name);
cam.Ver:=string(ver);
cam.CamIndex:=i;
SetLength(FList,length(FList)+1);
FList[High(FList)]:=cam;
end;
end;
end;
end.
Как видите, тут есть два класса — TCamera и TCamList. Самый необходимый для нас метод — TCamera.CaptureBMP. Он реализует захват кадра с камеры.
На главной форме располагаем один компонент TImage; — для вывода картинки, один ComboBox — для списка камер, одну кнопку (TButton или любую другую) — для запуска или остановки захвата видео, CheckBox — для запуска или остановки анализатора движения, и ещё таймер — для получения кадров. В private формы опишем список камер: CamList : TCamList; и саму камеру: cam: TCamera;
При создании формы, перебираем камеры в системе:
procedure TMainForm.FormCreate(Sender: TObject);
var i:integer;
begin
CamList:=TCamList.Create;
CamList.Emumerate;
if(CamList.count=0)then
begin
ShowMessage('No cams detected!');
Application.Terminate;
exit;
end;
CamListCB.items.BeginUpdate;
try
CamListCB.items.Clear;
for i:=0 to CamList.count-1 do
CamListCB.items.AddObject(CamList[i].Name,CamList[i]);
CamListCB.ItemIndex:=0;
finally
CamListCB.items.EndUpdate;
end;
end;
При нажатии на «Старт» — запускаем камеру:
procedure TMainForm.StartButtonClick(Sender: TObject);
begin
cam:=CamList[CamListCB.ItemIndex];
if(cam.Start)then
begin
CamListCB.Enabled:=false;
CamTimer1.Enabled:=true;
end;
end;
По таймеру получаем картинку:
procedure TMainForm.CamTimer1Timer(Sender: TObject);
var BMP : TBitmap;
begin
bmp:=TBitmap.Create;
try
cam.CaptureBMP(bmp);
Image1.Picture.Assign(bmp);
finally
bmp.Destroy;
end;
end;
Компилируем, запускаем, наслаждаемся результатом:

Анализ полученных кадров и определение движения
Теперь начинается самое интересное. Пособий о том, как получать изображение с камеры — полным полно в интернете. Нас же интересует определение движения. Скажу вам, что результат захватывает.
Для начала — немного теории. Мы будем использовать самый простой, однако, довольно эффективный и наиболее часто используемый метод — сравнение двух соседних кадров. Что же необходимо для этого?
Самый простой метод сравнения — это, конечно, попиксельное вычитание. Нам просто необходимо из каждого пикселя текущего кадра вычесть каждый пиксель предыдущего. Ну, и если разница = 0, то движения не было вовсе. Однако, на камере всегда присутствуют шумы, иногда пролетают мошки, комары... Поэтому мы не будем сравнивать разницу с нулём, а считать, что движение произошло, если модуль разницы меньше константы D Эта константа определяется опытным путём, числа 50 (из 255 возможных для каждого цвета) вполне достаточно.
Для кадра размером 640x480 и трёх цветов (красный, зелёный, синий) это будет: 640*480*3 = 921600 операций вычитания — почти миллион! И это не раз в секунду, а намного чаще (в идеале - 24 раза, но обычно количество кадров уменьшают до нескольких штук в секунду). Плюс, ещё надо их сравнить. Довольно ресурсоёмко...
Именно поэтому картинку приводят к чёрно-белому варианту и уменьшают в несколько раз. Мы каждый кадр тоже будем обесцвечивать и уменьшать (делить) на константу divisor.
Ну, алгоритм ясен:
- Получили картинку с камеры;
- Привели её к оттенкам серого для каждого пикселя: (R+G+B) div 3;
- Поделили на делитель (например, было 640x480, делитель = 8, итоговый кадр будет 80x60);
- Из полученной матрицы отнимаем матрицу, полученную на предыдущем кадре - получаем матрицу разницы (diff);
- Считаем количество элементов diff, значение которых меньше D;
- Если количество больше предельного K, то подаём сигнал тревоги.
Весь алгоритм реализуем в классе TMotionDetector
unit MotionDetectorUnit;
interface
uses graphics;
type
TMotionDetector = class
private
FOldBMP : TBitmap;
FOldMatrix : array of array of byte;
FNewMatrix : array of array of byte;
FDiffMatrix : array of array of byte;
FNewBMP : TBitmap;
Fdivisor : integer;
function FGetWidth():integer;
function FGetHeight():integer;
function FGetOldM(x,y:integer):byte;
function FGetNewM(x,y:integer):byte;
function FGetDiffM(x,y:integer):byte;
public
function PushBitmap(bmp:TBitmap):boolean;
function DetectMotion():boolean;
property width:integer read FGetWidth;
property height:integer read FGetHeight;
property divisor:integer read Fdivisor write Fdivisor;
property OldM[X, Y: Integer]:byte read FGetOldM;
property NewM[X, Y: Integer]:byte read FGetNewM;
property DiffM[X, Y: Integer]:byte read FGetDiffM;
constructor Create;
destructor Destroy; override;
end;
implementation
uses SysUtils;
function TMotionDetector.FGetOldM(x,y:integer):byte;
begin
if((not Assigned(FOldBMP))or(not Assigned(FNewBMP)))then
exit(0);
result:=FOldMatrix[x,y];
end;
function TMotionDetector.FGetNewM(x,y:integer):byte;
begin
if((not Assigned(FOldBMP))or(not Assigned(FNewBMP)))then
exit(0);
result:=FNewMatrix[x,y];
end;
function TMotionDetector.FGetDiffM(x,y:integer):byte;
begin
if((not Assigned(FOldBMP))or(not Assigned(FNewBMP)))then
exit(0);
result:=FDiffMatrix[x,y];
end;
function TMotionDetector.DetectMotion():boolean;
type TRGB=packed record
R : byte;
G : byte;
B : byte;
end;
TLine=array[0..65535]of TRGB;
PLine=^TLine;
var x,y,yy,xx,w,h,i,j : integer;
lines : array of PLine;
sum : integer;
point : TRGB;
d_n,d_o : integer;
begin
if((not Assigned(FOldBMP))or(not Assigned(FNewBMP)))then
exit(false);
w:=length(FNewMatrix);
SetLength(FOldMatrix,w);
for x:=0 to w-1 do
begin
h:=length(FNewMatrix[x]);
SetLength(FOldMatrix[x],h);
for y:=0 to h-1 do
FOldMatrix[x,y]:=FNewMatrix[x,y];
end;
//
w:=FNewBMP.Width div Fdivisor;
h:=FNewBMP.Height div Fdivisor;
//
SetLength(FNewMatrix,w);
for x:=0 to w-1 do
SetLength(FNewMatrix[x],h);
//Convert New BMP to mask
SetLength(lines,Fdivisor);
for y:=0 to h-1 do
begin
yy:=y*Fdivisor;
for i:=0 to Fdivisor-1 do
lines[i]:=FNewBMP.ScanLine[yy+i];
for x:=0 to w-1 do
begin
xx:=x*Fdivisor;
sum:=0;
for i:=0 to Fdivisor-1 do
for j:=0 to Fdivisor-1 do
begin
point:=lines[i][xx+j];
sum:=sum+((point.R+point.G+point.B)div 3);
end;
FNewMatrix[x,y]:=(sum div Fdivisor)div Fdivisor;
end;
end;
SetLength(FNewMatrix,FNewBMP.Width div Fdivisor);
result:=length(FOldMatrix)=length(FNewMatrix);
if(result)then
begin
SetLength(FDiffMatrix,w);
for x:=0 to w-1 do
begin
SetLength(FDiffMatrix[x],h);
for y:=0 to h-1 do
begin
d_n:=FNewMatrix[x,y];
d_o:=FOldMatrix[x,y];
//if(d_n>d_o)
FDiffMatrix[x,y]:=(abs(d_n-d_o) and $FF);
end;
end;
end;
end;
function TMotionDetector.FGetWidth():integer;
begin
if((not Assigned(FOldBMP))or(not Assigned(FNewBMP)))then
exit(0);
result:=FOldBMP.Width div Fdivisor;
end;
function TMotionDetector.FGetHeight():integer;
begin
if((not Assigned(FOldBMP))or(not Assigned(FNewBMP)))then
exit(0);
result:=FOldBMP.Height div Fdivisor;
end;
function TMotionDetector.PushBitmap(bmp:TBitmap):boolean;
begin
FreeAndNil(FOldBMP);
FOldBMP:=FNewBMP;
FNewBMP:=TBitmap.Create;
FNewBMP.Width:=bmp.Width;
FNewBMP.Height:=bmp.Height;
FNewBMP.PixelFormat:=pf24bit;
FNewBMP.Assign(BMP);
result:=true;
end;
constructor TMotionDetector.Create;
begin
inherited;
Fdivisor:=8;
FOldBMP:=nil;
FNewBMP:=nil;
end;
destructor TMotionDetector.Destroy;
begin
inherited;
end;
end.
Компилируем, запускаем, наслаждаемся результатом:
Исходник: web-cam-analyzer-src.zip
Exe-шки: web-cam-analyzer-bin.zip
Комментарии
Прокомментировать - конечно же могу. Возможно даже я расширю статью. Но для начала скажите, что конкретно вам не понятно - как реализуется захват видео (что такое сообщения или что за страшные слова такие stdcall и external) или каким образом работает определение движения?
Какие моменты в статье описаны плохо? Что можно дополнить?
Перерыл кучу сайтов и только тут нашёл то что искал.
Могу я использовать ваш код в своем приложении ?
Как реализовать cam.Stop; , нужно остановить захват с камеры выбрать другую и опять запустить. После cam.Destroy; запуск cam.Start; приводит к ошибке.
Спасибо!
p.s. отличный блог.
function TCamera.Stop():boolean;
begin
if(Fh<>0)then
begin
SendMessage(Fh, WM_CAP_STOP , 0, 0);
CloseHandle(Fh);
Fh:=0;
end;
end;
if(Fh=0)then
begin
result:=false;
exit;
end;
во-первых, не компилируется, ошибки в модуле детектора
выкусил как мог его из проекта (не нужен),
программа откомпилировалась и запустилась, но легче не стало
у меня в системе 2 устройства, а в списке только одно Microsoft WDM и т.д.
и белый экран вместо картинки
пожалуйста, помогите, очень нужен граббер
если возможно, лучше на е-почту
С уважением,
Котович
Подскажите, пожалуйста- при компиляции программы Delphi (7) ругается на строки, содержащие "exit(0)" и "exit(false)", а именно "Missing operator or semicolon". Как можно исправить эту ошибку? Заранее спасибо.
Пробую сделать похожим образом (http://ignatiev.su/blog/posts/webcam-borlanddelphi-7) захват видео, но не могу захваченное видео вписать в размеры панели. Ввиду большего разрешения камеры на панели демонстрируется кусок видео, а не вписанное в эти размеры все видео. Подскажите что нужно изменить?
Для Delphi 7 пишите
begin
result:=...;
exit;
end;
Во-первых: спасибо за труды, очень интересно!
При отображении в режиме видеотрансляции TImage периодически очищается, что приводит к эффекту моргания видео...
Подскажите, как избавиться от данного эффекта?
1) как реализовать двойную буферизацию
2) каким образом это должно помочь, или, по какой причине сейчас наблюдается такой эффект?
Заранее спасибо.
Это происходит потому, что процесс прорисовки картинки занимает некоторое время и этот процесс видим на экране.
Двойная буферизация - это такой приём, при котором изображение сначала рисуется в видеопамяти, которая не отображается на экране, а затем происходит довольно быстрое переключение указателя экрана в этот буфер.
Вам следует смотреть в сторону обработчика таймера (CamTimer1Timer). Вероятнее всего грешит Image1.Picture.Assign(bmp); Попробуйте использовать внутренний механизм двойной буферизации Delphi:
Image1.Parent.DoubleBuffered := true;
или вручную рисовать на канве с помощью BitBlt.
Теперь вылезла другая проблема, спустя примерно час работы программы программа виснет, изображение замораживается, часы на форме тоже замораживаются, работать это дело дальше не хочет....
Судя по симптому, что-то где-то переполняется....
Есть идеи куда смотреть в таком случае?
Заранее спасибо, с уважением, Дмитрий.
function TCamera.Stop():boolean;
begin
if(Fh<>0)then
begin
SendMessage(Fh, WM_CAP_STOP , 0, 0);
CloseHandle(Fh);
Fh:=0;
end;
end;
вылетает с ошибкой Project raised exception class $C0000008 with message 'system exception (code 0xc0000008) at 0x771112f7'
CamList:=TCamList.Create;
Ответил по почте на все вопросы.
@Никита
Вопрос выходит за рамки данного поста.
Используйте LoadLibrary и GetProcAddress.
@slider
Исходник имеется.
Получение картинки происходит в обработчике таймера формы (TMainForm.CamTimer1Timer).
Опишите ошибку подробнее. Какая у Вас версия Delphi?
Напоминаю что исходник дан для Delphi XE и выше. Если необходима поддержка версий ниже XE, сообщите.
ваша программа показывает белый экран и нет настроек драйвера
SendMessage(h_cam, WM_CAP_DLG_VIDEOSOURCE, SizeOf(Bt), LongInt(@Bt));
SendMessage(h_cam, WM_CAP_DLG_VIDEOFORMAT, SizeOf(Bt), LongInt(@Bt));
Вместо h_cam использовать соответствующее поле класса. Определить константы WM_CAP_DLG_VIDEOSOURCE и WM_CAP_DLG_VIDEOFORMAT. И ещё структуру Bt (или что это такое?) описать.
К сожалению, в скором будущем за Delphi 7 взяться не смогу. Если очень надо - можете сами портировать.
@Alex
cam.CaptureBMP(bmp);
bmp.savetofile(<путь к файлу>);
Всё не так просто. Это — тема для отдельной статьи.
Выложил исходник без exe файла!
Сталкивался с таким на некоторых ноутбуках. После 3-4 перезапусков софта заработало.
Может быть, у меня какой-то баг? Я его не нашел. Или же проблема в том, что библиотека AVICAP32.DLL попросту устарела.
Программа писалась ещё во времена Windows XP, в семёрке у меня тоже глючит, вот я чуток поправил захват видео - проверьте последние EXE-шки. Если всё будет ок - обновлю исходник.
В серьёзных проектах сейчас используют DirectShow - этот способ удобнее и универсальнее. У меня в планах было разобраться с DirectShow и когда до этого дойдут руки, я обязательно выложу исходник.
Вот, пожалуйста. Скомпилировал и добавил ссылку в конец статьи.
Наверное действительно какие-то существенные изменения претерпел AVICAP32.DLL. Запускаю на ноутбуке под Windows 8.1
Возможно. К сожалению, из всех тех компьютеров, которые меня окружают, ни на одном нет Windows 8.
Давно собирался разобраться с DirectShow, всё никак руки не доходят. В последнее время практически на 100% пересел на управление проектами и Web.
А так, нигде рабочих примеров не находил, кроме вашего, спасибо)
p/s Больше пояснений явно не помешало бы, хоть я и знаю делфи но не на таком уровне =)(Взял бы у вас уроки =))
Объяснять много не могу чисто физически, по моему, и так понятно. Если есть конкретные вопросы - задавайте, отвечу.
procedure TCamera.CaptureBMP(bmp: TBitmap);
var
tdc: HDC;
begin
SendMessage(Fh, WM_CAP_GRAB_FRAME, 0, 0);
bmp.Width := FWidth;
bmp.Height := FHeight;
tdc := GetDC(Fh);
BitBlt(bmp.Canvas.Handle, 0, 0, FWidth, FHeight, tdc, 0, 0, SRCCOPY);
ReleaseDC(Fh, tdc);
end;
Спасибо, поправил
Может быть, проблема в том, что библиотека AVICAP32.DLL попросту устарела?
Попробуйте убрать хак со скрытием окна камеры - в capCreateCaptureWindowA вместо 10000 поставьте 0.
Направил на тестер, работает.
Есть пример на распознавания на MatLab.
http://www.cyberforum.ru/measuring-devices/thread1364812.html
Для дальнейшей работы выбран Excel, чтобы исходники виделись на каждой машине.
Вам осталось совсем немного до распознавания цифр и тестеры вместе с другими цифровыми у Вас в кармане.
Спасибо
Виталий
Я не уверен, но мне кажется что нет.
procedure TMainFormCamera.CamTimer1Timer(Sender: TObject);
var BMP,orig : TBitmap;
begin
bmp:=TBitmap.Create;
bmp.PixelFormat:=pf24bit;
cam.CaptureBMP(bmp);
orig:=TBitmap.Create;
orig.Width:=bmp.Width;
orig.Height:=bmp.Height;
orig.Assign(bmp);
orig.Free;
bmp.free;
end;
Расскажу вкратце:
cam.CaptureBMP(bmp);
bmp.savetostream(stream);
Далее транслируем наш stream по своему протоколу в TCPServer/TCPClient.
Лучше, конечно, предварительно перекодировать в JPEG.
Ссылки на исходник и EXE-шник есть в конце статьи.
По поводу вашей проблемы читайте мой комментарий от
20.03.2013.
Delphi 7 уже очень сильно устарела, лучше используйте любую более-менее современную версию.
По поводу чёрного экрана. 1. Вы кнопку "Start" нажимали?
2. Возможно, вы некорректно закрыли устройство в прошлый раз или веб-камера уже используется другими программами? Перезагрузите компьютер и запустите программу "начисто". Попробуйте на другом компьютере.
3. Веб камера настроена и работает? Другие программы для работы с камерой работают?
4. Какая у вас версия Windows?
FWidth:=1280;
FHeight:=800;
Отображается не полный Image, картинка занимает примерно четверть. Для Image сделал ресайз под 1280х800. Камера поддерживает такое разрешение, проверял.
Странно. Должно работать.
У меня 640x480. Проверить на "большей" камере, к сожалению, не могу.
Библиотека AVICAP32 устарела. Я замечал проблемы при неправильном закрытии программы (без кнопки отправки сообщения WM_CAP_STOP). Бывали проблемы при повторном открытии программы.
Думаю, Microsoft просто "забила" на поддержку AVICAP32. На MSDN давно уже пишут о проблемах с чёрным экраном на Windows 7 и выше.
https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd756879(v=vs.85).aspx
AVICAP32 - это больше так, поиграться. Серьёзные проекты (типа Skype) используют DirectShow. Опыта использования DirectShow у меня нет.
Просто тут все хорошо расписано.
Fh:=capCreateCaptureWindowA('test', WS_VISIBLE or WS_CHILD,10000,10000, FWidth,FHeight,GetDesktopWindow,0);
Открывается новое окно, не смотря на то что окно за границами экрана (координаты 10000,10000), на панели задач оно видно. Иожно ли как-то скрыть его?
Fh:=capCreateCaptureWindowA('test', WS_VISIBLE,10000,10000, FWidth,FHeight,GetDesktopWindow,0);
Добавьте
ShowWindow(Fh,SW_HIDE);
SetWindowLong(Fh, GWL_EXSTYLE,
GetWindowLong(Fh, GWL_EXSTYLE) OR WS_EX_TOOLWINDOW);
ShowWindow(Fh,SW_SHOW);
dcc32.exe WebCam.dpr -M -B --no-config -$J+,R-,I-,Q-,Y-,B-,A+,W-,U-,T-,H+,X+,P+,V+,G+ -AWinTypes=Winapi.Windows;WinProcs=Win
api.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;Generics.Collections=System.Generics.Collections;Generics.Defaults=System.
Generics.Defaults -W-SYMBOL_PLATFORM -W-UNIT_PLATFORM -W-GARBAGE -NSSystem;Xml;Data;Datasnap;Web;Web.Win;Soap.Win;Winapi;Sys
tem.Win;Data.Win;BDE;Xml.Win;Web.Win;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Shell;VCLTee -$D- -GD -U".;c:\delphi\2013\lib\win32\debug
;c:\delphi\2013\lib\win32\release;c:\delphi\2013\imports;c:\delphi\2013\projects\bpl;c:\delphi\2013\source\toolsapi;c:\delph
i\2013\lib\win32\indy10" -I".;c:\delphi\2013\lib\win32\debug;c:\delphi\2013\lib\win32\release;c:\delphi\2013\imports;c:\delp
hi\2013\projects\bpl;c:\delphi\2013\source\toolsapi;c:\delphi\2013\lib\win32\indy10" -R".;c:\delphi\2013\lib\win32\debug;c:\
delphi\2013\lib\win32\release;c:\delphi\2013\imports;c:\delphi\2013\projects\bpl;c:\delphi\2013\source\toolsapi;c:\delphi\20
13\lib\win32\indy10"
Благодарю за правки.
@Terik90
И вам тоже спасибо за информацию о том, как сбилдить.
К сожалению, в последнее время не всегда находится свободные моменты чтоб перечитать коменты и решить чьи-то проблемы.
Приятно что есть энтузиасты, которые могут подсказать.
Adding comments is temporarily disabled for unregistered users.