コード例 #1
0
ファイル: convolution.cpp プロジェクト: HarveyLiuFly/TheiaSfM
void GaussianBlur(const RowMatrixXf& image,
                  const double sigma,
                  RowMatrixXf* out) {
  int kernel_size = std::ceil(((sigma - 0.8) / 0.3 + 1.0) * 2.0);
  if (kernel_size % 2 == 0) {
    kernel_size += 1;
  }

  RowVectorXf gauss_kernel(kernel_size);
  double norm_factor = 0;
  for (int i = 0; i < gauss_kernel.size(); i++) {
    gauss_kernel(i) = Gaussian(i, (kernel_size - 1.0) / 2.0, sigma);
    norm_factor += gauss_kernel(i);
  }
  gauss_kernel /= norm_factor;

  SeparableConvolution2d(image,
                         gauss_kernel,
                         gauss_kernel,
                         REPLICATE,
                         out);
}
コード例 #2
0
ファイル: mean_shift.c プロジェクト: GRASS-GIS/grass-ci
int mean_shift(struct globals *globals)
{
    int row, col, t, n;
    int mwrow, mwrow1, mwrow2, mwnrows, mwcol, mwcol1, mwcol2, mwncols, radiusc;
    double hspat, hspec, hspat2, hspec2, sigmaspat2, sigmaspec2;
    double hspecad, hspecad2;
    double ka2;
    double w, wsum;
    LARGEINT n_changes;
    double alpha2, maxdiff2;
    struct ngbr_stats Rin, Rout, Rn;
    double diff, diff2;
    SEGMENT *seg_tmp;
    double mindiff, mindiffzero, mindiffavg, mindiffzeroavg;
    double avgdiff, avgdiffavg;
    LARGEINT nvalid, count;
    int do_gauss = 0, do_adaptive, do_progressive;

    Rin.mean = G_malloc(globals->datasize);
    Rout.mean = G_malloc(globals->datasize);
    Rn.mean = G_malloc(globals->datasize);

    alpha2 = globals->alpha * globals->alpha;
    do_adaptive = globals->ms_adaptive;
    do_progressive = globals->ms_progressive;
    
    globals->candidate_count = 0;
    flag_clear_all(globals->candidate_flag);

    /* Set candidate flag to true/1 for all non-NULL cells */
    for (row = globals->row_min; row < globals->row_max; row++) {
	for (col = globals->col_min; col < globals->col_max; col++) {
	    if (!(FLAG_GET(globals->null_flag, row, col))) {
		
		FLAG_SET(globals->candidate_flag, row, col);
		globals->candidate_count++;
	    }
	}
    }

    /* spatial bandwidth */
    hspat = globals->hs;
    if (hspat < 1) {
	hspat = 1.5;
	globals->hs = hspat;
    }

    hspat2 = hspat * hspat;
    sigmaspat2 = hspat2 / 9.;
    radiusc = hspat;	/* radius in cells truncated to integer */
    mwnrows = mwncols = radiusc * 2 + 1;

    /* estimate spectral bandwidth for given spatial bandwidth */
    mindiffavg = mindiffzeroavg = 0;
    avgdiffavg = 0;
    nvalid = 0;

    G_message(_("Estimating spectral bandwidth for spatial bandwidth %g..."), hspat);
    G_percent_reset();
    for (row = globals->row_min; row < globals->row_max; row++) {
	G_percent(row - globals->row_min,
		  globals->row_max - globals->row_min, 4);

	mwrow1 = row - radiusc;
	mwrow2 = mwrow1 + mwnrows;
	if (mwrow1 < globals->row_min)
	    mwrow1 = globals->row_min;
	if (mwrow2 > globals->row_max)
	    mwrow2 = globals->row_max;

	for (col = globals->col_min; col < globals->col_max; col++) {
	    if ((FLAG_GET(globals->null_flag, row, col)))
		continue;

	    /* get current band values */
	    Segment_get(globals->bands_in, (void *)Rin.mean,
			row, col);

	    mwcol1 = col - radiusc;
	    mwcol2 = mwcol1 + mwncols;
	    if (mwcol1 < globals->col_min)
		mwcol1 = globals->col_min;
	    if (mwcol2 > globals->col_max)
		mwcol2 = globals->col_max;
	    
	    /* get minimum spectral distance for this cell */
	    count = 0;
	    mindiff = globals->max_diff;
	    mindiffzero = globals->max_diff;
	    avgdiff = 0;
	    for (mwrow = mwrow1; mwrow < mwrow2; mwrow++) {
		for (mwcol = mwcol1; mwcol < mwcol2; mwcol++) {
		    if ((FLAG_GET(globals->null_flag, mwrow, mwcol)))
			continue;
		    if (mwrow == row && mwcol == col)
			continue;

		    diff = mwrow - row;
		    diff2 = diff * diff;
		    diff = mwcol - col;
		    diff2 += diff * diff;

		    if (diff2 <= hspat2) {

			Segment_get(globals->bands_in, (void *)Rn.mean,
				    mwrow, mwcol);

			/* get spectral distance */
			diff2 = (globals->calculate_similarity)(&Rin, &Rn, globals);

			if (mindiff > diff2)
			    mindiff = diff2;
			if (mindiffzero > diff2 && diff2 > 0)
			    mindiffzero = diff2;
			avgdiff += sqrt(diff2);
			count++;
		    }
		}
	    }
	    if (count) {
		nvalid++;
		if (mindiff > 0)
		    mindiffavg += sqrt(mindiff);
		mindiffzeroavg += sqrt(mindiffzero);
		if (avgdiff > 0)
		    avgdiffavg += avgdiff / count;
	    }
	}
    }
    G_percent(1, 1, 1);
    if (!nvalid) {
	G_fatal_error(_("Empty moving windows"));
    }

    mindiffavg /= nvalid;
    mindiffzeroavg /= nvalid;
    avgdiffavg /= nvalid;
    G_debug(1, "Average minimum difference to neighbours: %g", mindiffavg);
    G_debug(1, "Average minimum difference excl zero to neighbours: %g", mindiffzeroavg);
    G_debug(1, "Average average difference to neighbours: %g", avgdiffavg);

    /* use avgdiffavg as hspec for adaptive bandwidth */

    hspec = globals->hr;
    if (hspec < 0 || hspec >= 1) {
	hspec = sqrt(avgdiffavg / 10.0);
	hspec = avgdiffavg;
	hspec = mindiffzeroavg;
	
	if (do_progressive)
	    G_message(_("Initial range bandwidth: %g"), hspec);
	else
	    G_message(_("Estimated range bandwidth: %g"), hspec);
	globals->hr = hspec;
    }
    else {
	G_message(_("Estimated range bandwidth: %g"), mindiffzeroavg);
    }
    if (do_adaptive) {
	/* bandwidth is now standard deviation for adaptive bandwidth 
	 * using a gaussian function with range bandwith used as 
	 * bandwidth for the gaussian function
	 * the aim is to produce similar but improved results with 
	 * adaptive bandwidth
	 * thus increase bandwidth */
	hspec = sqrt(hspec);
    }

    hspec2 = hspec * hspec;
    sigmaspec2 = hspec2 / 9.;

    if (!do_progressive) {
	G_message(_("Spatial bandwidth: %g"), hspat);
	G_message(_("Range bandwidth: %g"), hspec);
    }

    G_debug(4, "Starting to process %ld candidate cells",
	    globals->candidate_count);

    t = 0;
    n_changes = 1;
    maxdiff2 = 0;
    while (t < globals->end_t && n_changes > 0) {

	G_message(_("Processing pass %d..."), ++t);

	/* cells within an object should become more similar with each pass
	 * therefore the spectral bandwidth could be decreased
	 * and the spatial bandwidth could be increased */

	/* spatial bandwidth: double the area covered by the moving window
	 * area = M_PI * hspat * hspat
	 * new hspat = sqrt(M_PI * hspat * hspat * 2 / M_PI)
	 * no good, too large increases */

	if (do_progressive) {
	    if (t > 1)
		hspat *= 1.1;
	    hspat2 = hspat * hspat;
	    sigmaspat2 = hspat2 / 9.;
	    radiusc = hspat;	/* radius in cells truncated to integer */
	    mwnrows = mwncols = radiusc * 2 + 1;

	    /* spectral bandwidth: reduce by 0.7 */
	    if (t > 1)
		hspec *= 0.9;
	    hspec2 = hspec * hspec;
	    sigmaspec2 = hspec2 / 9.;

	    G_verbose_message(_("Spatial bandwidth: %g"), hspat);
	    G_verbose_message(_("Range bandwidth: %g"), hspec);
	}

	n_changes = 0;
	maxdiff2 = 0;

	/* swap input and output */
	seg_tmp = globals->bands_in;
	globals->bands_in = globals->bands_out;
	globals->bands_out = seg_tmp;

	/*process candidate cells */
	G_percent_reset();
	for (row = globals->row_min; row < globals->row_max; row++) {
	    G_percent(row - globals->row_min,
	              globals->row_max - globals->row_min, 4);

	    mwrow1 = row - radiusc;
	    mwrow2 = mwrow1 + mwnrows;
	    if (mwrow1 < globals->row_min)
		mwrow1 = globals->row_min;
	    if (mwrow2 > globals->row_max)
		mwrow2 = globals->row_max;

	    for (col = globals->col_min; col < globals->col_max; col++) {
		if ((FLAG_GET(globals->null_flag, row, col)))
		    continue;

		/* get current band values */
		Segment_get(globals->bands_in, (void *)Rin.mean,
			    row, col);
		
		/* init output */
		for (n = 0; n < globals->nbands; n++)
		    Rout.mean[n] = 0.;

		mwcol1 = col - radiusc;
		mwcol2 = mwcol1 + mwncols;
		if (mwcol1 < globals->col_min)
		    mwcol1 = globals->col_min;
		if (mwcol2 > globals->col_max)
		    mwcol2 = globals->col_max;

		hspecad2 = hspec2;
		
		if (do_adaptive) {
		    /* adapt initial range bandwith */
		    
		    ka2 = hspec2; 	/* OTB: conductance parameter */
		    
		    avgdiff = 0;
		    count = 0;
		    for (mwrow = mwrow1; mwrow < mwrow2; mwrow++) {
			for (mwcol = mwcol1; mwcol < mwcol2; mwcol++) {
			    if ((FLAG_GET(globals->null_flag, mwrow, mwcol)))
				continue;
			    if (mwrow == row && mwcol == col)
				continue;

			    diff = mwrow - row;
			    diff2 = diff * diff;
			    diff = mwcol - col;
			    diff2 += diff * diff;

			    if (diff2 <= hspat2) {

				Segment_get(globals->bands_in, (void *)Rn.mean,
					    mwrow, mwcol);

				/* get spectral distance */
				diff2 = (globals->calculate_similarity)(&Rin, &Rn, globals);

				avgdiff += sqrt(diff2);
				count++;
			    }
			}
		    }
		    hspecad2 = 0;
		    if (avgdiff > 0) {
			avgdiff /= count;
			hspecad = hspec;
			/* OTB-like, contrast enhancing */
			hspecad = exp(-avgdiff * avgdiff / (2 * ka2)) * avgdiff;
			/* preference for large regions, from Perona Malik 1990 
			 * if the settings are right, it could be used to reduce noise */
			/* hspecad = 1 / (1 + (avgdiff * avgdiff / (2 * hspec2))); */
			hspecad2 = hspecad * hspecad;
			G_debug(1, "avg spectral diff: %g", avgdiff);
			G_debug(1, "initial hspec2: %g", hspec2);
			G_debug(1, "adapted hspec2: %g", hspecad2);
		    }
		}
		
		/* actual mean shift */
		wsum = 0;
		for (mwrow = mwrow1; mwrow < mwrow2; mwrow++) {
		    for (mwcol = mwcol1; mwcol < mwcol2; mwcol++) {
			if ((FLAG_GET(globals->null_flag, mwrow, mwcol)))
			    continue;
			diff = mwrow - row;
			diff2 = diff * diff;
			diff = mwcol - col;
			diff2 += diff * diff;

			if (diff2 <= hspat2) {
			    w = 1;
			    if (do_gauss)
				w = gauss_kernel(diff2, sigmaspat2);

			    Segment_get(globals->bands_in, (void *)Rn.mean,
					mwrow, mwcol);

			    /* check spectral distance */
			    diff2 = (globals->calculate_similarity)(&Rin, &Rn, globals);
			    if (diff2 <= hspecad2) {
				if (do_gauss)
				    w *= gauss_kernel(diff2, sigmaspec2);
				wsum += w;
				for (n = 0; n < globals->nbands; n++)
				    Rout.mean[n] += w * Rn.mean[n];
			    }
			}
		    }
		}
		
		if (wsum > 0) {
		    for (n = 0; n < globals->nbands; n++)
			Rout.mean[n] /= wsum;
		}
		else {
		    for (n = 0; n < globals->nbands; n++)
			Rout.mean[n] = Rin.mean[n];
		}

		/* put new band values */
		Segment_put(globals->bands_out, (void *)Rout.mean,
			    row, col);

		/* if the squared difference between old and new band values 
		 * is larger than alpha2, then increase n_changes */
		
		diff2 = (globals->calculate_similarity)(&Rin, &Rout, globals);
		if (diff2 > alpha2)
		    n_changes++;
		if (maxdiff2 < diff2)
		    maxdiff2 = diff2;
	    }
	}
	G_percent(1, 1, 1);
	G_message(_("Changes > threshold: %d, largest change: %g"), n_changes, sqrt(maxdiff2));
    }
    if (n_changes > 1)
	G_message(_("Mean shift stopped at %d due to reaching max iteration limit, more changes may be possible"), t);
    else
	G_message(_("Mean shift converged after %d iterations"), t);

    /* identify connected components */
    cluster_bands(globals);

    /* remove small regions */
    remove_small_clumps(globals);
    
    return TRUE;
}