Sei sulla pagina 1di 52

STUDIO TEORICO PRATICO SPERIMENTALE RELATIVO A SISTEMA AUTOMATICO PER LIDENTIFICAZIONE DELLE VETTURE USATE PER LO SCARICO ABUSIVO

DI MATERIALE IN DISCARICHE NON AUTORIZZATE.

Studio e ricerche eseguite da Flavio Bernardotti & PINET mediante creazione di plugin da abbinare alla videosorveglianza intelligente FACESURVEIL installata nel sito di BORGOFRANCO di IVREA.

Il software FACESURVEIL installato di fatto una videosorveglianza avanzata la quale dopo aver ricevuto la segnalazione di un cambiamento nellimmagine ripresa registra quanto le telecamere inviano ma in pi analizza i frames cercando al loro interno gli oggetti che sono stati la causa dei cambiamenti e dopo averli identificati li estrae e li memorizza in un database associato ai filmati in modo che loperatore senza dover scorrere il filmato pu immediatamente sapere quale stata la causa. Le immagini estratte e memorizzate inoltre possono essere utilizzate da pacchetti plugin esterni indirizzati a svolgere funzioni come identificazioni delle persone, lidentificazione delle targhe o lapplicazione di qualsiasi altro algoritmo di computer vision.

La sperimentazione possedeva come scopo quello di dimostrare se con un sistema di costo medio come quello di una video sorveglianza era possibile creare processi ALGORITMICAMENTE complessi, COMPUTATIVAMENTE pesanti capaci di reggere in condizioni hardware, geografiche, climatiche e cromaticamente variabili. Lalgoritmo di base composto da varie fasi a partire dallestrazione della porzione immagine contenente la vettura, la memorizzazione e con le foto derivate dalle videocamere in senso inverso il riconoscimento in modo tale da poter eseguire il confronto volumetrico con la vettura giusta. Da qui anticipiamo che il cuore o lorgano algoritmico pi delicato e importante quello di riconoscimento.

PROBLEMI INIZIALI LEGATI ALLA TRASMISIONE DATI

Data la condizione e la posizione delle videocamere il primo grosso problema stato la stabilit della trasmissione dati la quale portava a distacchi continui delle videocamere. Il problema era contorto in quanto nei punti di lavoro distanti come quello nello studio PINET e in quello di Flavio Bernardotti la qualit spesso era accettabile cosa che invece non era nella posizione del server centrale posizionato nel comune di BORGOFRANCO. La ricerca delle cause stato lungo e complesso proprio per la complessit della struttura mista della rete.

CONDIZIONI

Nel comune di Borgofranco d Ivrea stato installato un sistema di videosorveglianza composto dal software FACESURVEIL, da 5 videocamere VIVOTEK 7151 e da una rete WIRELESS ad a elevate prestazioni che stato utilizzato per il controllo delle aree ecologiche e come base per la verifica della possibilit di creare un sistema per il controllo volumetrico degli automezzi in relazione alla discarica abusiva di materiale vario.

La strada che porta alla discarica presuppone che la vettura ritorni per la stessa via e quindi in caso di differenze di materiale di carico il sistema di videocamere dopo identificazione dovrebbe verificare le differenze. Su una strada di montagna due telecamere sono piazzate in modo di riprendere le vetture che percorrono la strada in salita, sia come fronte che come retro e in senso contrario la stessa cosa.

VIVOTEK 7151

Features
Embedded Video Content Analysis SONY Progressive Scan CCD Module in VGA Resolution 2.9mm~8.2mm Vari-focal, Auto-iris Lens Removable IR-cut Filter for Day & Night Function Real-time MPEG-4 and MJPEG Compression (Dual Codec) Dual Streams Simultaneously Built-in 802.3af Compliant PoE Two-way Audio via SIP Protocol Digital I/O for External Sensor and Alarm RS-485 Interface for Scanners, Pan/Tilts

SystemCPU: VVTK-1000 SoC Flash: 8MB RAM: 64MB Embedded OS: Linux 2.4Lensf = 2.9 ~ 8.2 mm F 1.0 auto iris CS-mount vari-focal Removable IR-cut filter for day & night function Angle of View26.7 ~ 69.0 (horizontal) 20.0 ~ 51.0 (vertical) Shutter Time1/30 ~ 1/15,000 secImage sensor1/4" SONY progressive scan CCD in VGA ResolutionMinimum Illumination1.0 Lux / F1.0 ( typical ) VideoCompression: MJPEG & MPEG-4 Streaming: Simultaneous multiple streams MPEG-4 streaming over UDP, TCP, HTTP or HTTPS MPEG-4 multicast streaming MJPEG streaming over HTTP or HTTPS Supports 3GPP mobile surveillance Frame rates: MPEG-4: Up to 30/25 fps at 640x480, MJPEG: Up to 30/25 fps at 640x480, Image SettingsAdjustable image size, quality, and bit rate Time stamp and text caption overlay Flip & mirror Configurable brightness, contrast, saturation, sharpness, white balance and exposure AGC AWB AES Automatic, manual or scheduled day/night mode Supports privacy masks BLC (Backlight compensation) AudioCompression

GSM-AMR speech encoding, bit rate: 4.75 kbps to 12.2 kbps MPEG-4 AAC audio encoding, bit rate: 16 kbps to 128 kbps Interface: Built-in microphone External microphone input Audio output Supports two-way audio via SIP protocolGeneral I/O Supports audio mute Networking10/100 Mbps Ethernet, RJ-45 Protocols: IPv4, TCP/IP, HTTP, UPnP, RTSP/RTP/RTCP, IGMP, SMTP, FTP, DHCP, NTP, DNS, DDNS and PPPoEAlarm and Event ManagementTriple-window video motion detection One D/I and one D/O for external sensor and alarm Event notification using HTTP, SMTP, or FTP Local recording of MP4 files SecurityMulti-level user access with password protection IP address filtering Users10 clients on-line monitoring at the same timeDimensionsDepth: 205.5mm Width: 82.1mm Height: 51.2mm WeightNet: 568 gLED IndicatorSystem power and status indicator System activity and network link indicator Power12V DC 24V AC Power consumption: Max. 6 W 802.3af compliant Power-over-EthernetApprovalsCE C-Tick FCC LVD VCCI Operating EnvironmentsTemperature: 0 ~ 50 C (32 ~ 122 F) Humidity: 20% ~ 80% Viewing System RequirementsOS: Microsoft Windows 2000/XP/Vista Browser: Mozilla Firefox, Internet Explorer 6.x or above Cell phone: 3GPP player Real Player: 10.5 or above Quick Time: 6.5 or aboveInstallation, Management, and MaintenanceInstallation Wizard 2 32-CH central management software Supports firmware upgrade ApplicationsSDK available for application development and system integrationWarranty24 months

