// Approximator.cpp -- Analysis of 1D Mondrian scenes // // // DESCRIPTION // // Copyright © Tim Bahls, Daniel Scharstien 2003. // /////////////////////////////////////////////////////////////////////////// #pragma once #include "Error.h" #include "Image.h" #include "Color.h" #include "Approximator.h" #include "Utils.h" #ifndef UNKNOWN #define UNKNOWN -9876 #define UNKNOWNF -9876.5f #define MAX 1234.5f #define MIN -1234.5f #ifndef WIN32 #define __max(a,b) (((a) > (b)) ? (a) : (b)) #define __min(a,b) (((a) < (b)) ? (a) : (b)) #endif #endif #define MINVEL -5 #define MAXVEL 5 #define MINLEN 5 #define MAXLEN 300 /////////////////////////////////////////////////////////////////////////// // class CRegApprox - a single region CRegApprox::CRegApprox(int iid, int inFrames) { id = iid; minVel=MINVEL; maxVel=MAXVEL; minLen=MINLEN; maxLen=MAXLEN; nFrames=inFrames; xmins=new int[nFrames]; for(int i=0; i0){ //delete [] relative; //} relative=c; } //returns the id of the color int CApproximator::getPixID(int row, int col){ CCol *c=(CCol*)&im.Pixel(col,row,0); //notice switch CCol cc=*c; int a= cc.getId(); if (a>maxID){ addid(a); } if(region[a]==null){ region[a]=CRegApprox(a,nFrames); nRegions++; } return a; } // create new region if necessary, add a new component, and record its left edge void CApproximator::startRegion(int id, int frame, int x, int prevID) { if(region[id].xmins[frame]==UNKNOWN){ region[id].xmins[frame]=x; region[id].leftIDs[frame]=prevID; region[id].maxmin[frame]=(float)x+0.5f; } } // record right boundary of current region void CApproximator::endRegion(int id, int frame, int x, int nextID) { region[id].xmaxes[frame]=x; region[id].rightIDs[frame]=nextID; region[id].minmax[frame]=(float)x-0.5f; } // read a frame: look at all pixels in center scanline and initialize / update // regions and their edges void CApproximator::readFrame(CByteImage iim, int frame) { im=iim; CShape sh = im.Shape(); int w = sh.width, h = sh.height; maxWidth=w; data[frame]=new int[w]; int row=h/2; int oldid = getPixID(row,0); startRegion(oldid, frame, 0, -1); data[frame][0]=oldid; for (int x = 1; x < w; x++) { int newid = getPixID(row,x); data[frame][x]=newid; if(newid!=oldid){ endRegion(oldid, frame, x-1, newid); startRegion(newid, frame, x, oldid); oldid = newid; } } //update last extent: endRegion(oldid, frame, w-1, -1); } void CApproximator::printData() { printf("%d regions observed\n", nRegions); for (int i=0; i <= maxID; i++) { if (region[i]==null) continue; printf(" "); p(i); printf(":"); CRegApprox r = region[i]; for (int f=0; f < nFrames; f++) { printf(" f%d:", f); if(r.xmins[f]==UNKNOWN) continue; printf("%d-%d,", r.xmins[f],r.xmaxes[f]); } printf("\n"); } } void CApproximator::possibilityElimination(){ for (int i=0; i <= maxID; i++) { CRegApprox r=region[i]; if (r==null) continue; bool change2=true; while(change2==true){ change2=false; change2|=region[i].restrictPosition(); change2|=region[i].restrictVel(); change2|=region[i].restrictLen(); } } } void CApproximator::occlusionDetection(){ if(verbose) printf("Occlusion Detection:\n"); for (int i=0; i <= maxID; i++) { CRegApprox r=region[i]; if (r==null) continue; for(int f=0; f=end1;x--){ if(compare(i,data[f][x])==2){ r.minmin[f]=(float)x+0.5f;//if i extended this far, it would've been found. Thus it doesn't. break; } } int start2=ROUND(r.minmax[f]); start2=__max(start2,0); start2=__max(start2,ROUND(r.maxmin[f])); int end2=ROUND(r.maxmax[f]); end2=__min(end2,(int)maxWidth-1); for(int x=start2;x<=end2;x++){ if(compare(i,data[f][x])==2){ r.maxmax[f]=(float)x+0.5f;//if i extended this far, it would've been found. Thus it doesn't. break; } } if(r.maxmin[f]==MAX||r.maxmin[f]==MIN) continue; for(int x=__max(0,ROUND(r.maxmin[f]));x<=__min(ROUND(r.minmax[f])-1,maxWidth-1);x++){ int id=data[f][x]; if(id!=i){ setCloser(id,i); } } } } } //like it sounds void CApproximator::transitiveClosure() { if(verbose) printf("Computing Transitive closure:\n"); bool newEdge = true; while (newEdge) { newEdge = false; for (int i=0; i <= maxID; i++) { if (region[i]==null) continue; for (int j=0; j <= maxID; j++) { if(compare(i,j)==2){//definite for (int k=0; k <= maxID; k++) { if(compare(j,k)==2&&i!=k){//definite newEdge |= setCloser(i,k);//definite newEdge; } } } } } } } void CApproximator::reportResults() { printf("\nResults: %d regions observed\n", nRegions); for (int i=0; i <= maxID; i++) { CRegApprox r=region[i]; if (r==null) continue; printf(" "); p(i); printf(" vel:"); justify(r.minVel); printf("~"); justify(r.maxVel); printf(" len:"); justify(r.minLen); printf("~"); justify(r.maxLen); printf(" Over: "); for (int j=0; j <= maxID; j++) { if(compare(i,j)==2){ p(j); printf(" "); //times++; } } printf("\n"); } } // infer depth ordering, lengths and motion int CApproximator::goGoGo() { times=0; int loopStopper=0; while (loopStopper<=10) { occlusionDetection(); possibilityElimination(); transitiveClosure(); loopStopper++; } for (int i=0; i <= maxID; i++) { for (int j=0; j <= maxID; j++) { if(compare(i,j)==2) times++; } } if(verbose) reportResults(); return times; } void CApproximator::checkAccuracy(CScene scene) { for (int i=1; i <= maxID; i++) { CRegApprox reg=region[i]; if (reg==null) continue; CRect rect=scene.getByID(i); //printf("again: expected id=%d actual id=%d\n",i,rect.color.getId()); if(rect.vel.x>reg.maxVel||rect.vel.xrect2.z){ verbose=true; printf("ERROR! "); p(i); printf(" doesn't beat "); p(j); printf("!\n"); throw CError("Relative Distances incorrect"); } } if(compare(0,i)==2){ verbose=true; printf("ERROR! "); p(i); printf(" doesn't beat "); p(0); // printf(" j=%d\n",j); throw CError("Nothing behind white"); } } if(verbose) printf("All true\n"); }