Пример #1
0
static lgfs2_rgrps_t mockup_rgrp(void)
{
	struct gfs2_sbd *sdp;
	lgfs2_rgrps_t rgs;
	unsigned i;
	uint64_t addr;
	struct gfs2_rindex ri = {0};
	lgfs2_rgrp_t rg;
	uint32_t rgsize = (1024 << 20) / 4096;

	sdp = calloc(1, sizeof(*sdp));
	fail_unless(sdp != NULL);

	sdp->device.length = rgsize + 20;
	sdp->device_fd = -1;
	sdp->bsize = sdp->sd_sb.sb_bsize = 4096;
	compute_constants(sdp);

	rgs = lgfs2_rgrps_init(sdp, 0, 0);
	fail_unless(rgs != NULL);

	lgfs2_rgrps_plan(rgs, sdp->device.length - 16, rgsize);

	addr = lgfs2_rindex_entry_new(rgs, &ri, 16, rgsize);
	ck_assert(addr != 0);

	rg = lgfs2_rgrps_append(rgs, &ri);
	fail_unless(rg != NULL);

	for (i = 0; i < rg->ri.ri_length; i++) {
		rg->bits[i].bi_bh = bget(sdp, rg->ri.ri_addr + i);
		fail_unless(rg->bits[i].bi_bh != NULL);
	}
	return rgs;
}
Пример #2
0
static double
distance(struct SubSig *SubSig1, struct SubSig *SubSig2, int nbands)
{
    double dist;

    static int first = 1;
    struct SigSet S;
    static struct ClassSig *Sig3;
    static struct SubSig *SubSig3;


    /* allocate scratch space first time subroutine is called */
    if (first) {
	I_InitSigSet(&S);
	I_SigSetNBands(&S, nbands);
	Sig3 = I_NewClassSig(&S);
	I_NewSubSig(&S, Sig3);
	SubSig3 = Sig3->SubSig;
	first = 0;
    }

    /* form SubSig3 by adding SubSig1 and SubSig2 */
    add_SubSigs(SubSig1, SubSig2, SubSig3, nbands);

    /* compute constant for SubSig3 */
    compute_constants(Sig3, nbands);

    /* compute distance */
    dist = SubSig1->N * SubSig1->cnst + SubSig2->N * SubSig2->cnst
	- SubSig3->N * SubSig3->cnst;

    return (dist);
}
Пример #3
0
static void
reduce_order(struct ClassSig *Sig, int nbands, int *min_ii, int *min_jj)
{
    int i, j;
    int min_i = 0, min_j = 0;
    double dist;
    double min_dist = 0;
    struct SubSig *SubSig1, *SubSig2;

    static int first = 1;
    struct SigSet S;
    static struct ClassSig *Sig3;
    static struct SubSig *SubSig3;

    /* allocate scratch space first time subroutine is called */
    if (first) {
	I_InitSigSet(&S);
	I_SigSetNBands(&S, nbands);
	Sig3 = I_NewClassSig(&S);
	I_NewSubSig(&S, Sig3);
	SubSig3 = Sig3->SubSig;
	first = 0;
    }

    if (Sig->nsubclasses > 1) {
	/* find the closest subclasses */
	for (i = 0; i < Sig->nsubclasses - 1; i++)
	    for (j = i + 1; j < Sig->nsubclasses; j++) {
		dist = distance(&(Sig->SubSig[i]), &(Sig->SubSig[j]), nbands);
		if ((i == 0) && (j == 1)) {
		    min_dist = dist;
		    min_i = i;
		    min_j = j;
		}
		if (dist < min_dist) {
		    min_dist = dist;
		    min_i = i;
		    min_j = j;
		}
	    }

	*min_ii = min_i;
	*min_jj = min_j;

	/* Combine Subclasses */
	SubSig1 = &(Sig->SubSig[min_i]);
	SubSig2 = &(Sig->SubSig[min_j]);
	add_SubSigs(SubSig1, SubSig2, SubSig3, nbands);
	compute_constants(Sig3, nbands);
	copy_SubSig(SubSig3, SubSig1, nbands);

	/* remove extra subclass */
	for (i = min_j; i < Sig->nsubclasses - 1; i++)
	    copy_SubSig(&(Sig->SubSig[i + 1]), &(Sig->SubSig[i]), nbands);

	/* decrement number of Subclasses */
	Sig->nsubclasses--;
    }
}
Пример #4
0
static int reestimate(struct ClassSig *Sig, int nbands)
{
    int i;
    int s;
    int b1, b2;
    int singular;
    double pi_sum;
    double diff1, diff2;
    struct ClassData *Data;

    G_debug(2, "reestimate()");

    /* set data pointer */
    Data = &(Sig->ClassData);

    pi_sum = 0;
    for (i = 0; i < Sig->nsubclasses; i++) {
	/* Compute N */
	Sig->SubSig[i].N = 0;
	for (s = 0; s < Data->npixels; s++)
	    Sig->SubSig[i].N += Data->p[s][i];
	Sig->SubSig[i].pi = Sig->SubSig[i].N;

	/* Compute means and variances for each subcluster, */
	/* and remove small clusters.                       */

	/* For large subclusters */
	if (Sig->SubSig[i].N > SMALLEST_SUBCLUST) {
	    /* Compute mean */
	    for (b1 = 0; b1 < nbands; b1++) {
		Sig->SubSig[i].means[b1] = 0;
		for (s = 0; s < Data->npixels; s++)
		    if (!Rast_is_d_null_value(&Data->x[s][b1]))
			Sig->SubSig[i].means[b1] +=
			    Data->p[s][i] * Data->x[s][b1];
		Sig->SubSig[i].means[b1] /= (Sig->SubSig[i].N);

		/* Compute R */
		for (b2 = 0; b2 <= b1; b2++) {
		    Sig->SubSig[i].R[b1][b2] = 0;
		    for (s = 0; s < Data->npixels; s++) {
			if (!Rast_is_d_null_value(&Data->x[s][b1])
			    && !Rast_is_d_null_value(&Data->x[s][b2])) {
			    diff1 = Data->x[s][b1] - Sig->SubSig[i].means[b1];
			    diff2 = Data->x[s][b2] - Sig->SubSig[i].means[b2];
			    Sig->SubSig[i].R[b1][b2] +=
				Data->p[s][i] * diff1 * diff2;
			}
		    }
		    Sig->SubSig[i].R[b1][b2] /= (Sig->SubSig[i].N);
		    Sig->SubSig[i].R[b2][b1] = Sig->SubSig[i].R[b1][b2];
		}
	    }
	}
	/* For small subclusters */
	else {
	    G_warning(_("Subsignature %d only contains %.0f pixels"),
		      i, Sig->SubSig[i].N);
	    
	    Sig->SubSig[i].pi = 0;

	    for (b1 = 0; b1 < nbands; b1++) {
		Sig->SubSig[i].means[b1] = 0;

		for (b2 = 0; b2 < nbands; b2++)
		    Sig->SubSig[i].R[b1][b2] = 0;
	    }
	}
	pi_sum += Sig->SubSig[i].pi;
    }


    /* Normalize probabilities for subclusters */
    if (pi_sum > 0) {
	for (i = 0; i < Sig->nsubclasses; i++)
	    Sig->SubSig[i].pi /= pi_sum;
    }
    else {
	for (i = 0; i < Sig->nsubclasses; i++)
	    Sig->SubSig[i].pi = 0;
    }


    /* Compute constants and reestimate if any singular subclusters occur */
    singular = compute_constants(Sig, nbands);
    return (singular);
}
Пример #5
0
static void seed(struct ClassSig *Sig, int nbands)
{
    int i, b1, b2;
    double period;
    double *mean, **R;

    G_debug(1, "seed()");

    /* Compute the mean of variance for each band */
    mean = G_alloc_vector(nbands);
    R = G_alloc_matrix(nbands, nbands);
    n_nulls = (int *)G_calloc(nbands, sizeof(int));

    total_nulls = 0;
    for (b1 = 0; b1 < nbands; b1++) {
	n_nulls[b1] = 0;
	mean[b1] = 0.0;
	for (i = 0; i < Sig->ClassData.npixels; i++) {
	    if (Rast_is_d_null_value(&Sig->ClassData.x[i][b1])) {
		n_nulls[b1]++;
		total_nulls++;
	    }
	    else
		mean[b1] += Sig->ClassData.x[i][b1];
	}
	mean[b1] /= (double)(Sig->ClassData.npixels - n_nulls[b1]);
    }

    for (b1 = 0; b1 < nbands; b1++)
	for (b2 = 0; b2 < nbands; b2++) {
	    R[b1][b2] = 0.0;
	    for (i = 0; i < Sig->ClassData.npixels; i++) {
		if (!Rast_is_d_null_value(&Sig->ClassData.x[i][b1]) &&
		    !Rast_is_d_null_value(&Sig->ClassData.x[i][b2]))
		    R[b1][b2] +=
			(Sig->ClassData.x[i][b1]) * (Sig->ClassData.x[i][b2]);
	    }
	    R[b1][b2] /= (double)(Sig->ClassData.npixels - n_nulls[b1] -
				  n_nulls[b2]);
	    R[b1][b2] -= mean[b1] * mean[b2];
	}

    /* Compute the sampling period for seeding */
    if (Sig->nsubclasses > 1) {
	period = (Sig->ClassData.npixels - 1) / (Sig->nsubclasses - 1.0);
    }
    else
	period = 0;


    /* Seed the means and set the diagonal covariance components */
    for (i = 0; i < Sig->nsubclasses; i++) {
	for (b1 = 0; b1 < nbands; b1++) {
	    if (Rast_is_d_null_value(&Sig->ClassData.x[(int)(i * period)][b1]))
		Rast_set_d_null_value(&Sig->SubSig[i].means[b1], 1);
	    else
		Sig->SubSig[i].means[b1] =
		    Sig->ClassData.x[(int)(i * period)][b1];

	    for (b2 = 0; b2 < nbands; b2++) {
		Sig->SubSig[i].R[b1][b2] = R[b1][b2];
	    }
	}

	Sig->SubSig[i].pi = 1.0 / Sig->nsubclasses;
    }

    G_free_vector(mean);
    G_free_matrix(R);

    compute_constants(Sig, nbands);
}
Пример #6
0
int main(int argc, char *argv[])
{
	struct gfs2_sbd sbd, *sdp = &sbd;
	int rindex_fd;
	int error = EXIT_SUCCESS;
	int devflags = (test ? O_RDONLY : O_RDWR) | O_CLOEXEC;

	setlocale(LC_ALL, "");
	textdomain("gfs2-utils");
	srandom(time(NULL) ^ getpid());

	memset(sdp, 0, sizeof(struct gfs2_sbd));
	sdp->bsize = GFS2_DEFAULT_BSIZE;
	sdp->rgsize = -1;
	sdp->jsize = GFS2_DEFAULT_JSIZE;
	sdp->qcsize = GFS2_DEFAULT_QCSIZE;
	sdp->md.journals = 1;
	decode_arguments(argc, argv, sdp);

	for(; (argc - optind) > 0; optind++) {
		struct metafs mfs = {0};
		struct mntent *mnt;
		unsigned rgcount;
		unsigned old_rg_count;
		lgfs2_rgrps_t rgs;

		error = lgfs2_open_mnt(argv[optind], O_RDONLY|O_CLOEXEC, &sdp->path_fd,
		                                       devflags, &sdp->device_fd, &mnt);
		if (error != 0) {
			fprintf(stderr, _("Error looking up mount '%s': %s\n"), argv[optind], strerror(errno));
			exit(EXIT_FAILURE);
		}
		if (mnt == NULL) {
			fprintf(stderr, _("%s: not a mounted gfs2 file system\n"), argv[optind]);
			continue;
		}

		if (lgfs2_get_dev_info(sdp->device_fd, &sdp->dinfo) < 0) {
			perror(mnt->mnt_fsname);
			exit(EXIT_FAILURE);
		}
		sdp->sd_sb.sb_bsize = GFS2_DEFAULT_BSIZE;
		sdp->bsize = sdp->sd_sb.sb_bsize;
		if (compute_constants(sdp)) {
			log_crit("%s\n", _("Failed to compute file system constants"));
			exit(EXIT_FAILURE);
		}
		if (read_sb(sdp) < 0) {
			fprintf(stderr, _("Error reading superblock.\n"));
			exit(EXIT_FAILURE);
		}
		if (sdp->gfs1) {
			fprintf(stderr, _("cannot grow gfs1 filesystem\n"));
			exit(EXIT_FAILURE);
		}
		fix_device_geometry(sdp);
		mfs.context = copy_context_opt(mnt);
		if (mount_gfs2_meta(&mfs, mnt->mnt_dir, (print_level > MSG_NOTICE))) {
			perror(_("Failed to mount GFS2 meta file system"));
			exit(EXIT_FAILURE);
		}
		rindex_fd = open_rindex(mfs.path, (test ? O_RDONLY : O_RDWR));
		if (rindex_fd < 0) {
			cleanup_metafs(&mfs);
			exit(EXIT_FAILURE);
		}
		/* Get master dinode */
		sdp->master_dir = lgfs2_inode_read(sdp, sdp->sd_sb.sb_master_dir.no_addr);
		if (sdp->master_dir == NULL) {
			perror(_("Could not read master directory"));
			exit(EXIT_FAILURE);
		}
		rgs = rgrps_init(sdp);
		if (rgs == NULL) {
			perror(_("Could not initialise resource groups"));
			error = -1;
			goto out;
		}
		/* Fetch the rindex from disk.  We aren't using gfs2 here,  */
		/* which means that the bitmaps will most likely be cached  */
		/* and therefore out of date.  It shouldn't matter because  */
		/* we're only going to write out new RG information after   */
		/* the existing RGs, and only write to the index at EOF.    */
		log_info(_("Gathering resource group information for %s\n"), argv[optind]);
		old_rg_count = lgfs2_rindex_read_fd(rindex_fd, rgs);
		if (old_rg_count == 0) {
			perror(_("Failed to scan existing resource groups"));
			error = -EXIT_FAILURE;
			goto out;
		}
		if (metafs_interrupted)
			goto out;
		fssize = lgfs2_rgrp_align_addr(rgs, filesystem_size(rgs) + 1);
		/* We're done with the old rgs now that we have the fssize and rg count */
		lgfs2_rgrps_free(&rgs);
		/* Now lets set up the new ones with alignment and all */
		rgs = rgrps_init(sdp);
		if (rgs == NULL) {
			perror(_("Could not initialise new resource groups"));
			error = -1;
			goto out;
		}
		fsgrowth = (sdp->device.length - fssize);
		rgcount = lgfs2_rgrps_plan(rgs, fsgrowth, ((GFS2_MAX_RGSIZE << 20) / sdp->bsize));
		if (rgcount == 0) {
			log_err( _("The calculated resource group size is too small.\n"));
			log_err( _("%s has not grown.\n"), argv[optind]);
			error = -1;
			goto out;
		}
		print_info(sdp, mnt->mnt_fsname, mnt->mnt_dir);
		rgcount = initialize_new_portion(sdp, rgs);
		if (rgcount == 0 || metafs_interrupted)
			goto out;
		fsync(sdp->device_fd);
		fix_rindex(rindex_fd, rgs, old_rg_count, rgcount);
	out:
		lgfs2_rgrps_free(&rgs);
		close(rindex_fd);
		cleanup_metafs(&mfs);
		close(sdp->device_fd);

		if (metafs_interrupted)
			break;
	}
	close(sdp->path_fd);
	sync();
	if (metafs_interrupted) {
		log_notice( _("gfs2_grow interrupted.\n"));
		exit(1);
	}
	log_notice( _("gfs2_grow complete.\n"));
	return error;
}
Пример #7
0
// Main
int main(int argc, char ** argv) {

	// Choose the best GPU in case there are multiple available
	choose_GPU();

	// Keep track of the start time of the program
	long long program_start_time = get_time();
	
	if (argc !=3){
	fprintf(stderr, "usage: %s <input file> <number of frames to process>", argv[0]);
	exit(1);
	}
	
	// Let the user specify the number of frames to process
	int num_frames = atoi(argv[2]);
	
	// Open video file
	char *video_file_name = argv[1];
	
	avi_t *cell_file = AVI_open_input_file(video_file_name, 1);
	if (cell_file == NULL)	{
		AVI_print_error("Error with AVI_open_input_file");
		return -1;
	}
	
	int i, j, *crow, *ccol, pair_counter = 0, x_result_len = 0, Iter = 20, ns = 4, k_count = 0, n;
	MAT *cellx, *celly, *A;
	double *GICOV_spots, *t, *G, *x_result, *y_result, *V, *QAX_CENTERS, *QAY_CENTERS;
	double threshold = 1.8, radius = 10.0, delta = 3.0, dt = 0.01, b = 5.0;
	
	// Extract a cropped version of the first frame from the video file
	MAT *image_chopped = get_frame(cell_file, 0, 1, 0);
	printf("Detecting cells in frame 0\n");
	
	// Get gradient matrices in x and y directions
	MAT *grad_x = gradient_x(image_chopped);
	MAT *grad_y = gradient_y(image_chopped);
	
	// Allocate for gicov_mem and strel
	gicov_mem = (float*) malloc(sizeof(float) * grad_x->m * grad_y->n);
	strel = (float*) malloc(sizeof(float) * strel_m * strel_n);

	m_free(image_chopped);

	int grad_m = grad_x->m;
	int grad_n = grad_y->n;
	
#pragma acc data create(sin_angle,cos_angle,theta,tX,tY) \
	create(gicov_mem[0:grad_x->m*grad_y->n])
{
	// Precomputed constants on GPU
	compute_constants();

	// Get GICOV matrices corresponding to image gradients
	long long GICOV_start_time = get_time();
	MAT *gicov = GICOV(grad_x, grad_y);
	long long GICOV_end_time = get_time();

	// Dilate the GICOV matrices
	long long dilate_start_time = get_time();
	MAT *img_dilated = dilate(gicov);
	long long dilate_end_time = get_time();
} /* end acc data */
	
	// Find possible matches for cell centers based on GICOV and record the rows/columns in which they are found
	pair_counter = 0;
	crow = (int *) malloc(gicov->m * gicov->n * sizeof(int));
	ccol = (int *) malloc(gicov->m * gicov->n * sizeof(int));
	for(i = 0; i < gicov->m; i++) {
		for(j = 0; j < gicov->n; j++) {
			if(!double_eq(m_get_val(gicov,i,j), 0.0) && double_eq(m_get_val(img_dilated,i,j), m_get_val(gicov,i,j)))
			{
				crow[pair_counter]=i;
				ccol[pair_counter]=j;
				pair_counter++;
			}
		}
	}

	GICOV_spots = (double *) malloc(sizeof(double) * pair_counter);
	for(i = 0; i < pair_counter; i++)
		GICOV_spots[i] = sqrt(m_get_val(gicov, crow[i], ccol[i]));
	
	G = (double *) calloc(pair_counter, sizeof(double));
	x_result = (double *) calloc(pair_counter, sizeof(double));
	y_result = (double *) calloc(pair_counter, sizeof(double));
	
	x_result_len = 0;
	for (i = 0; i < pair_counter; i++) {
		if ((crow[i] > 29) && (crow[i] < BOTTOM - TOP + 39)) {
			x_result[x_result_len] = ccol[i];
			y_result[x_result_len] = crow[i] - 40;
			G[x_result_len] = GICOV_spots[i];
			x_result_len++;
		}
	}
	
	// Make an array t which holds each "time step" for the possible cells
	t = (double *) malloc(sizeof(double) * 36);
	for (i = 0; i < 36; i++) {
		t[i] = (double)i * 2.0 * PI / 36.0;
	}
	
	// Store cell boundaries (as simple circles) for all cells
	cellx = m_get(x_result_len, 36);
	celly = m_get(x_result_len, 36);
	for(i = 0; i < x_result_len; i++) {
		for(j = 0; j < 36; j++) {
			m_set_val(cellx, i, j, x_result[i] + radius * cos(t[j]));
			m_set_val(celly, i, j, y_result[i] + radius * sin(t[j]));
		}
	}
	
	A = TMatrix(9,4);
	V = (double *) malloc(sizeof(double) * pair_counter);
	QAX_CENTERS = (double * )malloc(sizeof(double) * pair_counter);
	QAY_CENTERS = (double *) malloc(sizeof(double) * pair_counter);
	memset(V, 0, sizeof(double) * pair_counter);
	memset(QAX_CENTERS, 0, sizeof(double) * pair_counter);
	memset(QAY_CENTERS, 0, sizeof(double) * pair_counter);

	// For all possible results, find the ones that are feasibly leukocytes and store their centers
	k_count = 0;
	for (n = 0; n < x_result_len; n++) {
		if ((G[n] < -1 * threshold) || G[n] > threshold) {
			MAT * x, *y;
			VEC * x_row, * y_row;
			x = m_get(1, 36);
			y = m_get(1, 36);

			x_row = v_get(36);
			y_row = v_get(36);

			// Get current values of possible cells from cellx/celly matrices
			x_row = get_row(cellx, n, x_row);
			y_row = get_row(celly, n, y_row);
			uniformseg(x_row, y_row, x, y);

			// Make sure that the possible leukocytes are not too close to the edge of the frame
			if ((m_min(x) > b) && (m_min(y) > b) && (m_max(x) < cell_file->width - b) && (m_max(y) < cell_file->height - b)) {
				MAT * Cx, * Cy, *Cy_temp, * Ix1, * Iy1;
				VEC  *Xs, *Ys, *W, *Nx, *Ny, *X, *Y;
				Cx = m_get(1, 36);
				Cy = m_get(1, 36);
				Cx = mmtr_mlt(A, x, Cx);
				Cy = mmtr_mlt(A, y, Cy);
				
				Cy_temp = m_get(Cy->m, Cy->n);
				
				for (i = 0; i < 9; i++)
					m_set_val(Cy, i, 0, m_get_val(Cy, i, 0) + 40.0);
					
				// Iteratively refine the snake/spline
				for (i = 0; i < Iter; i++) {
					int typeofcell;
					
					if(G[n] > 0.0) typeofcell = 0;
					else typeofcell = 1;
					
					splineenergyform01(Cx, Cy, grad_x, grad_y, ns, delta, 2.0 * dt, typeofcell);
				}
				
				X = getsampling(Cx, ns);
				for (i = 0; i < Cy->m; i++)
					m_set_val(Cy_temp, i, 0, m_get_val(Cy, i, 0) - 40.0);
				Y = getsampling(Cy_temp, ns);
				
				Ix1 = linear_interp2(grad_x, X, Y);
				Iy1 = linear_interp2(grad_x, X, Y);
				Xs = getfdriv(Cx, ns);
				Ys = getfdriv(Cy, ns);
				
				Nx = v_get(Ys->dim);
				for (i = 0; i < Ys->dim; i++)
					v_set_val(Nx, i, v_get_val(Ys, i) / sqrt(v_get_val(Xs, i)*v_get_val(Xs, i) + v_get_val(Ys, i)*v_get_val(Ys, i)));
					
				Ny = v_get(Xs->dim);
				for (i = 0; i < Xs->dim; i++)
					v_set_val(Ny, i, -1.0 * v_get_val(Xs, i) / sqrt(v_get_val(Xs, i)*v_get_val(Xs, i) + v_get_val(Ys, i)*v_get_val(Ys, i)));
					
				W = v_get(Nx->dim);
				for (i = 0; i < Nx->dim; i++)
					v_set_val(W, i, m_get_val(Ix1, 0, i) * v_get_val(Nx, i) + m_get_val(Iy1, 0, i) * v_get_val(Ny, i));
					
				V[n] = mean(W) / std_dev(W);
				
				// Find the cell centers by computing the means of X and Y values for all snaxels of the spline contour
				QAX_CENTERS[k_count] = mean(X);
				QAY_CENTERS[k_count] = mean(Y) + TOP;
				
				k_count++;
				
				// Free memory
				v_free(W);
				v_free(Ny);
				v_free(Nx);
				v_free(Ys);
				v_free(Xs);
				m_free(Iy1);
				m_free(Ix1);
				v_free(Y);
				v_free(X);
				m_free(Cy_temp);
				m_free(Cy);
				m_free(Cx);				
			}

			// Free memory
			v_free(y_row);
			v_free(x_row);
			m_free(y);
			m_free(x);
		}
	}
	
	// Free memory
	free(gicov_mem);
	free(strel);
	free(V);
	free(ccol);
	free(crow);
	free(GICOV_spots);
	free(t);
	free(G);
	free(x_result);
	free(y_result);
	m_free(A);
	m_free(celly);
	m_free(cellx);
	m_free(img_dilated);
	m_free(gicov);
	m_free(grad_y);
	m_free(grad_x);
	
	// Report the total number of cells detected
	printf("Cells detected: %d\n\n", k_count);
	
	// Report the breakdown of the detection runtime
	printf("Detection runtime\n");
	printf("-----------------\n");
	printf("GICOV computation: %.5f seconds\n", ((float) (GICOV_end_time - GICOV_start_time)) / (1000*1000));
	printf("   GICOV dilation: %.5f seconds\n", ((float) (dilate_end_time - dilate_start_time)) / (1000*1000));
	printf("            Total: %.5f seconds\n", ((float) (get_time() - program_start_time)) / (1000*1000));
	
	// Now that the cells have been detected in the first frame,
	//  track the ellipses through subsequent frames
	if (num_frames > 1) printf("\nTracking cells across %d frames\n", num_frames);
	else                printf("\nTracking cells across 1 frame\n");
	long long tracking_start_time = get_time();
	int num_snaxels = 20;
	ellipsetrack(cell_file, QAX_CENTERS, QAY_CENTERS, k_count, radius, num_snaxels, num_frames);
	printf("           Total: %.5f seconds\n", ((float) (get_time() - tracking_start_time)) / (float) (1000*1000*num_frames));	
	
	// Report total program execution time
    printf("\nTotal application run time: %.5f seconds\n", ((float) (get_time() - program_start_time)) / (1000*1000));

	return 0;
}