Il sistema per limitare le distorsioni dovute ai corpi in rapido movimento utilizza un sistema di SCAN PROGRESSIVO.

Le videocamere sono VIVOTEK 7151 ad IP le quali sfruttano una rete WIRELESS creata appositamente per la struttura in questione. Lalgoritmo dovrebbe essere composto dai seguenti steps logici. 1 ) La videocamera che guarda verso la parte bassa della strada a seguito di una segnalazione di movimento cattura le immagini della vettura.

Il punto cruciale di tutto il sistema il riconoscimento delle vetture ovvero quello che dice che la vettura che era salita ore prima anche quella discesa. Per fare questo nella sperimentazione in base alle condizioni varie che era possibile avere si potevano tentare di usare algoritmi vari e precisamente di due classi separate. 1 2 Algoritmi di MATCHING quali SIFT, SURF ecc. Algoritmi di MATCHING per lidentificazione del punto dove si trovava la targa e poi di OCR per lidentificazione del numero di targa.

In condizioni ideali il riconoscimento targhe risulta quello ottimale. Lutilizzo di algoritmi di MATCHING pretende la purificazione dellimmagine eliminando la parti che non verrebbero usate nel sistema di riconoscimento. Per fare questo un algoritmo di blob riconosce la parte del camion.

Il codice orientativo il seguente :


#include <cv.h> #include <highgui.h> IplImage* img,*pimg,*timg,*mimg; void Process(); int main( ) { Process(); if(img){ cvNamedWindow( "Source", 1 ); cvShowImage( "Source", img ); } if(pimg){ cvNamedWindow( "Processed Image", 1 ); cvShowImage( "Processed Image", pimg ); } cvWaitKey(0); if(img) cvReleaseImage(&img); if(pimg) cvReleaseImage(&pimg); } void Process() { /* Loads Images */ if(img) cvReleaseImage(&img); img=cvLoadImage( "c://borgo//camion1.bmp ", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR ); /* Converts image from color space ( RGB ) to a Gray Scale */ if(pimg) cvReleaseImage(&pimg); pimg = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 ); cvCvtColor( img, pimg, CV_RGB2GRAY ); /* Copy Image2 to Image1 */ if(img) cvReleaseImage(&img); img=cvCloneImage(pimg); /* Equalizes histogram of grayscale image */

if(pimg) cvReleaseImage(&pimg); pimg = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 ); cvEqualizeHist(img,pimg); /* Copy Image2 to Image1 */ if(img) cvReleaseImage(&img); img=cvCloneImage(pimg); /* Aplly Sobel Edge-Detection Operation */ if(pimg) cvReleaseImage(&pimg); timg = cvCreateImage (cvGetSize (img), IPL_DEPTH_16S, 1); pimg = cvCreateImage (cvGetSize (img), IPL_DEPTH_8U, 1); cvSobel (img, timg, 1, 0, -1); cvConvertScaleAbs (timg, pimg); cvReleaseImage (&timg); /* Aplly Laplace Edge-Detection Operation */ if(pimg) cvReleaseImage(&pimg); timg = cvCreateImage (cvGetSize (img), IPL_DEPTH_16S, 1); pimg = cvCreateImage (cvGetSize (img), IPL_DEPTH_8U, 1); cvLaplace (img, timg, -1); cvConvertScaleAbs (timg, pimg); cvReleaseImage (&timg); /* Aplly Canny Edge-Detection Operation */ if(pimg) cvReleaseImage(&pimg); pimg = cvCreateImage (cvGetSize (img), IPL_DEPTH_8U, 1); cvCanny (img, pimg, 50, 150, 3); /* Aplly Black Hat Morphological Operation */ { IplConvKernel *element; if(pimg) cvReleaseImage(&pimg); pimg= cvCloneImage (img); element = cvCreateStructuringElementEx (3,3,2,2,CV_SHAPE_RECT, NULL); timg= cvCloneImage (img); cvMorphologyEx (img, pimg, timg,element,CV_MOP_BLACKHAT , 1); cvReleaseImage (&timg); cvReleaseStructuringElement(&element ); } /* Aplly Top Hat Morphological Operation */ { IplConvKernel *element; if(pimg) cvReleaseImage(&pimg); pimg= cvCloneImage (img); element = cvCreateStructuringElementEx (3,3,2,2,CV_SHAPE_RECT, NULL); timg= cvCloneImage (img); cvMorphologyEx (img, pimg, timg,element,CV_MOP_TOPHAT , 1); cvReleaseImage (&timg); cvReleaseStructuringElement(&element ); } /* Normal Threshold of image */ if(pimg) cvReleaseImage(&pimg);

pimg= cvCloneImage (img); cvThreshold (img, pimg, 128, 255, CV_THRESH_BINARY ); }

Limmagine estratta viene memorizzata :

Dopo la memorizzazione la seconda videocamera sempre attivata dal motion inizierebbe la ripresa della salita del camion verso la sommit della strada.

Lo stesso procedimento per identificare La posizione del camion ed estrapolarlo dal resto dellimmagine viene eseguito.

Il codice simile a questo : #include <cv.h> #include <highgui.h> IplImage* img,*pimg,*timg,*mimg; void Process(); int main( ) { Process(); if(img){ cvNamedWindow( "Source", 1 ); cvShowImage( "Source", img ); } if(pimg){ cvNamedWindow( "Processed Image", 1 ); cvShowImage( "Processed Image", pimg ); }

