www.pudn.com > stereo.zip > StcOptDP.cpp
/////////////////////////////////////////////////////////////////////////// // // NAME // StcOptDP.cpp -- select the best matches using dynamic programming // // DESCRIPTION // Input: m_cost: DSI (disparity space image) // Output: m_disparity best disparities in range [0 .. n_disp] // // Dynamic programming 1: like Intille & Bobick, no ground control points, but // encourage disparity discontinuities along intensity edges // // Each cell in x-d slice has one of three states: // 0: M - matched // 1: L - only visible in left image // 2: R - only visible in right image // // Here is a sample path through a DSI that uses the left image as reference: // // d=3 ' ' ' ' ' ' ' ' M M M ' ' ' ' ' ' // d=2 ' ' ' ' ' M M L ' ' R M M ' ' ' ' // d=1 ' ' ' ' L ' ' ' ' ' ' ' R ' ' ' ' // d=0 M M M L ' ' ' ' ' ' ' ' R M M M M // // x=0 1 2 3 4 5 6 7 8 10 12 14 16 // // The path is traversed from left to right. // It can be seen that there are seven possible transitions (current state is upper // case, predecessor is lower case): // // 0 1 2 3 4 5 6 // // L M m r // / / | | // m--M m--L l l R R r--M // // At each cell, we keep three cost values that correspond to the cumulative cost along the // lowest-cost path to the cell, ending in the current state. These values are stored in // the 3-band image sumcost (indexed by d, x rather than x, y), // where we use bands 0, 1, 2 for state M, L, R. The costs are // accumulated by adding a value to the sumcost value of the predecessor cell: // M cells get charged the matching cost; L and R cells get charged occlusion costs // ocL, ocR. In addition, for transitions 3 and 6, we charge the horizontal smoothness // cost to encourage disparity jumps to align with high intensity gradients. // // // NOTE: This implementation makes explicit assumptions about matches "shadowing" other // matches, not only in the same DSI column, but also in the diagonal corresponding // to the match-frame's line of sight. In particular, it is assumed that each // d-level in the DSI represents a shift of one pixel to the right. This is only true // if m_disp_step == 1. // // // SEE ALSO // StereoMatcher.h // StereoMatcher.cpp // // Copyright © Daniel Scharstein, 2001. // See Copyright.h for more details // /////////////////////////////////////////////////////////////////////////// #include "StereoMatcher.h" #include#define N_STATES 3 #define N_TRANS 7 // distribute disparities from certain matches to other pixels // on each scanline, fill "holes" with closest disparity value on the left // on left boundary, use closest value to the right // if revdir==1, go right-to-left instead of left-to-right // fill occluded pixels in disparity map to get disparity estimates everywhere // simply fill holes on each scanline from the left (at left edge, fill from right) // use other direction if revdir==1 static void fill_occluded_pixels(CIntImage dispimg, int occLabel, int revdir) { CShape sh = dispimg.Shape(); int x, y, w = sh.width, h = sh.height; int xstart = (revdir ? w-1 : 0); int xend = (revdir ? -1 : w); int xincr = (revdir ? -1 : 1); for (y = 0; y < h; y++) { int *disp = &dispimg.Pixel(0, y, 0); // find first nonoccluded pixel for (x = xstart; x != xend; x += xincr) if (disp[x] != occLabel) break; int oldd = disp[x]; // fill in all occluded pixels for (x = xstart; x != xend; x += xincr) { int d = disp[x]; if (disp[x] == occLabel) disp[x] = oldd; else oldd = d; } } } void CStereoMatcher::OptDP() { if (m_disp_step != 1.0f) fprintf(stderr, "WARNING: dynamic programming will not work properly for m_disp_step != 1\n"); float ocL = opt_occlusion_cost; float ocR = ocL; int occLabel = -9999; // marker for occluded pixels // (use 0 if you want to leave occluded pixels black) CShape sh = m_cost.Shape(); int width = sh.width, height = sh.height, n_disp = sh.nBands; CFloatImage sumcostIm(n_disp, width, N_STATES); // lowest cumulative cost for current scanline, indexed (d, x, state) CIntImage transIm(n_disp, width, N_STATES); // transition corresponding to lowest cost, indexed (d, x, state) // compute strides (not necessarily == n_disp * N_STATES!) int stride = &sumcostIm.Pixel(0, 1, 0) - &sumcostIm.Pixel(0, 0, 0); int stride2 = &transIm.Pixel(0, 1, 0) - &transIm.Pixel(0, 0, 0); assert(stride == stride2); // store current and predecessor state for each transition: int cstate[N_TRANS] = {0, 1, 1, 0, 2, 2, 0}; int pstate[N_TRANS] = {0, 0, 1, 1, 0, 2, 2}; // store "disparity predecessor" for each transition: int dleft = -n_disp, ddiag = -n_disp - 1, dup = 1; int pdisp[N_TRANS] = {dleft, dleft, ddiag, ddiag, dup, dup, dleft}; // store index offset of predecessor for each transition: int left = -stride, diag = -stride - N_STATES, up = N_STATES; int pindex[N_TRANS] = {left, left, diag, diag, up, up, left}; // store which transitions don't work for border cases: int border0[N_TRANS] = {0, 0, 1, 1, 0, 0, 0}; // for d==0 can't have diag predecessor int border1[N_TRANS] = {0, 0, 0, 0, 1, 1, 0}; // for d==max can't have up predecessor int x, y, d; // process each scanline separately for (y = 0; y < height; y++) { float* cost = &m_cost.Pixel(0, y, 0); int* trans = &transIm.Pixel(0, 0, 0); float* sumcost = &sumcostIm.Pixel(0, 0, 0); // initialize first column for (d = 0; d < n_disp; d++, trans += N_STATES, sumcost += N_STATES) { trans[0] = 0; // match trans[1] = -1; // safety checks (should never be on best path) trans[2] = -1; sumcost[0] = cost[d]; sumcost[1] = COST_MAX; // force first pixel to be non-occluded sumcost[2] = COST_MAX; } cost += n_disp; // keep pointer to m_smooth lag one behind, to reference position x-1 float* smoothcost = &m_smooth.Pixel(0, y, 1); // band 1 is horizontal cost // now, do dynamic programming step and build up costs // for each disparity column for (x = 1; x < width; x++) { trans = &transIm.Pixel(n_disp-1, x, 0); sumcost = &sumcostIm.Pixel(n_disp-1, x, 0); // for each cell, going down for (d = n_disp-1; d >=0; d--, trans -= N_STATES, sumcost -= N_STATES) { sumcost[0] = COST_MAX; sumcost[1] = COST_MAX; sumcost[2] = COST_MAX; trans[0] = -1; trans[1] = -1; trans[2] = -1; // try out all transitions for (int t=0; t =0; d--) { for (x = width-12; x = trans0) { int t = trans[0]; #if 0 // old debugging code if (y<3 && (x < 5 || x > width-15)) fprintf(stderr, "cost = %g, trans = %d, x = %d, d = %d\n", sumcost[0], t, x, best_d); #endif int current_state = cstate[t]; int pred_state = pstate[t]; // record current disparity if (current_state == 0) // matched cell disp[x] = d; else disp[x] = occLabel; // indicator for occluded pixel // update pointers int pred_index = pindex[t] - current_state + pred_state; trans += pred_index; sumcost += pred_index; // only for printing // update disparity d d += pdisp[t]; if (d < 0) { d += n_disp; x--; } } } // end for y if (occLabel != 0) fill_occluded_pixels(m_disparity, occLabel, 0); }