problem with blob tracking algorithm help!
in
Core Library Questions
•
2 years ago
Hi everyone! this is my first post and I wanna say I´ve been using processing for a while now and have never bumped into a problem I couldn´t find an answer in the forums, except this time where I wasn´t so lucky. I´ve coded a multiblob tracking algorithm with background subtraction (code by Daniel Shiffman), it uses a bounding circle to surround the blobs position (some people´s implementations like to use bounding boxes instead, I went for bounding circles ;-) ), you press the space bar to capture the background image against which all the subsequent frames captured by a webcam will be compared to pixel by pixel according to a threshold that you can change with the '+' and '-' keys, only the pixels considered different are displayed, then it finds the blobs and if their size in pixels is above another threshold they are stored in an arraylist which is later used for comparing it against the blob arraylist from the previous frame. It is a work in progress since it still lacks some features I plan to add, but it kinda works in general, the problem I´m facing right now is that the bounding circles leave a trail on top of the filtered pixels (i.e. the ones that get considered different from the background image, which after it´s captured are the only ones shown), the whole thing looks almost like when you forget to put a background() function inside of draw() thus drawing on top of what was previously drawn. Does anyone have any idea of what is causing this and how can I fix it??
Here´s my code(you can use a PS3 eye or the built in webcam, it detects them automatically, oh and I´m runnin it on OSX snow Leopard):
-
/*multiblob tracking by JLafargabackground subtraction code from Daniel Shiffman*/
import processing.video.*; Capture video; PImage bgimage; FINDER finder; TRACKER tracker; //PFont font; int minBlobSize = 100; int fontSize = 30; float threshold = 160; boolean start = false; boolean startTracking = true; void setup() { size((screen.width)/2, (screen.height)/2); String[] cams = Capture.list(); if(cams.length == 3) { video = new Capture(this, width, height); } else { video = new Capture(this, width, height, "Sony HD Eye for PS3 (SLEH 00201)", 60); } smooth(); // font = loadFont("Helvetica-48.vlw"); finder = new FINDER(); tracker = new TRACKER(); bgimage = createImage(video.width, video.height, RGB); } void draw() { // textFont(font, fontSize); if (video.available()) { video.read(); } finder.findBlobs(bgimage); if(startTracking) { tracker.track(finder.blobs); } println(threshold+" "+minBlobSize+" "+frameRate); } void keyPressed() { if(key == ' ') { if(start == false) { start = true; } bgimage.copy(video, 0, 0, video.width, video.height, 0, 0, video.width, video.height); bgimage.updatePixels(); } else if(key =='+') { threshold += 10; } else if(key == '-') { threshold -= 10; } else if(key == 't') { if(startTracking) { startTracking = false; } else { startTracking = true; } } else if(key == 's') { if(minBlobSize > 10) { minBlobSize -= 10; } } else if(key == 'S') { minBlobSize += 10; } /* else if(key == 'f') { if(fontSize > 1) { fontSize--; } } else if(key == 'F') { fontSize++; }*/ }
class BLOB {
int ID, x1, x2, y1, y2 = 0, Size = 0;boolean hasID = false;float radio, INCREMENTO = 15;PVector loc, speed;
BLOB(int tempx1, int tempx2, int tempy1){x1 = tempx1;x2 = tempx2;y1 = tempy1;loc = new PVector(0 , 0);}
void calcenter(){loc.x = (x1 + x2) / 2;loc.y = y1 + y2/2;radio = dist(loc.x, loc.y, x1, y1)+INCREMENTO;}}
class FINDER { int x1, x2, x, y; color fgColor, bgColor; float r1, g1, b1, r2, g2, b2; boolean A = false; ArrayList blobs = new ArrayList(); PImage thisFrame; void findBlobs(PImage temp_ThisFrame) { thisFrame = temp_ThisFrame; loadPixels(); video.loadPixels(); thisFrame.loadPixels(); image(video, 0, 0, width, height); if(start) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if(comparePixels() > threshold) { pixels[x + y*video.width] = fgColor; x1 = x; do { x++; } while(x < width && comparePixels() > threshold); x2 = x - 1; BLOB a = new BLOB(x1, x2, y); a.Size += (x2 - x1); for (int h = 0; h < blobs.size(); h++) { for (int i = x1; i <= x2; i++) { for (int j = ((BLOB) blobs.get(h)).x1; j <= ((BLOB) blobs.get(h)).x2; j++) { if (i == j && (y - (((BLOB) blobs.get(h)).y1 + ((BLOB) blobs.get(h)).y2)) == 1) { A = true; if (a.x1 < ((BLOB) blobs.get(h)).x1) { ((BLOB) blobs.get(h)).x1 = a.x1; } else { a.x1 = ((BLOB) blobs.get(h)).x1; } if (a.x2 > ((BLOB) blobs.get(h)).x2) { ((BLOB) blobs.get(h)).x2 = a.x2; } else { a.x2 = ((BLOB) blobs.get(h)).x2; } if(a.y1 > ((BLOB) blobs.get(h)).y1) { ((BLOB) blobs.get(h)).y2++; } break; } } if (A) { break; } } } if (!A) { if(a.Size > minBlobSize) { blobs.add(a); } } A = false; } else { pixels[x + y*video.width] = color(0); } } } if(blobs.size() != 0) { for(int i = 0; i < blobs.size(); i++) { ((BLOB) blobs.get(i)).calcenter(); } } else { image(video, 0, 0, width, height); tracker.prevFrame.clear(); } updatePixels(); } } float comparePixels() { fgColor = video.pixels[x + y*video.width]; bgColor = thisFrame.pixels[x + y*video.width]; r1 = red(fgColor); g1 = green(fgColor); b1 = blue(fgColor); r2 = red(bgColor); g2 = green(bgColor); b2 = blue(bgColor); return(dist(r1, g1, b1, r2, g2, b2)); } }
class TRACKER { float distance, CD = dist(0, 0, width, height); //CD stands for Closest Distance, which initially will have the biggest one in order to get in the first time ArrayList prevFrame = new ArrayList(); boolean newBlob = true; int[] newBlobs = new int[0]; void track(ArrayList CurrFrame) { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if(prevFrame.size() == 0) { for(int i = 0; i < CurrFrame.size(); i++) { BLOB cBlob = (BLOB) CurrFrame.get(i); cBlob.ID = i+1; cBlob.hasID = true; } } else { for(int i = 0; i < CurrFrame.size(); i++) { boolean blobMatched = false; BLOB cBlob = (BLOB) CurrFrame.get(i); for(int j = 0; j < prevFrame.size(); j++) { BLOB pBlob = (BLOB) prevFrame.get(j); if(PVector.dist(cBlob.loc, pBlob.loc) <= (cBlob.radio + pBlob.radio)) { cBlob.ID = pBlob.ID; blobMatched = cBlob.hasID = true; break; } } if(!blobMatched) { newBlobs = append(newBlobs, i); } } //WITH THE CURRENT APPROACH THERE IS NO NEED TO FIND THE CLOSEST BLOB //Find Closest Blob: this time we´ll search in THE CURRENT ARRAY since the blobs that also appear on the prev array have already been matched for(int a = 0; a < newBlobs.length; a++) { BLOB cBlob = (BLOB) CurrFrame.get(newBlobs[a]); boolean ID_REPEATED = true; int CB, i = 1; for(int j = 0; j < CurrFrame.size(); j++) { BLOB blob = (BLOB) CurrFrame.get(j); if(blob.hasID) { float distance; if((distance = PVector.dist(cBlob.loc, blob.loc)) < CD) { CD = distance; CB = blob.ID; } } } while(ID_REPEATED) { ID_REPEATED = false; for(int k = 0; k < CurrFrame.size(); k++) { BLOB blob = (BLOB) CurrFrame.get(k); if(i == blob.ID) { ID_REPEATED = true; break; } } if(!ID_REPEATED) { break; } i++; } cBlob.ID = i; } newBlobs = expand(newBlobs, 0); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// for(int i = 0; i < CurrFrame.size(); i++) { BLOB cBlob = (BLOB) CurrFrame.get(i); fill(255); // text("obj."+cBlob.ID+" size."+cBlob.Size, cBlob.loc.x, cBlob.loc.y); stroke(255); noFill(); ellipse(cBlob.loc.x, cBlob.loc.y, cBlob.radio, cBlob.radio); } ///////////////////////////////////////////////////////////////////////////////////////////////// if(prevFrame.size() != 0) { prevFrame.clear(); for(int i = 0; i < CurrFrame.size(); i++) { prevFrame.add((BLOB) CurrFrame.get(i)); } CurrFrame.clear(); } else if(prevFrame.size() == 0) { for(int i = 0; i < CurrFrame.size(); i++) { prevFrame.add((BLOB) CurrFrame.get(i)); } CurrFrame.clear(); } } }
edit: I forgot that you need to add a font to your sketch to make it work properly, but you could just comment the lines where the font is used
2nd edit: OK I´ll comment them for Y´all ;-)
1