cvWaitKey(0); if(img) cvReleaseImage(&img); if(pimg) cvReleaseImage(&pimg); } void Process() { /* Loads Images */ if(img) cvReleaseImage(&img); img=cvLoadImage( "c://Borgo//camion4.BMP ", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR ); /* Converts image from color space ( RGB ) to a Gray Scale */ if(pimg) cvReleaseImage(&pimg); pimg = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 ); cvCvtColor( img, pimg, CV_RGB2GRAY ); /* Copy Image2 to Image1 */ if(img) cvReleaseImage(&img); img=cvCloneImage(pimg); /* Equalizes histogram of grayscale image */ if(pimg) cvReleaseImage(&pimg); pimg = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 ); cvEqualizeHist(img,pimg); /* Aplly Top Hat Morphological Operation */ { IplConvKernel *element; if(pimg) cvReleaseImage(&pimg); pimg= cvCloneImage (img); element = cvCreateStructuringElementEx (3,3,2,2,CV_SHAPE_RECT, NULL); timg= cvCloneImage (img); cvMorphologyEx (img, pimg, timg,element,CV_MOP_TOPHAT , 1); cvReleaseImage (&timg); cvReleaseStructuringElement(&element ); } /* Aplly Gradiant Morphological Operation */ { IplConvKernel *element; if(pimg) cvReleaseImage(&pimg); pimg= cvCloneImage (img); element = cvCreateStructuringElementEx (3,3,2,2,CV_SHAPE_RECT, NULL); timg= cvCloneImage (img); cvMorphologyEx (img, pimg, timg,element,CV_MOP_GRADIENT , 1); cvReleaseImage (&timg);

cvReleaseStructuringElement(&element ); } /* Equalizes histogram of grayscale image */ if(pimg) cvReleaseImage(&pimg); pimg = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 ); cvEqualizeHist(img,pimg); /* Normal Threshold of image */ if(pimg) cvReleaseImage(&pimg); pimg= cvCloneImage (img); cvThreshold (img, pimg, 128, 255, CV_THRESH_BINARY ); /* Adaptive Threshold of image */ if(pimg) cvReleaseImage(&pimg); pimg= cvCloneImage (img); cvAdaptiveThreshold(img, pimg, 255, CV_THRESH_BINARY , CV_THRESH_BINARY ,3 , 5 ); /* Normal Threshold of image */ if(pimg) cvReleaseImage(&pimg); pimg= cvCloneImage (img); cvThreshold (img, pimg, 128, 255, CV_THRESH_BINARY_INV );

} Limmagine quindi viene memorizzata in copia con laltra.

<<<

IL RITORNO Le procedure del ritorno sono le stesse dellandata solo che dopo le memorizzazioni in questa fase avviene il riconoscimento delle vetture. IN PRATICA LALGORITMO DEL RITORNO E UGUALE A QUELLO DELLANDATA SE NON PER IL FATTO CHE NELLLA PARTE FINALE ATTIVA LALGORITMO DI RICONOSCIMENTO CON LE MACCHINE REGISTRATE ALLANDATA. LE MACCHINE REGISTRATE ALLANDATA DOPO N ORE VENGONO ELIMINATE. SE LA VETTURA E RICONOSCIUTA ALLORA LE DUE FOTO DEI RETRI VENGONO RICOSTRUITI GEOMETRICAMENTE PER POTER ESEGUIRE UN CONFRONTO VOLUMETRICO.

Proprio a seguito di questo riconoscimento avviene la comparazione dei retri delle vetture per comprendere se il carico cambiato. In questa fase si sono verificate le piu grosse problematiche a causa delle condizioni climatiche, della velocit delle macchine che non permettevano riprese perfette. Come detto precedentemente il riconoscimento perfetto sarebbe stato quello con le targhe.

Gli algoritmi alternativi di riconoscimento potevano essere lalgoritmo di SIFT. Purtroppo lalgoritmo di SIFT permette il riconoscimento di vetture come dimostrato dalla ricerca presente su http://visionofcars.blogspot.com/ solo in condizioni ottimali delle immagini. Lambiente di ripresa purtroppo possiede degli sfondi come lerba che creano falsi obiettivi. Le vetture che viaggiano troppo velocemente creano immagini sfumate povere di particolari.

I pali eccessivamente alti che spesso oscillano per il vento. Gli algoritmi di matching devono avere particolari ben distinti e non sfocati se no la loro identificazione diventa impossibile.

Con immagini pi definite il sistema identifica il mezzo creando il rettangolo che mostra linclinazione diversa e lle linee di corrispondenza.

Purtroppo il margine derrore troppo elevato per essere usato per un riconoscimento. Si deve considerare che il sistema lavora con foto in bianco e nero a causa delluso degli illuminatori a infrarossi. Questo purtroppo lo standard delle immagini :

Lalgoritmo di SURF usato :

#include <cv.h>

#include <highgui.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <vector> using namespace std; IplImage *image = 0; double compareSURFDescriptors( const float* d1, const float* d2, double best, int length ) { double total_cost = 0; assert( length % 4 == 0 ); for( int i = 0; i < length; i += 4 ) { double t0 = d1[i] - d2[i]; double t1 = d1[i+1] - d2[i+1]; double t2 = d1[i+2] - d2[i+2]; double t3 = d1[i+3] - d2[i+3]; total_cost += t0*t0 + t1*t1 + t2*t2 + t3*t3; if( total_cost > best ) break; } return total_cost; } int naiveNearestNeighbor( const float* vec, int laplacian, const CvSeq* model_keypoints, const CvSeq* model_descriptors ) { int length = (int)(model_descriptors->elem_size/sizeof(float)); int i, neighbor = -1; double d, dist1 = 1e6, dist2 = 1e6; CvSeqReader reader, kreader; cvStartReadSeq( model_keypoints, &kreader, 0 ); cvStartReadSeq( model_descriptors, &reader, 0 ); for( i = 0; i < model_descriptors->total; i++ ) { const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr; const float* mvec = (const float*)reader.ptr; CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader ); CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader ); if( laplacian != kp->laplacian ) continue; d = compareSURFDescriptors( vec, mvec, dist2, length ); if( d < dist1 ) { dist2 = dist1; dist1 = d; neighbor = i; } else if ( d < dist2 ) dist2 = d; } if ( dist1 < 0.6*dist2 ) return neighbor; return -1; } void findPairs( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors, const CvSeq* imageKeypoints, const CvSeq* imageDescriptors, vector<int>& ptpairs ) { int i; CvSeqReader reader, kreader; cvStartReadSeq( objectKeypoints, &kreader );

