В качестве веб-камеры используется камера заднего вида автомобиля, а она внутри себя переворачивает картинку справа налево. Естественно, неплохо было бы её перевернуть обратно, но стандартный компонент WebCam такой функцией не обладает. Вроде бы решение очевидно: получить картинку с камеры и уже графическими компонентами перевернуть её обратно, но вот тут возникла проблема: WebCam не выдаёт картинку в поток, он только отрисовывает её на указанном элементе.
Что же я перепробовал:
1. Метод компонента doSaveDIB (сохраняет кадр в файл) для последующей загрузки картинки из файла и переворота. Однако это придётся делать несколько раз в секунду, что сильно замедлит программу.
2. Метод doEditCopy - помещает кадр в буфер обмена. Однако не очень хорошо, если программа без ведома пользователя будет что-то помещать в буфер - тогда пользователь не сможет с ним работать.
3. Может быть, есть какие-то другие методы, не реализованные в WebCam? Порывшись на сайте https://learn.microsoft.com/en-us/windo … edit-copy, я ничего подходящего не нашёл. Да, есть какая-то колбэк-функция при получении очередного кадры с камеры, но ничего не описано, где именно там хранится картинка. Соответственно, в интернетах я по этому поводу тоже толком ничего не нашёл. Не выдаёт этот функционал картинку в поток/переменную, а только её отрисовывает!
4. Дальше уже пошли опыты в IC. Опробована фукнция
BitBlt(bmp.Canvas.Handle, 0, 0, 320, 240, GetDC(h), 0, 0, SRCCOPY);
, где h - это указатель на окно видеозахвата, получаемый с нижней точки компонента WebCam, а bmp - созданная временная картинка. Способ рабочий, да вот только исходный (т.е. отражённый справа налево) кадр при этом должен оставаться видимым на форме, иначе ничего не работает. А зачем отображать исходное, неправильное изображение?
5. Были мысли, может, методу doSaveDIB подсунуть имя какого-нибудь виртуального файла, на самом деле указывающего на участок памяти, но в сети я так и не нашёл толкового способа это сделать.
6. Спросил ИИ: ГПТ, copilot, replit... Видели бы вы, ЧТО они мне навыдавали! Какие-то несуществующие функции типа capGetFrame (существует только capGrabFrame, она позволяет получать один кадр с камеры в окно просмотра),
SendMessage(h, WM_CAP_COPY, 0, LPARAM(Bmp.Handle))
(это сообщение копирует кадр в буфер обмена, оно и используется в doEditCopy, но LParam там совсем не используется!). В общем, почти всё нерабочее, для моей цели не подошло ничего.
7. Сунулся было в DirectX - читал, что там расширенные возможности видеозахвата, но кода там на неделю разбираться для такой мелочи, как разворот картинки.
...
Решение нашлось, отуда не ждали. Есть такой стиль окон - WS_EX_LAYOUTRTL, он отражает справа налево само окно. Отражение выполняется самой виндой, достаточно установить этот стиль - и она сама будет разворачивать окно вместе с картинкой!
Код:Add(WebCam,1803333,609,322) { RefreshRate=200 FileDIB="a.bmp" FileVideo="cam.avi" Point(doVideoSource) Point(doVideoFormat) Point(doVideoCompression) Point(doSaveDIB) link(WinHandle,14074503:Handle,[]) } Add(Button,7768292,490,266) { Left=5 Top=35 Caption="Source" link(onClick,1803333:doVideoSource,[(566,272)(566,342)]) } Add(Button,14395040,483,308) { Left=5 Top=55 Caption="Format" link(onClick,1803333:doVideoFormat,[(562,314)(562,349)]) } Add(Button,7859332,483,350) { Left=5 Top=75 Caption="Compress" link(onClick,1803333:doVideoCompression,[]) } Add(Image,14074503,616,266) { Left=65 Top=5 Width=320 Height=263 Point(Handle) Point(doRefresh) } Add(Hub,5680976,532,203) { link(onEvent1,1803333:doDisConnect,[(583,209)(583,335)]) link(onEvent2,1803333:doConnect,[(578,216)(578,328)]) } Add(Button,11636729,490,203) { Left=5 Top=10 Caption="On" link(onClick,5680976:doEvent1,[]) } Add(InlineCode,14009132,609,399) { WorkPoints=#1:a| EventPoints=#5:onBmp| DataPoints=#8:dtHandle| Code=#42://Отражение картинки с камеры по вертикали|15:unit HiAsmUnit;|0:|9:interface|0:|38:uses windows,kol,Share,Debug,hiWebCam;|0:|24:var rtl:boolean = false;|0:|4:type|28: THiAsmClass = class(TDebug)|10: private|9: public|23: dtHandle:THI_Event;|20: onBmp:THI_Event;|42: procedure a(var dt:TData; index:word);|0:|5: end;|0:|14:implementation|0:|24:procedure THiAsmClass.a;|30:var h:longword; //bmp:PBitmap;|34:const WS_EX_LAYOUTRTL = $00400000;|5:begin|31: h := ToIntegerEvent(dtHandle);|29: //Bmp := NewBitmap(640,480);|14: {xy.x := 100;|13: xy.y := 100;|55: SendMessage(h, WM_CAP_SET_SCROLL, 0, longint(@(xy)));}|81: //SendMessage(h, WM_CAP_SET_CALLBACK_FRAME, 0, longint(@FrameCallbackFunction));|43: //SendMessage(h, WM_CAP_GRAB_FRAME, 0, 0);|70: //BitBlt(bmp.Canvas.Handle, 0, 0, 320, 240, GetDC(h), 0, 0, SRCCOPY);|33: //Bmp.Canvas.Handle := GetDC(h);|0:|97: if rtl then SetWindowLong(h, GWL_EXSTYLE, GetWindowLong(h, GWL_EXSTYLE) and not WS_EX_LAYOUTRTL)|87: else SetWindowLong(h, GWL_EXSTYLE, GetWindowLong(h, GWL_EXSTYLE) or WS_EX_LAYOUTRTL);|16: rtl := not rtl;|26: //_hi_OnEvent(onBmp,Bmp);|4:end;|0:|4:end.| link(dtHandle,1803333:Handle,[]) } Add(Button,12790683,490,399) { Left=5 Top=100 Caption="RTL" link(onClick,14009132:a,[]) }