Kết quả thử nghiệm thực tế

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 49)

5. Phƣơng pháp nghiên cứu:

3.2.2. Kết quả thử nghiệm thực tế

3.2.2.1. Thiết lập thử nghiệm

Trong quá trình thử nghiệm kết quả, các video mẫu sẽ đƣợc truyền vào trực tiếp trong phần Property của chƣơng trình bằng đƣờng dẫn tuyệt đối. Cụ thể là đƣa đƣờng dẫn trực tiếp vào ô Command Arguments.

Hình 3.3. Cách truyền video vào chương trình thử nghiệm

Sau khi thực hiện, chƣơng trình sẽ hiện lên 3 khung màn hình:

 Màn hình ChuyenDong: màn hình chính của chƣơng trình

 Màn hình Motion: thể hiện các đối tƣợng chuyển động.

 Màn hình KhungKetQua: thể hiện kết quả của chƣơng trình.

3.2.2.2. Kết quả thử nghiệm

frames/second, 3600 frame, khung hình 720*1280, quan sát vào lúc 20h00, điều kiện ánh sáng tốt, tại khu vực quầy tính tiền số 06. Chƣơng trình có thể phát hiện đối tƣợng chuyển động nhƣ hình 3.4.

Hình 3.4. Kết quả chương trình với Video 01

 Kết quả của chƣơng trình với đoạn video 02 có kích thƣớc 120 giây, 30 frames/second, 3600 frame, khung hình 720*1280, quan sát vào lúc 20h20, điều kiện ánh sáng tốt, tại khu vực trƣng bày hàng hóa mỹ phẩm. Chƣơng trình có thể phát hiện đ ối tƣợng chuyển động nhƣ hình 3.5.

Hình 3.5. Kết quả chương trình với Video 02

3.2.3. Điều kiện ràng buộc của chương trình

Để chƣơng trình hoạt động và cung cấp kết quả chính xác thì cần phải thỏa mãn một số yêu cầu sau:

 Nền video không đƣợc thay đổi.

 Camera dùng để quay phải đƣợc đặt ở một vị trí cố định.

 Ánh sáng trong video phải ổn định, không tối quá hoặc sáng quá thì chức năng sẽ thực hiện chính xác hơn.

 Chức năng sẽ thực hiện chính xác hơn với video màu.

3.2.4. Đánh giá

Sau khi thực hiện chƣơng trình với 02 video mẫu, Chƣơng trình đã giải quyết đƣợc vấn đề phát hiện đối tƣợng chuyển động tại khu vực quan sát.

3.3.Kết luận chƣơng 3

Trong chƣơng 3, luận văn đã trình bày bài toán phát hiện đối tƣợng chuyển động trong với phạm vi dữ liệu video trong siêu thị. Về cơ bản, nội dung đã thể hiện đƣợc từng bƣớc để có thể giải quyết một bài toán xử lý dữ liệu video trong thực tế. Từ việc phân tích yêu cầu bài toán đến quy trình xử lý và chƣơng trình thử nghiệm cùng với kết quả.

KẾT LUẬN VÀ HƢỚNG PHÁT TRIỂN

1. Kết luận

1.1.Về mặt lý thuyết

 Tìm hiểu và sử dụng một số thƣ viện OpenCV trên nền công cụ Microsoft Visual Studio 2015.

 Tìm hiểu đƣợc các khái niệm cơ bản trong xử lý ảnh.

 Tìm hiểu đƣợc các đặc trƣng của video.

 Tìm hiểu đƣợc một số kỹ thuật phát hiện đối tƣợng chuyển động.

 Tìm hiểu đƣợc bài toán phát hiện đối tƣợng chuyển động từ camera.

 Xây dựng đƣợc chƣơng trình demo phát hiện đối tƣợng chuyển động từ camera ghi hình tại siêu thị.

1.2.Về mặt thực tiễn

Về cơ bản, luận văn đã hoàn thành đƣợc các chức năng đặt ra nhƣ yêu cầu:

 Phát hiện đối tƣợng chuyển động qua từng frame của video.

 Phát hiện và đánh dấu thành công các đối tƣợng chuyển động trong video.

 Sử dụng thành công các công cụ xử lý video để chuyển đổi định dạng các video khác nhau về mp4.

2. Hạn chế

Bên cạnh những thành công đạt đƣợc, luận văn vẫn còn một số hạn chế cần phải khắc phục nhƣ:

 Chƣa có đƣợc dữ liệu từ đúng camera an ninh của siêu thị.

 Tốc độ xử lý của chƣơng trình chậm.

 Chƣơng trình còn chƣa loại bỏ đƣợc bóng của đối tƣợng.

vùng quan sát, lƣu vết đối tƣợng chuyển động,

3. Hƣớng phát triển

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 49)