cvStartReadSeq( objectDescriptors, &reader ); ptpairs.clear(); for( i = 0; i < objectDescriptors->total; i++ ) { const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr; const float* descriptor = (const float*)reader.ptr; CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader ); CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader ); int nearest_neighbor = naiveNearestNeighbor( descriptor, kp->laplacian, imageKeypoints, imageDescriptors ); if( nearest_neighbor >= 0 ) { ptpairs.push_back(i); ptpairs.push_back(nearest_neighbor); } } } /* a rough implementation for object location */ int locatePlanarObject( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors, const CvSeq* imageKeypoints, const CvSeq* imageDescriptors, const CvPoint src_corners[4], CvPoint dst_corners[4] ) { double h[9]; CvMat _h = cvMat(3, 3, CV_64F, h); vector<int> ptpairs; vector<CvPoint2D32f> pt1, pt2; CvMat _pt1, _pt2; int i, n; findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs ); n = ptpairs.size()/2; if( n < 4 ) return 0; pt1.resize(n); pt2.resize(n); for( i = 0; i < n; i++ ) { pt1[i] = ((CvSURFPoint*)cvGetSeqElem(objectKeypoints,ptpairs[i*2]))->pt; pt2[i] = ((CvSURFPoint*)cvGetSeqElem(imageKeypoints,ptpairs[i*2+1]))->pt; } _pt1 = cvMat(1, n, CV_32FC2, &pt1[0] ); _pt2 = cvMat(1, n, CV_32FC2, &pt2[0] ); if( !cvFindHomography( &_pt1, &_pt2, &_h, CV_RANSAC, 5 )) return 0; for( i = 0; i < 4; i++ ) { double x = src_corners[i].x, y = src_corners[i].y; double Z = 1./(h[6]*x + h[7]*y + h[8]); double X = (h[0]*x + h[1]*y + h[2])*Z; double Y = (h[3]*x + h[4]*y + h[5])*Z; dst_corners[i] = cvPoint(cvRound(X), cvRound(Y)); } return 1; } int main(int argc, char** argv) { const char* object_filename = argc == 3 ? argv[1] : "box.png"; const char* scene_filename = argc == 3 ? argv[2] : "box_in_scene.png"; CvMemStorage* storage = cvCreateMemStorage(0); cvNamedWindow("Object", 1); cvNamedWindow("Object Correspond", 1); static CvScalar colors[] =

{ {{0,0,255}}, {{0,128,255}}, {{0,255,255}}, {{0,255,0}}, {{255,128,0}}, {{255,255,0}}, {{255,0,0}}, {{255,0,255}}, {{255,255,255}} }; IplImage* object = cvLoadImage( object_filename, CV_LOAD_IMAGE_GRAYSCALE ); IplImage* image = cvLoadImage( scene_filename, CV_LOAD_IMAGE_GRAYSCALE ); if( !object || !image ) { fprintf( stderr, "Can not load %s and/or %s\n" "Usage: find_obj [<object_filename> <scene_filename>]\n", object_filename, scene_filename ); exit(-1); } IplImage* object_color = cvCreateImage(cvGetSize(object), 8, 3); cvCvtColor( object, object_color, CV_GRAY2BGR ); CvSeq *objectKeypoints = 0, *objectDescriptors = 0; CvSeq *imageKeypoints = 0, *imageDescriptors = 0; int i; CvSURFParams params = cvSURFParams(500, 1); double tt = (double)cvGetTickCount(); cvExtractSURF( object, 0, &objectKeypoints, &objectDescriptors, storage, params ); printf("Object Descriptors: %d\n", objectDescriptors->total); cvExtractSURF( image, 0, &imageKeypoints, &imageDescriptors, storage, params ); printf("Image Descriptors: %d\n", imageDescriptors->total); tt = (double)cvGetTickCount() - tt; printf( "Extraction time = %gms\n", tt/(cvGetTickFrequency()*1000.)); CvPoint src_corners[4] = {{0,0}, {object->width,0}, {object->width, object->height}, {0, object->height}}; CvPoint dst_corners[4]; IplImage* correspond = cvCreateImage( cvSize(image->width, object->height+image->height), 8, 1 ); cvSetImageROI( correspond, cvRect( 0, 0, object->width, object->height ) ); cvCopy( object, correspond ); cvSetImageROI( correspond, cvRect( 0, object->height, correspond->width, correspond->height ) ); cvCopy( image, correspond ); cvResetImageROI( correspond ); if( locatePlanarObject( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, src_corners, dst_corners )) { for( i = 0; i < 4; i++ ) { CvPoint r1 = dst_corners[i%4]; CvPoint r2 = dst_corners[(i+1)%4]; cvLine( correspond, cvPoint(r1.x, r1.y+object->height ), cvPoint(r2.x, r2.y+object->height ), colors[8] ); } } vector<int> ptpairs; findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs ); for( i = 0; i < (int)ptpairs.size(); i += 2 ) { CvSURFPoint* r1 = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, ptpairs[i] ); CvSURFPoint* r2 = (CvSURFPoint*)cvGetSeqElem( imageKeypoints, ptpairs[i+1] ); cvLine( correspond, cvPointFrom32f(r1->pt), cvPoint(cvRound(r2->pt.x), cvRound(r2->pt.y+object->height)), colors[8] ); } cvShowImage( "Object Correspond", correspond ); for( i = 0; i < objectKeypoints->total; i++ ) { CvSURFPoint* r = (CvSURFPoint*)cvGetSeqElem( objectKeypoints, i ); CvPoint center; int radius; center.x = cvRound(r->pt.x);

center.y = cvRound(r->pt.y); radius = cvRound(r->size*1.2/9.*2); cvCircle( object_color, center, radius, colors[0], 1, 8, 0 ); } cvShowImage( "Object", object_color ); cvWaitKey(0); cvDestroyWindow("Object"); cvDestroyWindow("Object SURF"); cvDestroyWindow("Object Correspond"); return 0; }

Qui a seguito sono riportati gli algoritmi per le comparazioni basandosi su vaRIE RICOSTRUZIONI.

CAR COLOR DETECT

#include <iostream> #include <string> #include <iomanip>

#include <fstream> #include <cmath> #include <vector> using namespace std; //struct for holding rgb color values typedef struct { int r,g,b; } rgb; const int NUMANGLES = 260; const int NUMDIST = 260; int main(int argc, char *argv[]){ string magicnum, comment; int height, width, range; int color_threshhold = 50; int near_threshhold = 3; int blocklen = 32; vector<rgb> colors; rgb blue, orange; blue.r = 66; blue.g = 99; blue.b = 176; orange.r = 203; orange.g = 130; orange.b = 35; colors.push_back(blue); colors.push_back(orange); ifstream in; cout << "opening file: " << argv[1] << endl; in.open(argv[1], ios::in); getline(in, magicnum); if(!(magicnum == "P3")){ cout << "error: image is not of type PPM!" << endl; return 0; } getline(in, comment); in >> width; in >> height; in >> range; cout << "width: " << width << " height: " << height << " range: " << range << endl;

