// Imagine++ project // Project: Seeds // Author: Pascal Monasse #include #include #include #include using namespace Imagine; using namespace std; /// Min and max disparities static const float dMin=-30, dMax=-7; /// Min NCC for a seed static const float nccSeed=0.95; /// Radius of patch for correlation static const int win=(9-1)/2; /// To avoid division by 0 for constant patch static const float EPS=0.1f; /// A seed struct Seed { Seed(int x0, int y0, int d0, float ncc0) : x(x0), y(y0), d(d0), ncc(ncc0) {} int x,y, d; float ncc; }; /// Order by NCC bool operator<(const Seed& s1, const Seed& s2) { return (s1.ncc disp, Window W, int subW) { Image im(disp.width(), disp.height()); for(int j=0; jdMax) im(i,j)=Color(0,255,255); else { int g = 255*(disp(i,j)-dMin)/(dMax-dMin); im(i,j)= Color(g,g,g); } } setActiveWindow(W,subW); display(im); showWindow(W,subW); } /// Show 3D window static void show3D(const Image im, const Image disp) { #ifdef IMAGINE_OPENGL // Imagine++ must have been built with OpenGL support... // Intrinsic parameters given by Middlebury website const float f=3740; const float d0=-200; // Doll images cropped by this amount const float zoom=2; // Half-size images, should double measured disparity const float B=0.160; // Baseline in m FMatrix K(0.0f); K(0,0)=-f/zoom; K(0,2)=disp.width()/2; K(1,1)= f/zoom; K(1,2)=disp.height()/2; K(2,2)=1.0f; K = inverse(K); K /= K(2,2); std::vector pts; std::vector col; for(int j=0; j& im1, int i1,int j1,float m1, const Image& im2, int i2,int j2,float m2) { float dist=0.0f; float var1 = 0.0f; float var2 = 0.0f; for(int ii=-win; ii<=win; ii++) for(int jj=-win; jj<=win; jj++){ var1 += (im1(i1+ii,j1+jj)-m1) * (im1(i1+ii,j1+jj)-m1); var2 += (im2(i2+ii,j2+jj)-m2) * (im2(i2+ii,j2+jj)-m2); dist += (im1(i1+ii,j1+jj)-m1) * (im2(i2+ii,j2+jj)-m2); } return dist / sqrt(var1*var2); } /// Sum of pixel values in patch centered on (i,j). static float sum(const Image& im, int i, int j) { float s=0.0f; for(int ii=-win; ii<=win; ii++) for(int jj=-win; jj<=win; jj++) s += im(i+ii,j+jj); return s; } /// Centered correlation of patches of size 2*win+1. static float ccorrel(const Image& im1,int i1,int j1, const Image& im2,int i2,int j2) { float m1 = sum(im1,i1,j1); float m2 = sum(im2,i2,j2); int w = 2*win+1; return correl(im1,i1,j1,m1/(w*w), im2,i2,j2,m2/(w*w)); } /// Compute disparity map from im1 to im2, but only at points where NCC is /// above nccSeed. Set to true the seeds and put them in Q. static void find_seeds(Image im1, Image im2, float nccSeed, Image& disp, Image& seeds, std::priority_queue& Q) { disp.fill(dMin-1); seeds.fill(false); while(! Q.empty()) Q.pop(); const int maxy = std::min(im1.height(),im2.height()); const int refreshStep = (maxy-2*win)*5/100; for(int y=win; y+win= win && x+d <= im2.width() - win){ ncc = ccorrel(im1, x, y, im2, x+d, y); // check if it is higher than the best so far if(ncc > nccBest){ dBest = d; nccBest = ncc; } } // check if the best ncc is better than the "nccSeed" threshold, if yes put it in the queue if(nccBest > nccSeed){ Q.push(Seed(x, y, dBest, nccBest)); seeds(x,y) = true; disp(x,y) = dBest; } } } std::cout << std::endl; } /// Propagate seeds static void propagate(Image im1, Image im2, Image& disp, Image& seeds, std::priority_queue& Q) { while(! Q.empty()) { Seed s=Q.top(); Q.pop(); for(int i=0; i<4; i++) { float x=s.x+dx[i], y=s.y+dy[i]; if(0<=x-win && 0<=y-win && x+win= win && x+d <= im2.width() - win){ ncc = ccorrel(im1, x, y, im2, x+d, y); if(ncc > nccBest){ dBest = d; nccBest = ncc; } } Q.push(Seed(x, y, dBest, nccBest)); seeds(x,y) = true; disp(x,y) = dBest; } } } } int main() { // Load and display images Image I1, I2; if( ! load(I1, srcPath("im1.jpg")) || ! load(I2, srcPath("im2.jpg")) ) { cerr<< "Unable to load images" << endl; return 1; } std::string names[5]={"image 1","image 2","dense","seeds","propagation"}; Window W = openComplexWindow(I1.width(), I1.height(), "Seeds propagation", 5, names); setActiveWindow(W,0); display(I1,0,0); setActiveWindow(W,1); display(I2,0,0); Image disp(I1.width(), I1.height()); Image seeds(I1.width(), I1.height()); std::priority_queue Q; // Dense disparity find_seeds(I1, I2, -1.0f, disp, seeds, Q); displayDisp(disp,W,2); // Only seeds find_seeds(I1, I2, nccSeed, disp, seeds, Q); displayDisp(disp,W,3); // Propagation of seeds propagate(I1, I2, disp, seeds, Q); displayDisp(disp,W,4); // Show 3D (use shift click to animate) show3D(I1,disp); endGraphics(); return 0; }