Hƣớng phát triển

Một phần của tài liệu (LUẬN văn THẠC sĩ) nghiên cứu một số kỹ thuật phát hiện đối tượng chuyển động từ camera và ứng dụng giám sát tự động trong siêu thị (Trang 54 - 78)

Trong quá trình thực hiện đề tài, do hạn chế về mặt trình độ và thời gian thực hiện luận văn có hạn, chƣơng trình chỉ là phần demo các thuật toán phát hiện đối tƣợng chuyển động, khử nhiễu, theo vết nhiều đối tƣợng chuyển động dựa vào video. Để triển khai thực tế cần đòi hỏi nhiều cải tiến hơn nữa. Hy vọng trong tƣơng lai, những phát triển dƣới đây sẽ giúp chƣơng trình hoàn thiện hơn.

 Kết hợp phát hiện đối tƣợng chuyển động với nhận diện nhân viên.

 Kết hợp phát hiện đối tƣợng chuyển động với nhận diện khách hàng.

 Kết hợp phát hiện đối tƣợng chuyển động với nhận diện hành vi của khách hàng khi đi mua sắm.

 Xây dựng đƣợc thuật toán cải thiện chất lƣợng của video nhƣ loại trừ nhiễu, loại trừ bóng và tối ƣu hóa các thuật toán để tăng tốc độ của chƣơng trình.

 Mở rộng thuật toán có thể đếm đƣợc số lƣợng đối tƣợng chuyển động tại khu vực quan sát.

DANH MỤC TÀI LIỆU THAM KHẢO

[1] TS. Nguyễn Đăng Bình (2011), “Giáo trình – xử lý ảnh số”

[2] Nguyễn Văn Long (2016), “Ứng dụng xử lý ảnh trong thực tế với thư viện

OpenCV”

[3] TS. Lê Thị Kim Nga (2017), “Bài giảng xử lý ảnh”

[4] PGS. TS Đỗ Năng Toàn (2007), “Bài giảng xử lý ảnh số”

[5] Adrian Kaehler & Gary Bradski (2016), “Learning OpenCV 3 Computer

Visicon in C++ with the OpenCV Library”

[6] David Holz, Hua Yang (2017), “Enhanced contrast for object detection

and characterization by optical imaging”

[7] Miss Helly M Desai, Mr. Vaibhav Gandhi (2014), “A Survey: Background

Subtraction Techniques”

[8] Nishu Singla (2014), “Motion Detection Based on Frame Difference Method” [9] Satrughan Kumar, Jigyendra Sen Yadav (2016), “Video object extraction

and its tracking using background subtraction in complex environments”

[10] Yong Xu, Jixiang Dong, Bob Zhang, Daoyun Xu (2016), “Background

PHỤ LỤC

Mã nguồn thuật toán trừ nền và đánh dấu đối tƣợng trong chƣơng trình demo: #include <cmath>

#include <iostream> #include <sstream> using namespace std;

#if (defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) || (defined(__APPLE__) & defined(__MACH__))) #include <cv.h> #else #include <opencv/cv.h> #endif #include "cvblob.h" namespace cvb {

double distantVolumeBlobTrack(double bcx, double bcy, double bminx, double bminy, double bmaxx, double bmaxy, double tcx, double tcy, double tminx, double tminy, double tmaxx, double tmaxy) {

double d1; if (bcx<tminx) {

if (bcy<tminy)

else if (bcy>tmaxy)

d1 = MAX(tminx - bcx, bcy - tmaxy); else // if (tminy < bcy)&&(bcy < tmaxy)

d1 = tminx - bcx; }

else if (bcx>tmaxx) {

if (bcy<tminy)

d1 = MAX(bcx - tmaxx, tminy - bcy); else if (bcy>tmaxy)

d1 = MAX(bcx - tmaxx, bcy - tmaxy); else

d1 = bcx - tmaxx; }

else // if (tminx =< bcx) && (bcx =< tmaxx) { if (bcy<tminy) d1 = tminy - bcy; else if (bcy>tmaxy) d1 = bcy - tmaxy; else return 0.; } double d2; if (tcx<bminx) { if (tcy<bminy)

d2 = MAX(bminx - tcx, bminy - tcy); else if (tcy>bmaxy)

d2 = MAX(bminx - tcx, tcy - bmaxy); else // if (bminy < tcy)&&(tcy < bmaxy)

d2 = bminx - tcx; }

else if (tcx>bmaxx) {

if (tcy<bminy)

d2 = MAX(tcx - bmaxx, bminy - tcy); else if (tcy>bmaxy)

d2 = MAX(tcx - bmaxx, tcy - bmaxy); else

d2 = tcx - bmaxx; }