rgb** ppm = new rgb*[height]; for(int k = 0; k < height; k++) ppm[k] = new rgb[width]; rgb** blocks = new rgb*[height/blocklen]; for(int k = 0; k < height/blocklen; k++) blocks[k] = new rgb[width/blocklen]; int** car_blocks = new int*[height/blocklen]; for(int k = 0; k < height/blocklen; k++) car_blocks[k] = new int[width/blocklen]; int** pos_blocks = new int*[height/blocklen]; for(int k = 0; k < height/blocklen; k++) pos_blocks[k] = new int[width/blocklen]; cout << "reading file... " << endl; //read the input file into an array of rgb data structures for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ in >> ppm[y][x].r; in >> ppm[y][x].g; in >> ppm[y][x].b; } } in.close(); cout << "done. calculating color values... " << endl; for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ blocks[y/blocklen][x/blocklen].r += ppm[y][x].r; blocks[y/blocklen][x/blocklen].b += ppm[y][x].b; blocks[y/blocklen][x/blocklen].g += ppm[y][x].g; } } cout << "averaging... " << endl; for(int y = 0; y < height/blocklen; y++){ for(int x = 0; x < width/blocklen; x++){ blocks[y][x].r = blocks[y][x].r/(blocklen*blocklen); blocks[y][x].g = blocks[y][x].g/(blocklen*blocklen); blocks[y][x].b = blocks[y][x].b/(blocklen*blocklen); } } cout << "done.\ndetecting car... " << endl; for(int y = 0; y < height/blocklen; y++){ for(int x = 0; x < width/blocklen; x++){ for(int k = 0; k < colors.size(); k++){ if(abs(blocks[y][x].r - colors.at(k).r) < color_threshhold && abs(blocks[y][x].g - colors.at(k).g) < color_threshhold && abs(blocks[y][x].b - colors.at(k).b) < color_threshhold){ pos_blocks[y][x] = 1; } } } }

cout << "done.\nremoving false positives... " << endl; for(int y = 0; y < height/blocklen; y++){ for(int x = 0; x < width/blocklen; x++){ int near = 0; int yoff = 0; int xoff = 1; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; } yoff = 0; xoff = -1; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; } yoff = 1; xoff = 0; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; } yoff = -1; xoff = 0; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; } yoff = 1; xoff = 1; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; } yoff = 1; xoff = -1; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; } yoff = -1; xoff = 1; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; }

yoff = -1; xoff = -1; if(y+yoff > -1 && y+yoff < height/blocklen && x+xoff > -1 && x+xoff < width/blocklen) if(pos_blocks[y+yoff][x+xoff] == 1){ near++; } if(near > near_threshhold) car_blocks[y][x] = 1; } } cout << "done.\nbeginning output... " << endl; //output the pixel-blocked image fstream out1; out1.open("blocks.ppm", fstream::out); out1 << "P3" << endl; comment = "#created by Andrew Stebbins"; out1 << comment << endl; out1 << (width/blocklen) << " " << (height/blocklen) << endl; out1 << range << endl; for(int y = 0; y < height/blocklen; y++){ for(int x = 0; x < width/blocklen; x++){ out1 << blocks[y][x].r << endl; out1 << blocks[y][x].g << endl; out1 << blocks[y][x].b << endl; } } out1.close(); //output original image with outlined car fstream out2; out2.open("foundcar.ppm", fstream::out); out2 << "P3" << endl; comment = "#created by Andrew Stebbins"; out2 << comment << endl; out2 << width << " " << height << endl; out2 << range << endl; bool color = false; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ if(car_blocks[y/blocklen][x/blocklen] == 1){ out2 << ppm[y][x].r << endl; out2 << ppm[y][x].g << endl; out2 << ppm[y][x].b << endl; } else{ out2 << 0 << endl; out2 << 0 << endl; out2 << 0 << endl; } } }

out2.close(); cout << "done.\n"; return 0; }

EDGE DETECT #include <iostream> #include <string> #include <iomanip> #include <fstream> #include <cmath> using namespace std; //struct for holding rgb color values typedef struct { int r,g,b; } rgb; int main(int argc, char *argv[]){ string magicnum, comment; int height, width, range; int edge_threshhold = 130; int hysteresis_threshold = 100; ifstream in; cout << "opening file: " << argv[1] << endl; in.open(argv[1], ios::in); getline(in, magicnum); if(!(magicnum == "P3")){ cout << "error: image is not of type PPM!" << endl; return 0; } getline(in, comment); in >> width; in >> height; in >> range;

cout << "width: " << width << " height: " << height << " range: " << range << endl; rgb** ppm = new rgb*[height]; for(int k = 0; k < height; k++) ppm[k] = new rgb[width]; int** pgm = new int*[height]; for(int k = 0; k < height; k++) pgm[k] = new int[width]; int** smoothed = new int*[height]; for(int k = 0; k < height; k++) smoothed[k] = new int[width]; int** edges = new int*[height]; for(int k = 0; k < height; k++) edges[k] = new int[width]; int** gx = new int*[height]; for(int k = 0; k < height; k++) gx[k] = new int[width]; int** gy = new int*[height]; for(int k = 0; k < height; k++) gy[k] = new int[width]; cout << "reading file... " << endl; //read the input file into an array of rgb data structures for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ in >> ppm[y][x].r; in >> ppm[y][x].g; in >> ppm[y][x].b; } } in.close(); cout << "done.\ngenerating grayscale image... " << endl; //generate a greyscale representation of the input file for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ pgm[y][x] = (ppm[y][x].r + ppm[y][x].g + ppm[y][x].b)/3; } } cout << "done.\napplying gaussian filtering... " << endl; //generate a flattened grayscale image using gaussian filtering for(int y = 1; y < height-1; y++){ for(int x=1; x < width-1; x++){ smoothed[y][x]=(pgm[y][x]*4+pgm[y-1][x]*2+pgm[y+1][x]*2+pgm[y][x1]*2+pgm[y][x+1]*2+pgm[y-1][x+1]*1+pgm[y-1][x-1]*1+pgm[y+1][x+1]*1+pgm[y+1][x-1]*1)/16;

} } cout << "done.\ndetecting edges... " << endl; //detect edges, setting color value to 256 out of a possible 255 if an edge pixel is found to signify an edge pixel for(int y = 2; y < height-2; y++){ for(int x = 2; x < width-2; x++){ if(y>0){ gx[y][x] = smoothed[y][x-1]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1); gy[y][x] = smoothed[y-1][x]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y-1][x+1]*(1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1); if(abs(abs(gx[y][x])+abs(gy[y][x]))>edge_threshhold){ edges[y][x] = abs(gx[y][x])+abs(gy[y][x]); } } } } //apply non-maximum suppression for(int y = 2; y < height-2; y++){ for(int x = 2; x < width-2; x++){ if(abs(gx[y][x])>abs(gy[y][x])){ if(gx[y][x]<0){ if(gx[y][x-1]<gx[y][x] || gx[y][x+1]<gx[y][x]) edges[y][x] = 0; } else { if(gx[y][x+1]>gx[y][x] || gx[y][x-1]>gx[y][x]) edges[y][x] = 0; } } else if(abs(gx[y][x])<abs(gy[y][x])){ if(gy[y][x]<0){ if(gy[y-1][x]<gy[y][x] || gy[y+1][x]<gy[y][x]) edges[y][x] = 0; } else { if(gy[y+1][x]>gy[y][x] || gy[y-1][x]>gy[y][x]) edges[y][x] = 0; } } } } cout << "done.\nbeginning output... " << endl;

