Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour,
nouveau défi: Nous voulons intégrer une webcam dans notre application.
La webcam choisi: Logitech c525
PB 11.5.1
Ce que nous utilisons déjà est le EZTwain version 3.43 pour accèder au Scanners, et maintenant aussi Webcams.
Donc l'idée est de d'avoir une fenêtre où on voit la personne de la wbcam et à côté dès qu'on clique sur un bouton "Capturer" d'afficher le cliché pris et de le sauvegarder dans une fichier ou voir même un blob.
Je suis partie sur l'implementation de capCreateCaptureWindowA de AVICAP32.DLL et des fonctions WM_CAP....
J'arrive à afficher la webcam dans une fênetre:
//Instances Variables: Uint lhand Constant long GET_FRAME = 1084 Constant long COPY = 1054 Constant long WM_USER = 1024 Constant long WM_CAP_START = WM_USER Constant long WM_CAP_STOP = WM_CAP_START + 68 Constant long WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10 Constant long WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11 Constant long WM_CAP_SAVEDIB = WM_CAP_START + 25 Constant long WM_CAP_GRAB_FRAME = WM_CAP_START + 60 Constant long WM_CAP_SEQUENCE = WM_CAP_START + 62 Constant long WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20 Constant long WM_CAP_FILE_SAVEAS = WM_CAP_START + 23 Constant long WM_CAP_SEQUENCE_NOFILE =WM_CAP_START+ 63 Constant long WM_CAP_SET_OVERLAY =WM_CAP_START+ 51 Constant long WM_CAP_SET_PREVIEW =WM_CAP_START+ 50 Constant long WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START +6 Constant long WM_CAP_SET_CALLBACK_ERROR=WM_CAP_START +2 Constant long WM_CAP_SET_CALLBACK_STATUSA= WM_CAP_START +3 Constant long WM_CAP_SET_CALLBACK_FRAME= WM_CAP_START +5 Constant long WM_CAP_SET_SCALE=WM_CAP_START+ 53 Constant long WM_CAP_SET_PREVIEWRATE=WM_CAP_START+ 52 Long wm_cap_savedatdib = 1049 Long wm_cap_dlg_videoformat = 1065 Long wm_cap_dlg_videosource = 1066 Long wm_cap_dlg_videodisplay = 1067 Long wm_cap_get_videoformat = 1068 Long wm_cap_set_videoformat = 1069 Long wm_cap_dlg_videocompression = 1070 Long cf_bitmap = 2 Long wm_close = 16 Ulong scrcopy = 32 string gs_pic_path string gs_cd_path string gs_path string gs_ds_pic string gs_ds_cd string gs_cd_rq long gl_pic_sj = 0
//Local External Functions: function ulong capCreateCaptureWindowA(string lpszWindowName,ulong dwStyle,long li_x ,long li_y ,long nWidth ,long nHeight ,ulong ParentWin ,long nId ) LIBRARY 'AVICAP32.DLL' alias for "capCreateCaptureWindowA;ansi"
//fonction pour initialiser la webcam avec argument : usignedlong a_handle, string a title string lpszName lpszName = a_title if lhand = 0 then lhand=capCreateCaptureWindowA(lpszName,262144+12582912+1073741824 + 268435456 ,10,10,200,200,a_handle,0) end if if lhand <> 0 then send(lhand, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0) send(lhand, WM_CAP_SET_CALLBACK_ERROR, 0, 0) send(lhand, WM_CAP_SET_CALLBACK_STATUSA, 0, 0) send(lhand, WM_CAP_DRIVER_CONNECT, 0, 0) send(lhand, WM_CAP_SET_SCALE, 1, 0) send(lhand, WM_CAP_SET_PREVIEWRATE, 66, 0) send(lhand, WM_CAP_SET_OVERLAY, 1, 0) send(lhand, WM_CAP_SET_PREVIEW, 1, 0) end if
Maintenant pour capturer une image j'ai un problème et cela ne fait rien:
string ls ls = "C:\test.jpg" Send(lhand,WM_CAP_FILE_SET_CAPTURE_FILEA,0,ls) Send(lhand, GET_FRAME, 0, 0); Send(lhand,WM_CAP_SAVEDIB,0, ls) Send(lhand,WM_CAP_FILE_SAVEAS,0, ls)
Quelqun' a une dit pour faire fonctionner cela? Ou même une autre solutioin pour integrer la visualistion et en même temps la capture?
L'autre solution que j'ai essayé d'implémenté c'est d'utilisé EZTwain pour capturer l'image.
Le problème la est que quand il veut capturer il m'ouvre l'assistant de capture de WINDOWS pour le faire et par après EZTwain récupere l'image et le sauvegarde dans un fichier. Cela fonctionne mais ça m'embête qu'il ouvre l'assistant et ne fait toute de suite la capture. Entre autre, de visualiser à l'aide WM_CAP et en même temps de faire la capture avec EZTwain ne fonctionne pas car EZTwain dit que la webcam est déjà en utilisation.
Donc je penche plus de finaliser la première solution sauf si qulqu'un a une autre solution "All In One", si possible non payant!
Existe-t-il un OCX free ou open source pour accomplir cela. J'ai cherché un peu sur internet mais j'ai rien trouvé.
Merci pour l'aide.
Dernière modification par Maestro (10-10-2013 13:24:17)
Hors ligne
J'ai trouvé une solution pour utiliser une Webcam avec PB:
avec visualisation permanente et en même temps capturer des images
Technique utilisé:
capCreateCaptureWindowA de AVICAP32.DLL et des fonctions WM_CAP pour visualiser et capturer
structures utilisées:
global type bitmapfileheader from structure integer bftype long bfsize integer bfreserved1 integer bfreserved2 long bfoffbits end type global type bitmapinfo from structure bitmapinfoheader bmiheader unsignedlong bmicolors[] end type global type bitmapinfoheader from structure long bisize long biwidth long biheight integer biplanes integer bibitcount long bicompression unsignedlong bisizeimage long bixpelspermeter long biypelspermeter long biclrused long biclrimportant end type
l'object NVO_WEBCAM
forward global type nvo_webcam from nonvisualobject end type end forward global type nvo_webcam from nonvisualobject autoinstantiate end type type prototypes function ulong capCreateCaptureWindowA(string lpszWindowName,ulong dwStyle,long li_x ,long li_y ,long nWidth ,long nHeight ,ulong ParentWin ,long nId ) LIBRARY 'AVICAP32.DLL' alias for "capCreateCaptureWindowA;ansi" Function ulong GetDC(ulong hWnd) Library "user32.dll" Function long ReleaseDC(ulong hWnd, ulong hdcr) Library "USER32.DLL" Function ulong CreateCompatibleDC(ulong hdc) Library "gdi32.dll" Function ulong CreateCompatibleBitmap( ulong hdc, ulong nWidth, ulong nHeight) Library "gdi32.dll" Function boolean DeleteDC(ulong hdc) Library "gdi32.dll" Function boolean BitBlt(ulong hdcDest, long nXDest, long nYDest, long nWidth, long nHeight, ulong hdcSrc, long nXSrc, long nYSrc, long dwRop) Library "gdi32.dll" Function boolean StretchBlt(ulong hdcDest, long nXOriginDest, long nYOriginDest, long nWidthDest, long nHeightDest, ulong hdcSrc, long nXOriginSrc, long nYOriginSrc, long nWidthSrc, long nHeightSrc, long dwRop) Library "gdi32.dll" Function ulong SelectObject(ulong hdc, ulong hgdiobj) Library "gdi32.dll" Function long GetDIBits (ulong hdc, ulong hbmp, uint uStartScan, uint cScanLines, Ref blob lpvBits, Ref bitmapinfo lpbi, uint uUsage) Library "gdi32.dll" alias for "GetDIBits" Function long GetDIBits (ulong hdc, ulong hbmp, uint uStartScan, uint cScanLines, ulong lpvBits, ref bitmapinfo lpbi, uint uUsage) Library "gdi32.dll" alias for "GetDIBits" Subroutine CopyBitmapFileHeader (Ref blob Destination, bitmapfileheader Source, long Length) Library "kernel32.dll" Alias For "RtlMoveMemory" Subroutine CopyBitmapInfo (Ref blob Destination, bitmapinfo Source, long Length) Library "kernel32.dll" Alias For "RtlMoveMemory" Function boolean OpenClipboard(ulong hWndNewOwner) Library "user32.dll" Function boolean CloseClipboard() Library "user32.dll" Function boolean EmptyClipboard() Library "user32.dll" Function ulong GetClipboardData(ulong uFormat) Library "user32.dll" end prototypes type variables Uint lhand Constant long GET_FRAME = 1084 Constant long COPY = 1054 Constant long WM_USER = 1024 Constant long WM_CAP_START = WM_USER Constant long WM_CAP_STOP = WM_CAP_START + 68 Constant long WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10 Constant long WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11 Constant long WM_CAP_SAVEDIB = WM_CAP_START + 25 Constant long WM_CAP_GRAB_FRAME = WM_CAP_START + 60 Constant long WM_CAP_SEQUENCE = WM_CAP_START + 62 Constant long WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20 Constant long WM_CAP_FILE_SAVEAS = WM_CAP_START + 23 Constant long WM_CAP_SEQUENCE_NOFILE =WM_CAP_START+ 63 Constant long WM_CAP_SET_OVERLAY =WM_CAP_START+ 51 Constant long WM_CAP_SET_PREVIEW =WM_CAP_START+ 50 Constant long WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START +6 Constant long WM_CAP_SET_CALLBACK_ERROR=WM_CAP_START +2 Constant long WM_CAP_SET_CALLBACK_STATUSA= WM_CAP_START +3 Constant long WM_CAP_SET_CALLBACK_FRAME= WM_CAP_START +5 Constant long WM_CAP_SET_SCALE=WM_CAP_START+ 53 Constant long WM_CAP_SET_PREVIEWRATE=WM_CAP_START+ 52 //Long wm_cap_savedatdib = 1049 //Long wm_cap_dlg_videoformat = 1065 //Long wm_cap_dlg_videosource = 1066 //Long wm_cap_dlg_videodisplay = 1067 //Long wm_cap_get_videoformat = 1068 //Long wm_cap_set_videoformat = 1069 //Long wm_cap_dlg_videocompression = 1070 //Long cf_bitmap = 2 //Long wm_close = 16 //Ulong scrcopy = 32 //string gs_pic_path //string gs_cd_path //string gs_path //string gs_ds_pic //string gs_ds_cd //string gs_cd_rq //long gl_pic_sj = 0 // end variables forward prototypes public subroutine of_close () public subroutine of_initialize_webcam (unsignedlong a_handle, string a_title, integer a_width, integer a_height) public function blob of_copy_clipboard_to_blob () public subroutine of_capture_pic () end prototypes public subroutine of_close ();Send(lhand, WM_CAP_DRIVER_DISCONNECT, 0, 0) end subroutine public subroutine of_initialize_webcam (unsignedlong a_handle, string a_title, integer a_width, integer a_height);string lpszName lpszName = a_title if lhand = 0 then lhand=capCreateCaptureWindowA(lpszName,262144+12582912+1073741824 + 268435456 ,1,40,a_width,a_height,a_handle,0) end if if lhand <> 0 then send(lhand, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0) send(lhand, WM_CAP_SET_CALLBACK_ERROR, 0, 0) send(lhand, WM_CAP_SET_CALLBACK_STATUSA, 0, 0) send(lhand, WM_CAP_DRIVER_CONNECT, 0, 0) send(lhand, WM_CAP_SET_SCALE, 1, 0) send(lhand, WM_CAP_SET_PREVIEWRATE, 66, 0) send(lhand, WM_CAP_SET_OVERLAY, 1, 0) send(lhand, WM_CAP_SET_PREVIEW, 1, 0) end if end subroutine public function blob of_copy_clipboard_to_blob ();BitmapInfo lstr_Info BitmapFileHeader lstr_Header Blob lblb_header, lblb_info, lblb_bitmap, lbl_final ULong lul_hdc, lul_hdcMem, lul_hBitmap, lul_hWnd, lul_blpos UInt DIB_RGB_COLORS Integer li_pixels Boolean lb_result long al_width, ll_height, ll_ret constant integer BITMAPTYPE = 19778 //4D42 = BM constant integer CF_BITMAP = 2 constant integer CF_DIB = 8 lul_hWnd = Handle(this) lb_result = OpenClipboard(lul_hWnd) // Get the device context of window and allocate memory lul_hdc = GetDC(lul_hWnd) lul_hdcMem = CreateCompatibleDC(lul_hdc) lul_hBitmap = getclipboarddata(CF_BITMAP) // try to store the bitmap into a blob so we can save it lstr_Info.bmiHeader.biSize = 40 ll_height = 480 // ... 480 devrait suffire pour tout le monde ? ;) DIB_RGB_COLORS = 0 // Get the bitmapinfo If GetDIBits(lul_hdcMem, lul_hBitmap, 0, ll_height, 0, lstr_Info, DIB_RGB_COLORS) > 0 Then li_pixels = lstr_Info.bmiHeader.biBitCount lstr_Info.bmiColors[li_pixels] = 0 lblb_bitmap = Blob(Space(lstr_Info.bmiHeader.biSizeImage), EncodingANSI!) ll_height = lstr_Info.bmiHeader.biheight // get the actual bits ll_ret = GetDIBits(lul_hdcMem, lul_hBitmap, 0, ll_height, lblb_bitmap, lstr_Info, DIB_RGB_COLORS) //ls_msg = hexdump_blob(lblb_bitmap, false) // create a bitmap header lstr_Header.bfType = BITMAPTYPE lstr_Header.bfSize = lstr_Info.bmiHeader.biSizeImage lstr_Header.bfOffBits = 54 + (li_pixels * 4) // copy the header structure to a blob lblb_header = Blob(Space(7))//14/2 CopyBitmapFileHeader(lblb_header, lstr_Header, 14) // copy the info structure to a blob lblb_Info = Blob(Space((40 + li_pixels * 4)/2)) CopyBitmapInfo(lblb_Info, lstr_Info, len(lblb_Info)) // add all together and we have a window bitmap in a blob lbl_final = lblb_header + lblb_info + lblb_bitmap End If CloseClipboard() ReleaseDC(lul_hwnd, lul_hdc) DeleteDC(lul_hdcMem) return lbl_final end function public subroutine of_capture_pic ();Send(lhand, GET_FRAME, 0, 0) Send(lhand, COPY, 0, 0) end subroutine on nvo_webcam.create call super::create TriggerEvent( this, "constructor" ) end on on nvo_webcam.destroy TriggerEvent( this, "destructor" ) call super::destroy end on
A utiliser comme suit:
1. instancier l'objet et initialisez le:
i_nvo_webcam.of_initialize_webcam(handle(this), "Webcam",il_width,il_height)
2. capturer:
i_nvo_webcam.of_capture_pic()
3. traitement de l'image:
lb_blob = i_nvo_webcam.of_copy_clipboard_to_blob() //reinitialse pour que la webcam continue en live i_nvo_webcam.of_initialize_webcam(handle(this), "Webcam",il_width,il_height)
4. Fermer
i_nvo_webcam.of_close()
Si vous avez EZTWAIN Pro:
Vous pouvez facilement utiliser les fonction DIB pour traiter le clipboard et faire le traitement nécéssaire de l'image ainsi que de sauvegarde dans différent format de fichier JPG ou BMP.
ll_dib_handle = lnvo_twain.dib_getfromclipboard()
ls_filename = "c:\test.jpg"
lnvo_twain.dib_writetofilename(ll_dib_handle,ls_filename)
Le script et structures pour la fonction of_copy_clipboard_to_blob a été trouvé dans ce forum ;). MERCI.
Hors ligne
Merci à toi pour le retour.
Le passe les scripts avec la bonne balise pour qu'ils soient plus lisibles.
Hors ligne
Merci de ton retour
NB : ça serait parfait si tu ajoutais code=pb
Edit : argh à 6 secondes près
Hors ligne
Hors ligne
Bonjour,
je me permets de reouvrir ce post. Un nouveau challenge:
Quelqu'un aurait une solution pour faire un zoom in et zoom out de la webcam?
Toute solution est bien venue.
Hors ligne
Hello,
Tu parles d'un vrai Zoom (dans ce cas faut déjà que la webcam le permette, dispose d'un mécanisme de zoom Hardware)
ou bien un zoom numérique (avec tout ce que ça implique de dégradation de l'image, déjà souvent pas fameuse sur les webcams)
?
Hors ligne
C'est une Logitech c525, un zoom Hardware serait bien car la caméra le supporte, sinon avec la solution qu j'ai proposé, lors de la visualisation de faire un zoom et puis la photo.
Hors ligne
Je me suis mal exprimé. biensûr la webcam n'a pas un zoom hardware, mais bien un zoom numérique, donc comme dans une application d'utiliser le zoom pour la video et après de faire une image. S'il y a une petite perte de qualité ce n'est pas trop grave.
Hors ligne
Pas sûr que ça puisse t'aider vu que ça a l'air d'être un système différent du tien mais peut-être ça te mettra sur un piste.
http://web.archive.org/web/201110260415 … pplication
http://web.archive.org/web/201102031728 … operty-set
http://slworkthings.wordpress.com/2009/ … vc-driver/
Hors ligne
Je m'ensors pas avec tout ça. Selon des forums vaut mieux utiliser DirectShow. Quelqu'un a un exemple pour DirectShow sous Powerbuilder de A à Z. Je regarde chez MSDN, je trouve c'est lourd, n'arrive pas à lier le tout.
Une idée?
Hors ligne
Autre chose: selon les défintions MCIWNDM_SETZOOM est traité comme un message pour windows, donc comme pour les autres fonctions j'utilise Send(lhand, MCIWNDM_SETZOOM, 0, 200) où MCIWNDM_SETZOOM se déclare comme WM_USER + 108, mais cela ne fonctionne pas. Pourquoi?
Hors ligne
Quelqu'un peut essayer s'il arrive à zoomer avec MCIWNDM_SETZOOM car moi je n'y arrive pas, mais cela devrai fonctionner???
Hors ligne
Salut,
Faut vraiment que tu zoom sur la vidéo ? tu ne peux pas capturer une image puis zoomer cette image après ?
Hors ligne
L'idéé est de sauvegarde une image d'une webcam (photo d'une personne) => faire la photo et sauvgarder.
L'alternative que tu proposes est prendre la photo => sauvegarde temporaire => zoomer => sauvegarde définitive. C'est possible, je me demande comment faire pour zoomer dans une image? Sinon est-ce élégant? ;)
J'étais a 2 doigts d'acheter une OCX de Visioforge qui utilise Directshow je crois et arrive à zoomer, sauf qu'il n'arrive pas à sauvegarder directement l'image zoomée. J'utilise un screenshot de la zone conerné pour la sauvgardé, mais bon payer pour quelquechose qui ne fonctionne qu'à moitié.
C'est pour cela je crois que MCIWNDM_SETZOOM doit fonctionner puisque les autres fonctions pour gérer la webcam fonctionne sauf ça, je n'arrive pas à le faire fonctionner et pourtant ça a l'air facile d'intégrer. Si aumoins je connaiterai la raison pourquoi cela ne fonctionne pas, je lacherai l'affaire mais je n'abondonne pas aussi facilement ;).
Hors ligne
Pour zoomer tu as imagemagick que tu peux utiliser en ligne de commande
Sinon tu as GD Picture avec la partner edition http://www.orpalis.com/downloads/syncfusion-offer/ qui est gratuite et qui te permet de manipuler les images, attention pour GD Picture il faudra que tu fasses un petit wrapper en .net vu que l'objet COM ne fait pas partie cette edition
Ca c'est un petit exemple d'utilisation de GD Picture en VB.Net
J'ai fait une classe que j'utilise depuis PB 12.5 Classic (en OLE)
dans ton cas c'est évidemment d'autres fonctions qu'il va falloir appeler
Le plus simple reste quand même ImageMagick en ligne de commande (dans ce cas il est bon de passer par un run and wait)
Namespace SigmaVBHelpers <ComVisible(True)> _ <ProgId("BHelpers.PictureHandler")> _ <ClassInterface(ClassInterfaceType.AutoDual)> _ Public Class PictureHandler Private LicMgr As LicenseManager Private monImage As GdPictureImaging Private imageID As Int32 = 0 Private retourStatus As GdPictureStatus Private miniatureID As Int32 = 0 Private ImageInit As Boolean Private pSettings As Drawing.Printing.PrinterSettings Private pName As String Public Sub New() LicMgr = New LicenseManager() LicMgr.RegisterKEY("XXXXX") LicMgr = Nothing Me.ImageInit = False End Sub Protected Overrides Sub Finalize() Try monImage.ClearGdPicture() Catch ex As Exception Finally End Try Try monImage.Dispose() Catch ex As Exception Finally End Try End Sub Public Function CreerMiniatureImage(ByVal blob As Byte(), ByVal largeur As Int32, ByVal hauteur As Int32, ByRef bRet As Boolean) As Byte() Dim nbBytes As Int32 = 0 bRet = True If Not Me.ImageInit Then Me.monImage = New GdPictureImaging() Me.ImageInit = True End If Dim miniature As Byte() = New Byte() {} Me.imageID = monImage.CreateGdPictureImageFromByteArray(blob) If Me.imageID > 0 Then Me.miniatureID = monImage.CreateThumbnail(Me.imageID, largeur, hauteur) If Me.miniatureID > 0 Then monImage.SaveAsByteArray(Me.miniatureID, miniature, nbBytes, DocumentFormat.DocumentFormatJPEG, 80) monImage.ReleaseGdPictureImage(Me.miniatureID) Else bRet = False End If monImage.ReleaseGdPictureImage(Me.imageID) Else bRet = False End If GC.Collect() Return miniature End Function Public Function PrintImage(ByVal blob As Byte(), ByVal initPrinter As Boolean) As Boolean Dim bRet As Boolean = True If Not Me.ImageInit Then Me.monImage = New GdPictureImaging() Me.ImageInit = True End If Me.imageID = monImage.CreateGdPictureImageFromByteArray(blob) If Me.imageID > 0 Then If initPrinter Then monImage.PrintDialog(Me.imageID) pSettings = monImage.PrintGetPrinterSettings() pName = monImage.PrintGetActivePrinter() Else monImage.PrintSetPrinterSettings(pSettings) monImage.PrintSetActivePrinter(pName) monImage.Print(Me.imageID) End If monImage.ReleaseGdPictureImage(Me.imageID) Else bRet = False End If GC.Collect() Return bRet End Function End Class End Namespace
Dernière modification par _francois_ (06-11-2013 14:22:52)
Hors ligne
en fait si tu peux zoomer après que l'image soit sauvegardée je pensais à un truc encore plus simple comme par exemple afficher l'image dans un picture control dans une DW et après tu joues avec la propriété Zoom de la DW.
Comme de toutes façon ici on ne parles pas vraiment d'un vrai zoom (optique) mais d'un agrandissement de l'image affiché je pense que c'est pas plus ou moins propre qu'une autre solution.
Edit : non en fait je pense que c'est plus "propre" ou en tout cas préférable comme solution par rapport à utiliser un outil externe pour redimensionner la photo par exemple parceque utiliser un outil externe t'expose aux problèmes suivants :
- outil externe à gérer en plus de ton programme (installation, quid si outil pas présent sur le système quand on en a besoin)
- problèmes de droits d'accès ( au programme externe, aux fichiers concernés )
- bugs éventuels de l'outil externe
- etc.
perso je préfère faire tout ce que je peux avec le moins d'outils possible, moins t'utilises de trucs différents moins t'as de chances d'avoir des problèmes, rasoir d’Occam toussa...
Hors ligne
je suis d'accord c'est mieux d'utiliser du natif
par contre avec le zoom datawindow quid de la sauvegarde de l'image zoomée ?
Hors ligne
ben tu peux toujours sauver l'image de base d'un côté et le niveau de zoom voulu d'un autre puis tu combines les 2 quand tu en as besoin.
Hors ligne