else // if (bminx =< tcx) && (tcx =< bmaxx) { if (tcy<bminy) d2 = bminy - tcy; else if (tcy>bmaxy) d2 = tcy - bmaxy; else return 0.; } return MIN(d1, d2); }

return distantVolumeBlobTrack(b->centroid.x, b->centroid.y, b->minx, b- >miny,

b->maxx, b->maxy, t->centroid.x + t->v.x, t->centroid.y + t->v.y, t->minx + t->v.x, t->miny + t->v.y, t->maxx + t->v.x, t->maxy + t->v.y);

}

void locateCamTrackRect(CvRect& localBGRect, CvRect& localRect, int minx,

int miny, int maxx, int maxy, const IplImage* bgr) { CvRect rect; rect.x = minx; rect.y = miny; rect.width = maxx-minx; rect.height = maxy-miny; rect.x += rect.width/2; rect.y += rect.height/2; rect.width *= 5; rect.height *= 5; if (rect.width>=bgr->width) { rect.x = 0; rect.width = bgr->width; }else { rect.x -= rect.width/2; if (rect.x<0) { rect.x = 0; }else if ((rect.x+rect.width)>=bgr->width) { rect.x -= (rect.x+rect.width-bgr->width);

} } if (rect.height>=bgr->height) { rect.y = 0; rect.height = bgr->height; }else { rect.y -= rect.height/2; if (rect.y<0) { rect.y = 0; }else if ((rect.y+rect.height)>=bgr->height) { rect.y -= (rect.y+rect.height-bgr->height); } } localBGRect = rect;

localRect = cvRect(minx-rect.x, miny-rect.y, maxx-minx, maxy-miny); }

IplImage* getSubImage(const IplImage* src, const CvRect& rect) {

int sh = src->height,sw = src->width, ss = src->widthStep, sc = src- >nChannels,

dh = rect.height, dw = rect.width, i, j;

IplImage* dst = cvCreateImage(cvSize(dw, dh), src->depth, sc); int ds = dst->widthStep;

for ( i=dh-1; i>=0; --i ) memcpy( dst->imageData+i*ds, src->imageData+ss*(i+rect.y)+rect.x*sc, dw*sc ); return dst; }

void saStartCamTrack(CvTrack* track, IplImage* bgr) { CvRect localBGRect, localRect;

locateCamTrackRect(localBGRect, localRect, track->minx, track- >miny,

track->maxx, track->maxy, bgr);

IplImage* img = getSubImage(bgr, localBGRect); track->camTrack.startTracking(img, &localRect); track->camTrack.createTracker(img);

cvReleaseImage(&img); }

CvBox2D saTrackCam(CvTrack *track, IplImage* bgr) { CvRect localBGRect, localRect;

locateCamTrackRect(localBGRect, localRect, track->minx+track->v.x, track->miny+track->v.y, track->maxx+track->v.x, track->maxy+track- >v.y, bgr);

IplImage* img = getSubImage(bgr, localBGRect);

CvBox2D box = track->camTrack.track(img, &localRect); cvReleaseImage(&img);

box.center.x += localBGRect.x; box.center.y += localBGRect.y;

return box; }

bool valueInRange(int value, int min, int max) { return (value >= min) && (value <= max); }

bool rectOverlap(CvRect A, CvRect B) {

bool xOverlap = valueInRange(A.x, B.x, B.x + B.width) || valueInRange(B.x, A.x, A.x + A.width);

bool yOverlap = valueInRange(A.y, B.y, B.y + B.height) || valueInRange(B.y, A.y, A.y + B.height);

return xOverlap && yOverlap; }

CvRect getRectFromBox2D(CvBox2D box) {

int x = MAX(0, box.center.x-box.size.width/2); int y = MAX(0, box.center.y-box.size.height/2); return cvRect(x, y, box.size.width, box.size.height); }

double distEuclid(CvScalar bgr1, CvScalar bgr2) {

return sqrt((bgr1.val[0]-bgr2.val[0])*(bgr1.val[0]-bgr2.val[0]) + (bgr1.val[1]-bgr2.val[1])*(bgr1.val[1]-bgr2.val[1]) + (bgr1.val[2]- bgr2.val[2])*(bgr1.val[2]-bgr2.val[2]));

}

int matchBlobTrack(CvBlob const *b, CvTrack *t, double thres, IplImage* bgr, double colorThres) {

// if (!rectOverlap(getRectFromBox2D(saTrackCam(t, bgr)), cvRect(b- >minx,

b->miny, b->maxx-b->minx, b->maxy-b->miny))) return 0; if (distEuclid(b->meanColor, t->meanColor)>colorThres) return 0; double d = distantBlobTrack(b, t);