//output the smoothed grayscale image with no edge superposition fstream out1; out1.open("output.pgm", fstream::out); out1 << "P2" << endl; out1 << comment << endl; out1 << width << " " << height << endl; out1 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ out1 << smoothed[y][x] << endl; } } out1.close(); comment = "#created by Andrew Stebbins"; //output the detected edges fstream out2; out2.open("output.ppm", fstream::out); out2 << magicnum << endl; out2 << comment << endl; out2 << width << " " << height << endl; out2 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ /* //if edge pixel, make red if(edges[y][x] == 256){ out2 << 255 << endl; out2 << 0 << endl; out2 << 0 << endl; } else{ out2 << 0 << endl; out2 << 0 << endl; out2 << 0 << endl; } */ out2 << edges[y][x] << endl; out2 << edges[y][x] << endl; out2 << edges[y][x] << endl; } }

out2.close(); cout << "done." << endl; return 0; }

LINE DETECT

#include <iostream> #include <string> #include <iomanip> #include <fstream> #include <map> #include <cmath> using namespace std; //struct for holding rgb color values typedef struct { int r,g,b; } rgb; const int NUMANGLES = 240; const int NUMDIST = 240; const double RELATIVE_LINE_THRESHOLD = 0.4; //relative percentage of the image's diagonal int main(int argc, char *argv[]){ string magicnum, comment; int height, width, range; int edge_threshhold = 120; int line_threshhold = 0; //this will change as soon we get the width/height of the image ifstream in; cout << "opening file: " << argv[1] << endl; in.open(argv[1], ios::in); getline(in, magicnum); if(!(magicnum == "P3")){ cout << "error: image is not of type PPM!" << endl; return 0; }

getline(in, comment); in >> width; in >> height; in >> range; cout << "width: " << width << " height: " << height << " range: " << range << endl; double MAXDIST = width*cos(3.14159/4.0) + height*sin(3.14159/4.0); line_threshhold = (int)(sqrt((double)height*(double)height+(double)width*(double)width)*RELATIVE_LINE_THRESHOLD); cout << "threshold: " << line_threshhold << endl; cout << "initializing arrays... " << endl; cout << "ppm" << endl; rgb** ppm = new rgb*[height]; for(int k = 0; k < height; k++){ ppm[k] = new rgb[width]; for(int c = 0; c < width; c++){ ppm[k][c].r = 0; ppm[k][c].g = 0; ppm[k][c].b = 0; } } cout << "pgm" << endl; int** pgm = new int*[height]; for(int k = 0; k < height; k++){ pgm[k] = new int[width]; for(int c = 0; c < width; c++){ pgm[k][c] = 0; } } cout << "smoothed" << endl; int** smoothed = new int*[height]; for(int k = 0; k < height; k++){ smoothed[k] = new int[width]; for(int c = 0; c < width; c++){ smoothed[k][c] = 0; } } cout << "edges" << endl; int** edges = new int*[height]; for(int k = 0; k < height; k++){

edges[k] = new int[width]; for(int c = 0; c < width; c++){ edges[k][c] = 0; } } cout << "lines" << endl; int** lines = new int*[height]; for(int k = 0; k < height; k++){ lines[k] = new int[width]; for(int c = 0; c < width; c++){ lines[k][c] = 0; } } cout << "accum" << endl; int** accumulator = new int*[NUMANGLES]; for(int k = 0; k < NUMANGLES; k++){ accumulator[k] = new int[NUMDIST]; for(int c = 0; c < NUMDIST; c++){ accumulator[k][c] = 0; } } cout << "done." << endl; cout << "reading file... " << endl; //read the input file into an array of rgb data structures for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ in >> ppm[y][x].r; in >> ppm[y][x].g; in >> ppm[y][x].b; } } in.close(); cout << "done.\ngenerating grayscale image... " << endl; //generate a greyscale representation of the input file for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ pgm[y][x] = (ppm[y][x].r + ppm[y][x].g + ppm[y][x].b)/3; } } cout << "done.\napplying gaussian filtering... " << endl;

//generate a flattened grayscale image using gaussian filtering for(int y = 1; y < height-1; y++){ for(int x=1; x < width-1; x++){ smoothed[y][x]=(pgm[y][x]*4+pgm[y-1][x]*2+pgm[y+1][x]*2+pgm[y][x1]*2+pgm[y][x+1]*2+pgm[y-1][x+1]*1+pgm[y-1][x-1]*1+pgm[y+1][x+1]*1+pgm[y+1][x-1]*1)/16; } } cout << "done.\ndetecting edges... " << endl; //detect edges, setting color value to 256 out of a possible 255 if an edge pixel is found to signify an edge pixel for(int y = 2; y < height-2; y++){ for(int x=2; x < width-2; x++){ if(y>0){ int gx = smoothed[y][x-1]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1); int gy = smoothed[y-1][x]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y-1][x+1]*(1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1); if(abs(abs(gx)+abs(gy))>edge_threshhold){ edges[y][x] = 256; } } } } cout << "done.\nfilling hough space... " << endl; //fill hough space for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ if(edges[y][x]==256){ for(int a = 0; a < NUMANGLES; a++){ double ad = 360.0*(double)a/(double)NUMANGLES; double ar = (double)(3.14159)*((double)(ad/180.0)); int d = (int)((double)NUMDIST * (((double)x*cos(ar)+(double)y*sin(ar))/(double)MAXDIST)); accumulator[a][abs(d)]++; } } } } cout << "done.\ninitializing array to store line data... " << endl; //initialize array to store detected lines for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ lines[y][x] = 0;

} } cout << "done.\ndetecting lines... " << endl; //use hough space accumulator to detect lines for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ for(int a = 0; a < NUMANGLES; a++){ double ad = 360.0*(double)a/(double)NUMANGLES; double ar = (double)(3.14159)*((double)(ad/180.0)); int d = (int)((double)NUMDIST * (((double)x*cos(ar)+(double)y*sin(ar))/(double)MAXDIST)); if(accumulator[a][abs(d)] > line_threshhold){ lines[y][x] = 1; } } } } cout << "done.\nbeginning output... " << endl; //output image of Hough space fstream outh; outh.open("houghspace.pgm", fstream::out); outh << "P2" << endl; outh << "#generated by Andrew Stebbins" << endl; outh << NUMANGLES-1 << " " << NUMDIST-1 << endl; outh << range << endl; for(int y = 0; y < NUMANGLES; y++){ for(int x=0; x < NUMDIST; x++){ outh << accumulator[y][x] << endl; } } outh.close(); //output the smoothed grayscale image with no edge superposition fstream out1; out1.open("output.pgm", fstream::out); out1 << "P2" << endl; out1 << comment << endl; out1 << width << " " << height << endl; out1 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ out1 << smoothed[y][x] << endl;

} } out1.close(); comment = "#created by Andrew Stebbins"; //output the detected edges fstream out2; out2.open("output.ppm", fstream::out); out2 << magicnum << endl; out2 << comment << endl; out2 << width << " " << height << endl; out2 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ //if edge pixel, make red if(edges[y][x] == 256){ out2 << 255 << endl; out2 << 0 << endl; out2 << 0 << endl; } else{ out2 << 0 << endl; out2 << 0 << endl; out2 << 0 << endl; } } } out2.close(); //output the detected lines fstream outl; outl.open("lines.ppm", fstream::out); outl << magicnum << endl; outl << comment << endl; outl << width << " " << height << endl; outl << range << endl; for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ //if pixel is on a detected line, make red if(lines[y][x] == 1){ outl << 255 << endl;

