Salve a tutti,
sto cercando di realizzare un sistema di analisi dell'immagine proveniente da una telecamera. L'analisi in se non è troppo difficile, si tratta di selezionare una area rettangolare (fissa) e controllare quanti pixel di questa area differiscono (con un certo margine) da un colore campione settato.
Per adesso, per fare una prova, ho solo calcolato il colore medio dell'area selezionata (tanto per far fare qualcosa al programma). Per quanto riguarda l'analisi dei pixel dell'area non ho problemi, almeno fino a quando lo posso fare con le normali istruzioni in VB, cicli, calcoli, ecc... Premetto che conosco VB abbastanza superficialmente, e tendo comunque per formazione a utilizzare istruzioni semplici anche per fare cose complesse...
Come telecamera sto usando una webcam (settata a 640x480). Per l'accesso alle immagini della webcam ho fatto un po' di copia e incolla su alcuni sorgenti trovati in rete, e grossomodo funziona. Purtroppo non ho capito come funzionano di preciso le istruzioni che mi creano l'immagine, quindi il programma sicuramente non è ottimizzato.
Il principale problema che ho adesso (e che mi aspettavo, ma almeno ho tentato di fare qualcosa da solo) è che il programma è troppo lento. In generale non riesco a caricare più di 10 immagini al secondo (sebbene tenti di caricarne 20, con un timer ciclico di 50 ms)... Se poi l'area di pixel da anlizzare cresce un pochino (al momento sto analizzando 6300 pixel) le immagini al secondo analizzate diminuiscono ancora (bene che vada ne analizzo 5 o 6). Poichè vorrei poter analizzare aree più vaste (in previsione di utilizzare immagini a risoluzione superiore, almeno 1024x768) e con maggiore velocità (20-25 frame al secondo), vorrei capire come poter ottimizzare il codice, o se magari conviene cambiare linguaggio di programmazione.
Questo è il codice del programma:
Form principale:
codice:
Option Explicit
Dim Frame_Per_Sec As Integer 'contatore frame per secondo elaborati
Dim Xcoord_start As Integer 'coordinate inizio area analizzata
Dim Ycoord_start As Integer 'coordinate inizio area analizzata
Dim Xcoord_end As Integer 'coordinate fine area analizzata
Dim Ycoord_end As Integer 'coordinate fine area analizzata
Dim hCap As Long
Private Sub cmdImpostazioniVideo_Click()
'Visualizza la finestra di dialogo per la modifica delle impostazioni video.
Call SendMessage(hCap, WM_CAP_DLG_VIDEOFORMAT, 0&, 0&)
End Sub
Private Sub Timer1_Timer()
'base tempi 50 ms, poi gira a quanto ce la fa...
'acquisisco una immagine
SendMessage hCap, WM_CAP_EDIT_COPY, 0&, 0&
picCam2.Picture = Clipboard.GetData
Dim pixelColor As Long 'variabile prelievo colore pixel
'variabili singoli colori
Dim red As Long 'le dichiaro long perchè sennò non funziona, chissà perchè...
Dim green As Long
Dim blue As Long
'variabili analisi colore per calcolo colore medio
Dim red_medium As Long
Dim green_medium As Long
Dim blue_medium As Long
Dim pixel_number As Long
'puntatori cicli
Dim i As Integer
Dim j As Integer
'inizializzazione variabili
pixel_number = 0
red_medium = 0
green_medium = 0
blue_medium = 0
Xcoord_start = 5
Xcoord_end = 634
Ycoord_start = 100
Ycoord_end = 109
'ciclo lettura pixel e calcolo media
For i = Xcoord_start To Xcoord_end
For j = Ycoord_start To Ycoord_end
pixelColor = GetPixel(picCam2.hdc, i, j) 'lettura colore pixel
blue = pixelColor \ 65536 'estrazione informazione blu
green = (pixelColor - blue * 65536) \ 256 'estrazione informazione verde
red = pixelColor - blue * 65536 - green * 256 'estrazione informazione rosso
red_medium = red_medium + red 'media colore rosso
green_medium = green_medium + green 'media colore verde
blue_medium = blue_medium + blue 'media colore blu
pixel_number = pixel_number + 1 'conteggio pixel analizzati
Next
Next
'visualizzazione numero pixel analizzati
Text1.Text = pixel_number
'calcolo e visualizzazione media colore area
Rout.Text = red_medium / pixel_number
Gout.Text = green_medium / pixel_number
Bout.Text = blue_medium / pixel_number
'disegno un rettangolo rosso intorno all'area analizzata
'riga superiore
For i = Xcoord_start To Xcoord_end
SetPixel picCam2.hdc, i, Ycoord_start, 255
Next
'riga inferiore
For i = Xcoord_start To Xcoord_end
SetPixel picCam2.hdc, i, Ycoord_end, 255
Next
'riga sinistra
For j = Ycoord_start To Ycoord_end
SetPixel picCam2.hdc, Xcoord_start, j, 255
Next
'riga destra
For j = Ycoord_start To Ycoord_end
SetPixel picCam2.hdc, Xcoord_end, j, 255
Next
'contatore frame per secondo analizzati
Frame_Per_Sec = Frame_Per_Sec + 1
End Sub
Private Sub Timer2_Timer()
'base tempi 1 secondo
'visualizzo il numero di frame per secondo analizzati e resetto il contatore
Text2.Text = Frame_Per_Sec
Frame_Per_Sec = 0
End Sub
Private Sub Form_Load()
hCap = capCreateCaptureWindow("Cattura immagini", WS_CHILD Or WS_VISIBLE, 0, 0, picCam.Width, picCam.Height, picCam.hWnd, 0)
If hCap <> 0 Then
Call SendMessage(hCap, WM_CAP_DRIVER_CONNECT, 0, 0)
Call SendMessage(hCap, WM_CAP_SET_PREVIEWRATE, 66, 0&)
Call SendMessage(hCap, WM_CAP_SET_PREVIEW, CLng(True), 0&)
End If
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
On Error Resume Next
Call SendMessage(hCap, WM_CAP_DRIVER_DISCONNECT, 0, 0)
If hCap <> 0 Then DestroyWindow (hCap)
Kill App.Path & "\Temp.bmp"
End Sub
Modulo:
codice:
Option Explicit
Public Const WS_CHILD As Long = &H40000000
Public Const WS_VISIBLE As Long = &H10000000
Public Declare Function capCreateCaptureWindow Lib "avicap32.dll" Alias "capCreateCaptureWindowA" (ByVal lpszWindowName As String, ByVal dwStyle As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hwndParent As Long, ByVal nID As Long) As Long
Public Const WM_USER As Long = &H400
Public Const WM_CAP_START As Long = WM_USER
Public Const WM_CAP_EDIT_COPY As Long = WM_USER + 30
Public Const WM_CAP_DRIVER_CONNECT As Long = WM_CAP_START + 10
Public Const WM_CAP_DRIVER_DISCONNECT As Long = WM_CAP_START + 11
Public Const WM_CAP_SET_PREVIEW As Long = WM_CAP_START + 50
Public Const WM_CAP_SET_PREVIEWRATE As Long = WM_CAP_START + 52
Public Const WM_CAP_DLG_VIDEOFORMAT As Long = WM_CAP_START + 41
Public Const WM_CAP_FILE_SAVEDIB As Long = WM_CAP_START + 25
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Public Declare Function DestroyWindow Lib "user32" (ByVal hWnd As Long) As Long
Public Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
Public Declare Function SetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
Nel form principale ho due picturebox (picCam e picCam2). Nella prima visualizzo direttamente quello che ricevo dalla webcam (non mi serve a nulla, ma il sorgente che ho copiato faceva così, e non so come toglierla), mentre nella seconda acquisisco una immagine ogni volta che devo fare l'analisi. Ho provato a fare l'analisi della prima immagine (stoppando la ricezione delle immagini dala webcam per avere un frame fisso) ma non riesco a prelevare il colore dei pixel, mentre dalla seconda immagine funziona.
Ho inoltre le seguenti textbox di output:
Rout: valore medio colore rosso
Gout: valore medio colore verde
Bout: valore medio colore blu
Text1: numero pixel analizzati
Text2: numero frame al secondo analizzati
Ho postato il codice del progetto, se può essere utile posso allegare in qualche modo anche tutto il progetto in VB.
Spero di non essermi dimenticato nulla di utile...
Grazie a tutti!