return (t->v.x==0 && t->v.y==0)?(d<1.5*thres):(d<0.7*thres); }

// Access to matrix

#define C(blob, track) close[((blob) + (track)*(nBlobs+2))] // Access to accumulators

#define AB(label) C((label), (nTracks)) #define AT(id) C((nBlobs), (id))

// Access to identifications

#define IB(label) C((label), (nTracks)+1) #define IT(id) C((nBlobs)+1, (id))

// Access to registers

#define B(label) blobs.find(IB(label))->second #define T(id) tracks.find(IT(id))->second

void getClusterForTrack(unsigned int trackPos, CvID *close, unsigned int nBlobs, unsigned int nTracks, CvBlobs const &blobs, CvTracks const &tracks,

void getClusterForBlob(unsigned int blobPos, CvID *close, unsigned int nBlobs, unsigned int nTracks, CvBlobs const &blobs, CvTracks const &tracks,

list<CvBlob*> &bb, list<CvTrack*> &tt) {

for (unsigned int j=0; j<nTracks; j++) {

if (C(blobPos, j)) {

tt.push_back(T(j));

unsigned int c = AT(j);

C(blobPos, j) = 0; AB(blobPos)--; AT(j)--;

if (c>1) {

getClusterForTrack(j, close, nBlobs, nTracks, blobs, tracks, bb, tt);

} }

} }

nBlobs, unsigned int nTracks, CvBlobs const &blobs, CvTracks const &tracks,

list<CvBlob*> &bb, list<CvTrack*> &tt) {

for (unsigned int i=0; i<nBlobs; i++) {

if (C(i, trackPos)) {

bb.push_back(B(i));

unsigned int c = AB(i);

C(i, trackPos) = 0; AB(i)--;

AT(trackPos)--;

if (c>1) {

getClusterForBlob(i, close, nBlobs, nTracks, blobs, tracks, bb, tt);

} }

} }

void cvUpdateTracks(CvBlobs const &blobs, CvTracks &tracks, const double thDistance, const unsigned int thInactive, const unsigned int thActive,

IplImage* bgr, double colorThres) {

CV_FUNCNAME("cvUpdateTracks"); __CV_BEGIN__;

unsigned int nBlobs = blobs.size(); unsigned int nTracks = tracks.size();

CvID *close = new unsigned int[(nBlobs+2)*(nTracks+2)]; try

{

// Inicialization: unsigned int i=0;

for (CvBlobs::const_iterator it = blobs.begin(); it!=blobs.end(); ++it, i++) { AB(i) = 0; IB(i) = it->second->label; } CvID maxTrackID = 0; unsigned int j=0;

for (CvTracks::const_iterator jt = tracks.begin(); jt!=tracks.end(); ++jt, j++)

{

IT(j) = jt->second->id;

if (jt->second->id > maxTrackID) maxTrackID = jt->second->id; }

// Proximity matrix calculation and "used blob" list inicialization: for (i=0; i<nBlobs; i++)

for (j=0; j<nTracks; j++)

if (C(i, j) = (matchBlobTrack(B(i), T(j), thDistance, bgr, colorThres))) { AB(i)++; AT(j)++; }

// Detect inactive tracks for (j=0; j<nTracks; j++) {

unsigned int c = AT(j);

if (c==0) {

//cout << "Inactive track: " << j << endl;

CvTrack *track = T(j); track->inactive++; track->label = 0; }

}

// Detect new tracks for (i=0; i<nBlobs; i++) {

unsigned int c = AB(i);

if (c==0) {

//cout << "Blob (new track): " << maxTrackID+1 << endl;

//cout << *B(i) << endl;

// New track. maxTrackID++; CvBlob *blob = B(i);

CvTrack *track = new CvTrack; track->id = maxTrackID; track->label = blob->label; track->minx = blob->minx; track->miny = blob->miny; track->maxx = blob->maxx; track->maxy = blob->maxy;

track->centroid = blob->centroid; track->lifetime = 0; track->active = 0; track->inactive = 0; track->bCounted = false; track->v.x = 0; track->v.y = 0; saStartCamTrack(track, bgr); track->meanColor = blob->meanColor; tracks.insert(CvIDTrack(maxTrackID, track)); } } // Clustering for (j=0; j<nTracks; j++) {

unsigned int c = AT(j);

if (c) {

list<CvTrack*> tt; tt.push_back(T(j)); list<CvBlob*> bb;

nTracks,

blobs, tracks, bb, tt);

// Select track CvTrack *track; unsigned int area = 0;

for (list<CvTrack*>::const_iterator it=tt.begin(); it!=tt.end(); ++it) { CvTrack *t = *it; unsigned int a = (t->maxx-t->minx)*(t->maxy-t- >miny); if (a>area) { area = a; track = t; } } // Select blob CvBlob *blob; area = 0;