outl << 0 << endl; outl << 0 << endl; } else{ outl << ppm[y][x].r << endl; outl << ppm[y][x].g << endl; outl << ppm[y][x].b << endl; } } } outl.close(); cout << "done.\n"; return 0; } VERTEX DETECT #include <iostream> #include <string> #include <iomanip> #include <fstream> #include <map> #include <cmath> using namespace std; //struct for holding rgb color values typedef struct { int r,g,b; } rgb; const int NUMANGLES = 240; const int NUMDIST = 240; const double RELATIVE_LINE_THRESHOLD = 0.2; //relative percentage of the image's diagonal int main(int argc, char *argv[]){ string magicnum, comment; comment = "#created by Andrew Stebbins"; int height, width, range; int edge_threshold = 120; int hysteresis_threshold = 90; int line_threshhold = 0; //this will change as soon we get the width/height of the image ifstream in;

cout << "opening file: " << argv[1] << endl; in.open(argv[1], ios::in); getline(in, magicnum); if(!(magicnum == "P3")){ cout << "error: image is not of type PPM!" << endl; return 0; } getline(in, comment); in >> width; in >> height; in >> range; cout << "width: " << width << " height: " << height << " range: " << range << endl; double MAXDIST = width*cos(3.14159/4.0) + height*sin(3.14159/4.0); line_threshhold = (int)(sqrt((double)height*(double)height+(double)width*(double)width)*RELATIVE_LINE_THRESHOLD); cout << "threshold: " << line_threshhold << endl; cout << "initializing arrays... " << endl; cout << "ppm" << endl; rgb** ppm = new rgb*[height]; for(int k = 0; k < height; k++){ ppm[k] = new rgb[width]; for(int c = 0; c < width; c++){ ppm[k][c].r = 0; ppm[k][c].g = 0; ppm[k][c].b = 0; } } cout << "pgm" << endl; int** pgm = new int*[height]; for(int k = 0; k < height; k++){ pgm[k] = new int[width]; for(int c = 0; c < width; c++){ pgm[k][c] = 0; } } cout << "smoothed" << endl;

int** smoothed = new int*[height]; for(int k = 0; k < height; k++){ smoothed[k] = new int[width]; for(int c = 0; c < width; c++){ smoothed[k][c] = 0; } } cout << "edges" << endl; int** edges = new int*[height]; for(int k = 0; k < height; k++){ edges[k] = new int[width]; for(int c = 0; c < width; c++){ edges[k][c] = 0; } } int** gx = new int*[height]; for(int k = 0; k < height; k++) gx[k] = new int[width]; int** gy = new int*[height]; for(int k = 0; k < height; k++) gy[k] = new int[width]; int** edge_vals = new int*[height]; for(int k = 0; k < height; k++) edge_vals[k] = new int[width]; cout << "vertices" << endl; int** vertices = new int*[height]; for(int k = 0; k < height; k++){ vertices[k] = new int[width]; for(int c = 0; c < width; c++){ vertices[k][c] = 0; } } cout << "lines" << endl; int** lines = new int*[height]; for(int k = 0; k < height; k++){ lines[k] = new int[width]; for(int c = 0; c < width; c++){ lines[k][c] = 0; } } cout << "accum" << endl;

int** accumulator = new int*[NUMANGLES]; for(int k = 0; k < NUMANGLES; k++){ accumulator[k] = new int[NUMDIST]; for(int c = 0; c < NUMDIST; c++){ accumulator[k][c] = 0; } } cout << "done." << endl; cout << "reading file... " << endl; //read the input file into an array of rgb data structures for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ in >> ppm[y][x].r; in >> ppm[y][x].g; in >> ppm[y][x].b; } } in.close(); cout << "done.\ngenerating grayscale image... " << endl; //generate a greyscale representation of the input file for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ pgm[y][x] = (ppm[y][x].r + ppm[y][x].g + ppm[y][x].b)/3; } } cout << "done.\napplying gaussian filtering... " << endl; //generate a flattened grayscale image using gaussian filtering for(int y = 1; y < height-1; y++){ for(int x=1; x < width-1; x++){ smoothed[y][x]=(pgm[y][x]*4+pgm[y-1][x]*2+pgm[y+1][x]*2+pgm[y][x1]*2+pgm[y][x+1]*2+pgm[y-1][x+1]*1+pgm[y-1][x-1]*1+pgm[y+1][x+1]*1+pgm[y+1][x-1]*1)/16; } } cout << "done.\ndetecting edges... " << endl; //detect edges for(int y = 2; y < height-2; y++){ for(int x=2; x < width-2; x++){ if(y>0){ gx[y][x] = smoothed[y][x-1]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1); gy[y][x] = smoothed[y-1][x]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y-1][x+1]*(1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1);

