| ||
: О проекте :: Устройство робота :: Фото и видео :: Демострационный софт :: О авторе : | ||
Захват видеоизображения. Преобразование цветного изображения в черно-белоеПри ограниченных вычислительных ресурсах важно, во-первых, выбрать минимальный допустимый размер видеоизображения в пикселях, а во-вторых, для его хранения в памяти организовать структуру данных, которая бы обеспечивала максимально быстрый доступ к пикселям. При этом следует выполнять следующие требования (эти требования носят эвристический характер и сформулированы на основе опыта автора):
Обращаем Ваше внимание на то, что изображение в формате RGB24 (цветное изображение) и GrayScale8 (черно-белое изображение) хранится в формате DIB, который используется в BMP-файлах. Согласно этому формату, строки изображения хранятся снизу вверх, а размер каждой строки должен быть кратен 4 байтам. Для достяжения последнего требования следует правильно выбирать ширину изображения (ImageWidth) так, чтобы в нем не было пустых байтов. В цветном изображении (RGB24) на каждый пиксель отводится 3 байта. Цветовые составляющие хранятся в последовательности СИНИЙ, ЗЕЛЕНЫЙ, КРАСНЫЙ. При этом каждая составляющая является байтом и изменяется в диапазоне от 0 до 255 (0 - минимальная интенсивность цвета, 255 - максимальная интенсивность). В черно-белом изображении (Grayscale8) на каждый пиксель приходится 1 байт. Яркость пикселя определяется значением 0 до 255 (0-максимально темный пиксель, 255-максимально светлый). Захват видеоизображения описанным ниже способом возможен для большинства карт видеозахвата (TV-тюнеров) и определяется наличием соответствующего драйвера. Код проверялся для карт видеозахвата DE-18 (DigitEys-18) (Драйвер только для Win95,98,Me), FlyVideo-98 (Драйвер только для Win95,98,Me), EZCapture, AverMedia. Пример захвата видеоизображения представлен на языке Delphi: unit Main; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, VidCap, ExtCtrls; type TMainForm = class(TForm) Timer1: TTimer; PaintBox1: TPaintBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } public { Public declarations } VideoWND : HWND; end; const ImageWidth = 384; // ширина изображения. Если умножить на 3 должно быть кратным 4 ImageHeight = 284; // высота изображения DriverIndex = 0; // номер карты видеозахвата (от 0 до 9). type // тип данных цветного изображения TColorImage = packed array[0..ImageHeight-1,0..ImageWidth-1,0..2] of Byte; // тип данных для черно-белого изображения TBWImage = array[0..ImageHeight-1,0..ImageWidth-1] of Byte; // вспомогательный тип данных TBitmapInfo256 = record bmiHeader : TBitmapInfoHeader; bmiColors : array[0..255,0..3] of Byte; end; var MainForm: TMainForm; VideoOk : boolean; // признак удачного захвата кадра ColorImage : TColorImage; // область памяти для хранения цветного изображения BWImage : TBWImage; // область памяти для хранения черно-белого изображения var BitmapInfo256 : TBitmapInfo256; BitmapInfo : TBitmapInfo absolute BitmapInfo256; // BitmapInfo и BitmapInfo256 лежат в одной области памяти implementation {$R *.DFM} // callback-функция для захвата видео procedure VideoCallback(Wnd:HWND; Hdr:PVIDEOHDR); stdcall; begin Move(Hdr.lpData^, ColorImage, Hdr.dwBytesUsed); VideoOk:=true; end; // инициализирует структуру BitmapInfo procedure InitBitmapInfo; var i : integer; begin Fillchar(BitmapInfo256,sizeof(TBitmapInfoHeader),0); BitmapInfo256.bmiHeader.biSize:=40; BitmapInfo256.bmiHeader.biPlanes:=1; BitmapInfo256.bmiHeader.biWidth:=ImageWidth; BitmapInfo256.bmiHeader.biHeight:=ImageHeight; for i:=0 to 255 do begin BitmapInfo256.bmiColors[i,0]:=i; BitmapInfo256.bmiColors[i,1]:=i; BitmapInfo256.bmiColors[i,2]:=i; BitmapInfo256.bmiColors[i,3]:=0; end; end; // рисует на устройстве DC цветное изображение Image procedure DrawColorImage(DC:HDC; var Image:TColorImage); begin BitmapInfo.bmiHeader.biBitCount:=24; SetDIBitsToDevice(DC,0,0,ImageWidth,ImageHeight,0,0,0,ImageHeight,@Image,BitmapInfo,DIB_RGB_COLORS); end; // рисует на устройстве DC черно-белое изображение Image procedure DrawBWImage(DC:HDC; var Image:TBWImage); begin BitmapInfo.bmiHeader.biBitCount:=8; SetDIBitsToDevice(DC,0,0,ImageWidth,ImageHeight,0,0,0,ImageHeight,@Image,BitmapInfo,DIB_RGB_COLORS); end; // конвертирует цветное изображение в черно-белое procedure ColorImageToBWImage(const ColorImage : TColorImage; var BWImage:TBWImage); assembler; asm PUSH EDI PUSH ESI PUSH EBX MOV EDI,EDX MOV ESI,EAX MOV ECX,ImageHeight*ImageWidth MOV EBX,3 @@2: XOR EAX,EAX LODSB MOV EDX,EAX LODSB ADD EDX,EAX LODSB ADD EAX,EDX DIV BL STOSB LOOP @@2 POP EBX POP ESI POP EDI end; procedure TMainForm.FormCreate(Sender: TObject); begin // инициализируем структуру BitmapInfo InitBitmapInfo; // Создаем окно для проекции оверлея VideoWND:=capCreateCaptureWindow('Video',WS_CHILD or WS_VISIBLE, 10,10,ImageWidth,ImageHeight, Handle,0); if VideoWND <> 0 then begin // подключение окна к драйверу if SendMessage(VideoWND,WM_CAP_DRIVER_CONNECT,DriverIndex,0)=0 then begin DestroyWindow(VideoWND); VideoWND:=0; exit; end; // задаем формат видеокадра. Большая часть BitmapInfo проинициализирована в InitBitmapInfo BitmapInfo.bmiHeader.biBitCount:=24; SendMessage(VideoWND,WM_CAP_SET_VIDEOFORMAT ,0,Integer(@BitmapInfo)); // задаем callback-функцию SendMessage(VideoWND,WM_CAP_SET_CALLBACK_FRAME ,0,Integer(@VideoCallback)); // включаем оверлей SendMessage(VideoWND,WM_CAP_SET_OVERLAY,1,0); VideoOk:=true; end; end; procedure TMainForm.FormDestroy(Sender: TObject); begin SendMessage(VideoWND,WM_CAP_DRIVER_DISCONNECT,0,0) end; procedure TMainForm.Timer1Timer(Sender: TObject); begin // захват кадра if (VideoWND <> 0) and VideoOk then begin VideoOk:=False; SendMessage(VideoWND,WM_CAP_GRAB_FRAME_NOSTOP,0,0); end; // цветное в черно-белое ColorImageToBWImage(ColorImage,BWImage); // Нарисовать для проверки DrawBWImage(PaintBox1.Canvas.Handle,BWImage); end; end. Для компиляции кода необходим модуль vidcap.pas. Скачать полностью все файлы проекта можно здесь (winrar3.2, Delphi 3.0 и выше). | ||
Дизайн: DynSoft |