//cout << "Matching blobs: "; for (list<CvBlob*>::const_iterator

it=bb.begin(); it!=bb.end(); ++it) {

CvBlob *b = *it; //cout << b->label << " "; if (b->area>area) { area = b->area; blob = b; } } //cout << endl; // Update track

//cout << "Matching: track=" << track- >id <<

", blob=" << blob->label << endl; track->label = blob->label;

track->minx = blob->minx; track->miny = blob->miny; track->maxx = blob->maxx; track->maxy = blob->maxy;

track->v.x = blob->centroid.x - track- >centroid.x;

track->v.y = blob->centroid.y - track- >centroid.y;

track->centroid = blob->centroid; if (track->inactive) track->active = 0; track->inactive = 0; // Others to inactive for (list<CvTrack*>::const_iterator it=tt.begin(); it!=tt.end(); ++it) { CvTrack *t = *it; if (t!=track) { //cout << "Inactive: track=" << t->id << endl; t->inactive++; t->label = 0; } } } }

for (CvTracks::iterator jt=tracks.begin(); jt!=tracks.end();)

((jt->second->inactive)&&(thActive)&& (jt->second->active<thActive))) { delete jt->second; tracks.erase(jt++); } else { jt->second->lifetime++; if (!jt->second->inactive) jt->second->active++; ++jt; } } catch (...) { delete[] close;

throw; // TODO: OpenCV style. }

delete[] close;

__CV_END__; }

void cvRenderTracks(CvTracks const tracks, IplImage *imgSource, IplImage *imgDest, unsigned short mode, CvFont *font)

{ CV_FUNCNAME("cvRenderTracks"); __CV_BEGIN__; CV_ASSERT(imgDest&&(imgDest->depth==IPL_DEPTH_8U)&& (imgDest->nChannels==3)); if ((mode&CV_TRACK_RENDER_ID)&&(!font)) { if (!defaultFont) {

font = defaultFont = new CvFont;

cvInitFont(font, CV_FONT_HERSHEY_DUPLEX, 0.5, 0.5, 0, 1); } else font = defaultFont; } if (mode) {

for (CvTracks::const_iterator it=tracks.begin(); it!=tracks.end(); ++it)

{

if (mode&CV_TRACK_RENDER_ID) if (!it->second->inactive)

{

stringstream buffer; buffer << it->first;

cvPutText(imgDest, buffer.str().c_str(), cvPoint((int)it->second->centroid.x, (int)it->second->centroid.y), font, CV_RGB(0.,255.,0.)); } if (mode&CV_TRACK_RENDER_BOUNDING_BOX) if (it->second->inactive) cvRectangle(imgDest, cvPoint(it->second->minx, it->second->miny), cvPoint(it->second->maxx-1, it->second->maxy-1), CV_RGB(0., 0., 50.));

else

cvRectangle(imgDest, cvPoint(it- >second->minx, it->second->miny), cvPoint(it->second->maxx-1, it- >second->maxy-1), CV_RGB(0., 0., 255.));

if (mode&CV_TRACK_RENDER_TO_LOG) {

clog << "Track " << it->second->id << endl; if (it->second->inactive)

clog << " - Inactive for " << it- >second->inactive << " frames" << endl;

clog << " - Associated with blob " << it->second->label << endl;

clog << " - Lifetime " << it->second- >lifetime << endl;

clog << " - Active " << it->second->active << endl;

clog << " - Bounding box: (" << it->second- >minx << ", " << it->second->miny << ") - (" << it->second->maxx << ", " << it->second->maxy << ")" << endl;

clog << " - Centroid: (" << it->second- >centroid.x << ", " << it->second->centroid.y << ")" << endl;

clog << endl; }

if (mode&CV_TRACK_RENDER_TO_STD) {

cout << "Track " << it->second->id << endl; if (it->second->inactive)

cout << " - Inactive for " << it- >second->inactive << " frames" << endl;

else

cout << " - Associated with blobs " << it->second->label << endl;

cout << " - Lifetime " << it->second- >lifetime << endl;

cout << " - Active " << it->second->active << endl;

cout << " - Bounding box: (" << it->second- >minx << ", " << it->second->miny << ") - (" << it->second->maxx << ", " << it->second->maxy << ")" << endl;

cout << " - Centroid: (" << it->second- >centroid.x << ", " << it->second->centroid.y << ")" << endl;

cout << endl; } } } __CV_END__; } }

Một phần của tài liệu (LUẬN văn THẠC sĩ) nghiên cứu một số kỹ thuật phát hiện đối tượng chuyển động từ camera và ứng dụng giám sát tự động trong siêu thị (Trang 54 - 78)