if(abs(gx[y][x])+abs(gy[y][x])>edge_threshold) edges[y][x] = abs(gx[y][x])+abs(gy[y][x]); } } } //apply non-maximum suppression for(int y = 2; y < height-2; y++){ for(int x = 2; x < width-2; x++){ if(abs(gx[y][x])>abs(gy[y][x])){ if(gx[y][x]<0){ if(gx[y][x-1]<gx[y][x] || gx[y][x+1]<gx[y][x]) edges[y][x] = 0; } else { if(gx[y][x+1]>gx[y][x] || gx[y][x-1]>gx[y][x]) edges[y][x] = 0; } } else if(abs(gx[y][x])<abs(gy[y][x])){ if(gy[y][x]<0){ if(gy[y-1][x]<gy[y][x] || gy[y+1][x]<gy[y][x]) edges[y][x] = 0; } else { if(gy[y+1][x]>gy[y][x] || gy[y-1][x]>gy[y][x]) edges[y][x] = 0; } } } } //hysteresis cout << "done.\nfilling hough space... " << endl; //fill hough space for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ if(edges[y][x] > edge_threshold){ for(int a = 0; a < NUMANGLES; a++){ double ad = 360.0*(double)a/(double)NUMANGLES; double ar = (double)(3.14159)*((double)(ad/180.0)); int d = (int)((double)NUMDIST * (((double)x*cos(ar)+(double)y*sin(ar))/(double)MAXDIST)); accumulator[a][abs(d)]++;

} } } } cout << "done.\ninitializing array to store line data... " << endl; //initialize array to store detected lines for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ lines[y][x] = 0; } } cout << "done.\ndetecting lines... " << endl; //use hough space accumulator to detect lines for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ for(int a = 0; a < NUMANGLES; a++){ double ad = 360.0*(double)a/(double)NUMANGLES; double ar = (double)(3.14159)*((double)(ad/180.0)); int d = (int)((double)NUMDIST * (((double)x*cos(ar)+(double)y*sin(ar))/(double)MAXDIST)); if(accumulator[a][abs(d)] > line_threshhold){ lines[y][x] = 1; } } } } cout << "done.\ndetecting vertices... " << endl; for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ for(int a = 0; a < NUMANGLES; a++){ double ad = 360.0*(double)a/(double)NUMANGLES; double ar = (double)(3.14159)*((double)(ad/180.0)); int d = (int)((double)NUMDIST * (((double)x*cos(ar)+(double)y*sin(ar))/(double)MAXDIST)); if(accumulator[a][abs(d)] > line_threshhold){ for(int a2 = 0; a2 < NUMANGLES; a2++){ double ad2 = 360.0*(double)a2/(double)NUMANGLES; double ar2 = (double)(3.14159)*((double)(ad2/180.0)); int d2 = (int)((double)NUMDIST * (((double)x*cos(ar2)+(double)y*sin(ar2))/(double)MAXDIST)); if(accumulator[a2][abs(d2)] > line_threshhold){

if(abs(ad - ad2) >= 75 && abs(ad - ad2) <= 105) vertices[y][x] = 1; } } } } } } cout << "done.\nbeginning output... " << endl; //output image of Hough space fstream outh; outh.open("houghspace.pgm", fstream::out); outh << "P2" << endl; outh << comment << endl; outh << NUMANGLES-1 << " " << NUMDIST-1 << endl; outh << range << endl; for(int y = 0; y < NUMANGLES; y++){ for(int x=0; x < NUMDIST; x++){ outh << accumulator[y][x] << endl; } } outh.close(); //output the smoothed grayscale image with no edge superposition fstream out1; out1.open("smoothed.pgm", fstream::out); out1 << "P2" << endl; out1 << comment << endl; out1 << width << " " << height << endl; out1 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ out1 << smoothed[y][x] << endl; } } out1.close(); //output the detected edges fstream out2; out2.open("edges.ppm", fstream::out); out2 << magicnum << endl; out2 << comment << endl;

out2 << width << " " << height << endl; out2 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ out2 << edges[y][x] << endl; out2 << edges[y][x] << endl; out2 << edges[y][x] << endl; } } out2.close(); //output the detected lines fstream outl; outl.open("lines.ppm", fstream::out); outl << magicnum << endl; outl << comment << endl; outl << width << " " << height << endl; outl << range << endl; for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ //if pixel is on a detected line, make red if(lines[y][x] == 1){ outl << 255 << endl; outl << 0 << endl; outl << 0 << endl; } else{ outl << ppm[y][x].r << endl; outl << ppm[y][x].g << endl; outl << ppm[y][x].b << endl; } } } outl.close(); //output the detected lines fstream outv; outv.open("vertices.ppm", fstream::out); outv << magicnum << endl; outv << comment << endl; outv << width << " " << height << endl; outv << range << endl;

for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ //if pixel is on a detected line, make red if(vertices[y][x] == 1){ outv << 255 << endl; outv << 0 << endl; outv << 0 << endl; } else{ outv << ppm[y][x].r << endl; outv << ppm[y][x].g << endl; outv << ppm[y][x].b << endl; } } } outv.close(); cout << "done.\n"; return 0; }

CONCLUSIONI

Come dicevamo allinizio lalgoritmo si basa su questa sequenza :

1 2 3 4

Il motion rileva il movimento sulla video che punta a valle e inizia a registrare Un algoritmo di tracking dei blob identifica la zone camion ed estrae blimmagine precisa senza disturbi. Limmagine viene memorizzate La telecamera che punta verso monte registra e con lo stesso procedimento memorizza il retro della macchina associandola al fronte.

Dopo N tempo una vettura ritorna verso valle . 1 2 3 La videocamera si attiva e registra Lalgoritmo di tracking estrae la vettura e la memorizza La seconda videocamera estrae il retro della vettura

A questo punto parte lalgoritmo di riconoscimento e comparazione.

1 2

Larchivio macchine viene fatto scorrere ed ogni vettura presente viene confrontata con le immagini delle vetture di ritorno. Se una vettura viene identificata le due immagini relative al retro vengono comprate per vedere se il volume mutato.

A questo punto risulta chiaro che il sistema di riconoscimento la parte vitale. Non essendo possibile riprendere le targhe tutti gli altri algoritmi usati e testati nellarco di quasi 2 anni sono risultati inefficaci in quanto le condizioni ambientali e hardware non permettevano di avere un limite accettabile di sicurezza. Gli algoritmi usati sono stati dai semplici TEMPLATE MATCHING a quelli di SIFT, RANSAC, SURF basandosi sulla libreria OPEN CV di INTEL. Lefficienza del SURF con immagini definiti il seguente :

In alcune condizioni costruite mediante copia dellimmagine lalgoritmo di SURF funziona.

Il funzionamento dovrebbe essere basato su un sistema di videocamere piazzate ad un altezza di circa 1.5m

Tale modalit permette di riprendere le targhe e quindi di eseguire il riconoscimento. Le telecamere devono inoltre essere sui 200 FRAMES per eliminare i problemi delle vetture veloci. Generalmente vengono abbinate due videocamere. Rimane comunque il fatto che con tali condizioni hardware, di rete e territoriali non possibile creare un sistema per risolvere tale problematica. Una videocamera utilizzabile potrebbe essere la VIVOTEK a 2 Mpx

Potrebbero piacerti anche