📄 blobtracker.cpp
字号:
// Search the frame for bright spots. BlobTrackerObjectList new_objects; FindObjects(new_objects); // Match up the objects just found with the ones found previously, // to try to achieve continuity of object ids across frames. BlobTrackerObjectList old_objects = *m_objects; m_objects->clear(); unsigned long matched = 0; for (BlobTrackerObjectList::iterator old = old_objects.begin(); old != old_objects.end(); ) { int min_d = m_distance_threshold; BlobTrackerObjectList::iterator min_o = new_objects.end(); for (BlobTrackerObjectList::iterator o = new_objects.begin(); o != new_objects.end(); o++) { if (InRect(old->GetRect(), o->GetCenter())) { min_o = o; break; } int d = distance(o->GetCenter(), old->GetCenter()); if (d < min_d) { min_d = d; min_o = o; } } if (min_o != new_objects.end()) { int id = old->GetId(); min_o->SetId(id); matched |= 1 << id; m_objects->push_back(*min_o); new_objects.erase(min_o); old_objects.erase(old); } else { old++; } } // For any objects that weren't matched up, assign ids in // order of decreasing size. if (m_objects->size() < m_num_objects && new_objects.size() > 0) { std::sort(new_objects.begin(), new_objects.end(), size_cmp); int id = 0; for (BlobTrackerObjectList::iterator o = new_objects.begin(); o != new_objects.end() && m_objects->size() < m_num_objects; o++) { while (matched & (1 << id)) id++; o->SetId(id); id++; m_objects->push_back(*o); } } // Generate output frame FillDestinationData(image); return NOERROR;}// (These functions are not very efficient, but they are called rarely enough// that it is not a big impact on performance.)static inline int GetPixel(const unsigned char *image, int width, int x, int y){ return image[y*width + x];}static inline void SetPixel(unsigned char *image, int width, int x, int y, int color){ image[y*width + x] = color;}// Search the image for spots that meet the brightness and size thresholds.void BlobTracker::FindObjects(BlobTrackerObjectList &objects){ for (int y = 0; y < m_image_format.height; y++) { for (int x = 0; x < m_image_format.width; x++) { // Check each pixel to see if it meets the brightness threshold. // (This call to GetPixel is the only one that is executed with enough frequency to have // any impact on performance, but optimizing it gave minimal performance improvement.) if (GetPixel((unsigned char *)m_image->imageData, m_image_format.width, x, y) >= m_pixel_threshold) { // Find all connected bright pixels. Set them all to black while keeping track // of the bounding rectangle and the number of pixels found. CvRect rect; int area; FloodFill((unsigned char *)m_image->imageData, m_image_format.width, m_image_format.height, x, y, m_pixel_threshold, rect, area); // Ignore any spots that don't meet the size threshold. if (area >= m_size_threshold) objects.push_back(BlobTrackerObject(rect, area)); } } }}// Filled horizontal segment of scanline y for xl$<=$x$<=$xr.// Parent segment was on line y-dy. dy=l or -1struct Segment { int y, xl, xr, dy; Segment(int a, int b, int c, int d) : y(a), xl(b), xr(c), dy(d) { };};static inline void push(std::stack<Segment> &stack, int height, int y, int xl, int xr, int dy){ y += dy; if (y >= 0 && y < height) stack.push(Segment(y, xl, xr, dy));}static inline void SetPixel(unsigned char *image, int width, int x, int y, int color, CvRect &rect, int &area){ if (x < rect.x) rect.x = x; else if (x >= rect.x+rect.width) rect.width = x+1-rect.x; if (y < rect.y) rect.y = y; else if (y >= rect.y+rect.height) rect.height = y+1-rect.y; SetPixel(image, width, x, y, color); area++;}#define GET_PIXEL(x, y) GetPixel(image, width, x, y)#define SET_PIXEL(x, y) SetPixel(image, width, x, y, 0, rect, area)#define PUSH(y, xl, xr, dy) push(stack, height, y, xl, xr, dy)// FloodFill: set the pixel at (x,y) and all of its 4-connected neighbors// that meet the brightness threshold to zero while keeping track// of the bounding rectangle and the number of pixels found.// A 4-connected neighbor is a pixel above, below, left, or right of// a pixel.// Algorithm adapted from one by Paul Heckbert 13 Sept 1982, 28 Jan 1987.static void FloodFill(unsigned char *image, int width, int height, int start_x, int start_y, int threshold, CvRect &rect, int &area){ CvRect init_rect = { start_x, start_y, 1, 1 }; rect = init_rect; area = 0; std::stack<Segment> stack; PUSH(start_y, start_x, start_x, 1); /* needed in some cases */ PUSH(start_y+1, start_x, start_x, -1); /* seed segment (popped 1st) */ while (!stack.empty()) { /* pop segment off stack and fill a neighboring scan line */ const Segment seg = stack.top(); stack.pop(); // segment of scan line y-dy for xl<=x<=x2 was // previously filled, // now explore adjacent pixels in scan line y int l; int x; for (x = seg.xl; x >= 0 && GET_PIXEL(x, seg.y) >= threshold; x--) SET_PIXEL(x, seg.y); if (x >= seg.xl) goto skip; l = x+1; if (l < seg.xl) PUSH(seg.y, l, seg.xl-1, -seg.dy); /* leak on left? */ x = seg.xl+1; do { for (; x < width && GET_PIXEL(x, seg.y) >= threshold; x++) SET_PIXEL(x, seg.y); PUSH(seg.y, l, x-1, seg.dy); if (x > seg.xr+1) PUSH(seg.y, seg.xr+1, x-1, -seg.dy); /* leak on right? */skip: for (x++; x <= seg.xr && GET_PIXEL(x, seg.y) < threshold; x++) ; l = x; } while (x <= seg.xr); }}// Registration information// List of class IDs and creator functions for the class factory. This// provides the link between the COM entry point in the DLL and an object// being created. The class factory will call the static CreateInstance.CFactoryTemplate g_Templates[] = { { L"Blob Tracker", &CLSID_BlobTracker, BlobTracker::CreateInstance }, { L"Blob Tracker Property Page", &CLSID_BlobTrackerPropertyPage, BlobTrackerPropertyPage::CreateInstance }};int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);//// DllRegisterServer//// Register the COM objects (the tracker and the property page).// Also add the tracker to the "Video Trackers" component category.STDAPI DllRegisterServer(){ HRESULT hr = AMovieDllRegisterServer2( TRUE ); if (FAILED(hr)) return hr; ICatRegister *reg; hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_ALL, IID_ICatRegister, (void **)®); if (FAILED(hr)) return hr; CATEGORYINFO catinfo; catinfo.catid = CATID_Trackers; catinfo.lcid = 0x409; wcscpy(catinfo.szDescription, L"Video Trackers"); reg->RegisterCategories(1, &catinfo); reg->RegisterClassImplCategories(CLSID_BlobTracker, 1, const_cast<GUID *>(&CATID_Trackers)); reg->Release(); return NOERROR;} // DllRegisterServer//// DllUnregisterServer//// Unregister the COM objects (the tracker and the property page).// Also remove the tracker from the "Video Trackers" component category.STDAPI DllUnregisterServer(){ HRESULT hr = AMovieDllRegisterServer2( FALSE ); if (FAILED(hr)) return hr; ICatRegister *reg; hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_ALL, IID_ICatRegister, (void **)®); if (FAILED(hr)) return hr; reg->UnRegisterClassImplCategories(CLSID_BlobTracker, 1, const_cast<GUID *>(&CATID_Trackers)); reg->Release(); return NOERROR;} // DllUnregisterServer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -