コード例 #1
0
ファイル: hsm.c プロジェクト: abachrach/csm
void hsm_find_peaks_circ(int n, const double*f, double min_angle_deg, int unidir, int max_peaks,
	int*peaks, int* npeaks)
{
	sm_log_push("hsm_find_peaks_circ");

	assert(max_peaks>0);

	/* Find all local maxima for the function */
	int maxima[n], nmaxima;
	hsm_find_local_maxima_circ(n, f, maxima, &nmaxima);

	sm_debug("Found %d of %d are local maxima.\n", nmaxima, n);

	/* Sort based on value */
	qsort_descending(maxima, (size_t) nmaxima, f);

	*npeaks = 0;

	sm_log_push("For each maximum");
	/* Only retain a subset of these */
	for(int m=0;m<nmaxima;m++) {
		/* Here's a candidate maximum */
		int candidate = maxima[m];
		double candidate_angle = candidate * (2*M_PI/n);
		/* Check that is not too close to the already accepted maxima */
		int acceptable = 1;
		for(int a=0;a<*npeaks;a++) {
			int other = peaks[a];
			double other_angle = other * (2*M_PI/n);

			if(hsm_is_angle_between_smaller_than_deg(candidate_angle,other_angle,min_angle_deg)) {
				acceptable = 0; break;
			}

			/* If unidir, check also +M_PI */
			if(unidir)
			if(hsm_is_angle_between_smaller_than_deg(candidate_angle+M_PI,other_angle,min_angle_deg)) {
				acceptable = 0; break;
			}

		}

		sm_debug("%saccepting candidate %d; lag = %d value = %f\n",
			acceptable?"":"not ", m, maxima[m], f[maxima[m]]);

		if(acceptable) {
			peaks[*npeaks] = candidate;
			(*npeaks) ++;
		}

		if(*npeaks>=max_peaks) break;
	}
	sm_log_pop();

	sm_debug("found %d (max %d) maxima.\n", *npeaks, max_peaks);
	sm_log_pop();
}
コード例 #2
0
ファイル: hsm.c プロジェクト: abachrach/csm
void hsm_find_peaks_linear(int n, const double*f, double min_dist, int max_peaks,
	int*peaks, int* npeaks)
{
	sm_log_push("hsm_find_peaks_linear");

	assert(max_peaks>0);

	/* Find all local maxima for the function */
	int maxima[n], nmaxima;
	hsm_find_local_maxima_linear(n,f,maxima,&nmaxima);

	sm_debug("Found %d of %d are local maxima.\n", nmaxima, n);

	/* Sort based on value */
	qsort_descending(maxima, (size_t) nmaxima,  f);

	*npeaks = 0;
	sm_log_push("for each maximum");
	/* Only retain a subset of these */
	for(int m=0;m<nmaxima;m++) {
		/* Here's a candidate maximum */
		int candidate = maxima[m];
		/* Check that is not too close to the already accepted maxima */
		int acceptable = 1;
		for(int a=0;a<*npeaks;a++) {
			int other = peaks[a];

			if(abs(other-candidate) < min_dist) {
				acceptable = 0; break;
			}
		}

		sm_debug("%s accepting candidate %d; lag = %d value = %f\n",
			acceptable?"":"not", m, maxima[m], f[maxima[m]]);

		if(acceptable) {
			peaks[*npeaks] = candidate;
			(*npeaks) ++;
		}

		if(*npeaks >= max_peaks) break;
	}
	sm_log_pop("");
	sm_debug("Found %d (max %d) maxima.\n", *npeaks, max_peaks);

	sm_log_pop();
}
コード例 #3
0
int main(int argc, char **argv) 
{
    const int dim = 128;

    if (argc != 6 && argc != 7 && argc != 8) {
        printf("Usage: %s <tree.in> <db.in> <query.in> <num_nbrs> "
               "<matches.out> [distance_type:1] [normalize:1]\n", argv[0]);
        return 1;
    }
    
    char *tree_in = argv[1];
    char *db_in = argv[2];
    char *query_in = argv[3];
    int num_nbrs = atoi(argv[4]);
    char *matches_out = argv[5];
    DistanceType distance_type = DistanceMin;
    bool normalize = true;

#if 0    
    if (argc >= 7)
        output_html = argv[6];
#endif

    if (argc >= 7)
        distance_type = (DistanceType) atoi(argv[6]);

    if (argc >= 8)
        normalize = (atoi(argv[7]) != 0);

    printf("[VocabMatch] Using tree %s\n", tree_in);

    switch (distance_type) {
    case DistanceDot:
        printf("[VocabMatch] Using distance Dot\n");
        break;        
    case DistanceMin:
        printf("[VocabMatch] Using distance Min\n");
        break;
    default:
        printf("[VocabMatch] Using no known distance!\n");
        break;
    }

    /* Read the tree */
    printf("[VocabMatch] Reading tree...\n");
    fflush(stdout);

    clock_t start = clock();
    VocabTree tree;
    tree.Read(tree_in);

    clock_t end = clock();
    printf("[VocabMatch] Read tree in %0.3fs\n", 
           (double) (end - start) / CLOCKS_PER_SEC);

#if 1
    tree.Flatten();
#endif

    tree.SetDistanceType(distance_type);
    tree.SetInteriorNodeWeight(0, 0.0);
    
    /* Read the database keyfiles */
    FILE *f = fopen(db_in, "r");
    
    std::vector<std::string> db_files;
    char buf[256];
    while (fgets(buf, 256, f)) {
        /* Remove trailing newline */
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = 0;

        db_files.push_back(std::string(buf));
    }

    fclose(f);

    /* Read the query keyfiles */
    f = fopen(query_in, "r");
    
    std::vector<std::string> query_files;
    while (fgets(buf, 256, f)) {
        /* Remove trailing newline */
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = 0;

        char keyfile[256];
        sscanf(buf, "%s", keyfile);

        query_files.push_back(std::string(keyfile));
    }

    fclose(f);

    int num_db_images = db_files.size();
    int num_query_images = query_files.size();

    printf("[VocabMatch] Read %d database images\n", num_db_images);

    /* Now score each query keyfile */
    printf("[VocabMatch] Scoring %d query images...\n", num_query_images);
    fflush(stdout);

#if 0
    FILE *f_html = fopen(output_html, "w");
    PrintHTMLHeader(f_html, num_nbrs);
#endif

    float *scores = new float[num_db_images];
    double *scores_d = new double[num_db_images];
    int *perm = new int[num_db_images];

    FILE *f_match = fopen(matches_out, "w");
    if (f_match == NULL) {
        printf("[VocabMatch] Error opening file %s for writing\n",
               matches_out);
        return 1;
    }

    for (int i = 0; i < num_query_images; i++) {
        start = clock();

        /* Clear scores */
        for (int j = 0; j < num_db_images; j++) 
            scores[j] = 0.0;

        int num_keys = 0;
        unsigned char *keys = ReadDescriptorFile(query_files[i].c_str(), 
                                                 dim, num_keys);

        clock_t start_score = clock();
        double mag = tree.ScoreQueryKeys(num_keys, normalize, keys, scores);
        clock_t end_score = end = clock();

        printf("[VocabMatch] Scored image %s in %0.3fs "
               "( %0.3fs total, num_keys = %d, mag = %0.3f )\n", 
               query_files[i].c_str(), 
               (double) (end_score - start_score) / CLOCKS_PER_SEC,
               (double) (end - start) / CLOCKS_PER_SEC, num_keys, mag);

        /* Find the top scores */
        for (int j = 0; j < num_db_images; j++) {
            scores_d[j] = (double) scores[j];
        }

        qsort_descending();
        qsort_perm(num_db_images, scores_d, perm);        

        int top = MIN(num_nbrs, num_db_images);

        for (int j = 0; j < top; j++) {
            // if (perm[j] == index_i)
            //     continue;
            
            fprintf(f_match, "%d %d %0.4f\n", i, perm[j], scores_d[j]);
            //fprintf(f_match, "%d %d %0.4f\n", i, perm[j], mag - scores_d[j]);
        }
        
        fflush(f_match);
        fflush(stdout);

#if 0
        PrintHTMLRow(f_html, query_files[i], scores_d, 
                     perm, num_nbrs, db_files);
#endif

        delete [] keys;
    }

    fclose(f_match);

#if 0
    PrintHTMLFooter(f_html);
    fclose(f_html);
#endif

    delete [] scores;
    delete [] scores_d;
    delete [] perm;

    return 0;
}
コード例 #4
0
int main(int argc, char **argv) 
{
    const int dim = 128;

    if (argc != 6 && argc != 7 && argc != 8 && argc != 9 && argc != 10 && 
        argc != 11) {
        printf("Usage: %s <tree.in> <db.in> <query.in> <num_nbrs> "
               "<match-script.out> [leaves_only] [distance_type] [normalize] "
               "[min_feature_scale] [max_keys]\n",
               argv[0]);
        return 1;
    }
    
    char *tree_in = argv[1];
    char *db_in = argv[2];
    char *query_in = argv[3];
    int num_nbrs = atoi(argv[4]);
    char *matches_out = argv[5];
    bool leaves_only = false;
    bool normalize = true;
    double min_feature_scale = 0.0;
    DistanceType distance_type = DistanceMin;
    int max_keys = 0;

    if (argc >= 7) {
        if (atoi(argv[6]) != 0)
            leaves_only = true;
    }

    if (argc >= 8)
        distance_type = (DistanceType) atoi(argv[7]);

    if (argc >= 9)
        if (atoi(argv[8]) == 0)
            normalize = false;

    if (argc >= 10) {
        min_feature_scale = atof(argv[9]);
    }

    if (argc >= 11) {
        max_keys = atoi(argv[10]);
    }

    if (leaves_only) {
        printf("[VocabMatch] Scoring with leaves only\n");
    } else {
        printf("[VocabMatch] Scoring with all nodes\n");
    }

    printf("[VocabMatch] Using tree %s\n", tree_in);
    printf("[VocabMatch] min_feature_scale = %0.3f\n", min_feature_scale);
    printf("[VocabMatch] max_keys = %d\n", max_keys);

    switch (distance_type) {
    case DistanceDot:
        printf("[VocabMatch] Using distance Dot\n");
        break;        
    case DistanceMin:
        printf("[VocabMatch] Using distance Min\n");
        break;
    default:
        printf("[VocabMatch] Using no known distance!\n");
        break;
    }

    /* Read the tree */
    printf("[VocabMatch] Reading tree...\n");
    fflush(stdout);

    clock_t start = clock();
    VocabTree tree;
    tree.Read(tree_in);
    clock_t end = clock();
    printf("[VocabMatch] Read tree in %0.3fs\n", 
           (double) (end - start) / CLOCKS_PER_SEC);

#if 1
    tree.Flatten();
#endif

    tree.SetDistanceType(distance_type);

    if (leaves_only) {
        tree.SetInteriorNodeWeight(atoi(argv[6]) - 1, 0.0);
        // #define CONSTANT_WEIGHTS
#ifdef CONSTANT_WEIGHTS
        tree.SetConstantLeafWeights();
#endif
    }
    
    /* Read the database keyfiles */
    FILE *f = fopen(db_in, "r");
    
    std::vector<std::string> db_files;
    char buf[256];
    while (fgets(buf, 256, f)) {
        /* Remove trailing newline */
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = 0;

        db_files.push_back(std::string(buf));
    }

    fclose(f);

    /* Read the query keyfiles */
    f = fopen(query_in, "r");
    
    std::vector<std::string> query_files;
    std::vector<int> query_indices;
    while (fgets(buf, 256, f)) {
        /* Remove trailing newline */
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = 0;

        char keyfile[256];
        int index;
        sscanf(buf, "%d %s", &index, keyfile);

        query_files.push_back(std::string(keyfile));
        query_indices.push_back(index);
    }

    fclose(f);

    /* Populate the database */
    printf("[VocabMatch] Populating database...\n");
    fflush(stdout);

    int num_db_images = db_files.size();
    int num_query_images = query_files.size();

    /* Now score each query keyfile */
    printf("[VocabMatch] Scoring query images...\n");
    fflush(stdout);

    float *scores = new float[num_db_images];
    double *scores_d = new double[num_db_images];
    int *perm = new int[num_db_images];

    FILE *f_match = fopen(matches_out, "w");
    if (f_match == NULL) {
        printf("[VocabMatch] Error opening file %s for writing\n",
               matches_out);
        return 1;
    }

    for (int i = 0; i < num_query_images; i++) {
        int index_i = query_indices[i];

        start = clock();

        /* Clear scores */
        for (int j = 0; j < num_db_images; j++) 
            scores[j] = 0.0;

        unsigned char *keys;
        int num_keys;

        keys = ReadAndFilterKeys(query_files[i].c_str(), dim, 
                                 min_feature_scale, max_keys, num_keys);

        tree.ScoreQueryKeys(num_keys, /*i,*/ true, keys, scores);

        end = clock();
        printf("[VocabMatch] Scored image %s (%d keys) in %0.3fs\n", 
               query_files[i].c_str(), num_keys,
               (double) (end - start) / CLOCKS_PER_SEC);

#if 0
        for (int j = 0; j < num_db_images; j++) {
            /* Normalize scores */
            if (magnitudes[j] > 0.0)
                scores[j] /= magnitudes[j];
            else 
                scores[j] = 0.0;
        }
#endif

        /* Find the top scores */
        for (int j = 0; j < num_db_images; j++) {
            scores_d[j] = (double) scores[j];
        }

        qsort_descending();
        qsort_perm(num_db_images, scores_d, perm);        
        // assert(is_sorted(num_db_images, scores_d));

        int top = MIN(num_nbrs+1, num_db_images);

        for (int j = 0; j < top; j++) {
            if (perm[j] == index_i)
                continue;
            fprintf(f_match, "%d %d %0.5e\n", index_i, perm[j], scores_d[j]);
            fflush(f_match);
        }
        
        fflush(stdout);

        delete [] keys;
    }

    fclose(f_match);

    delete [] scores;
    delete [] scores_d;
    delete [] perm;

    return 0;
}
コード例 #5
0
ファイル: horn.c プロジェクト: AsherBond/MondocosmOS
/* Computes the closed-form least-squares solution to a rigid
 * body alignment.
 *
 * n: the number of points
 * right_pts: Target set of n points 
 * left_pts:  Source set of n points */
double align_horn_3D(int n, v3_t *right_pts, v3_t *left_pts, int scale_xform, 
		     double *Tout) {
    int i;
    v3_t right_centroid = v3_new(0.0, 0.0, 0.0);
    v3_t left_centroid = v3_new(0.0, 0.0, 0.0);
    double M[3][3] = { { 0.0, 0.0, 0.0, }, 
                       { 0.0, 0.0, 0.0, },
		       { 0.0, 0.0, 0.0, } };
    double MT[3][3];
    double MTM[3][3];
    double eval[3], sqrteval_inv[3];
    double evec[3][3], evec_tmp[3][3];
    double Sinv[3][3], U[3][3];
    double Tcenter[4][4] = { { 1.0, 0.0, 0.0, 0.0 },
			     { 0.0, 1.0, 0.0, 0.0 },
			     { 0.0, 0.0, 1.0, 0.0 },
			     { 0.0, 0.0, 0.0, 1.0 } };

    double Ttmp[4][4];
    double T[16], R[16];

    double sum_num, sum_den, scale, RMS_sum;

    int perm[3];

    /* Compute the centroid of both point sets */
    right_centroid = v3_mean(n, right_pts);
    left_centroid  = v3_mean(n, left_pts);

    /* Compute the scale */
    sum_num = sum_den = 0.0;

    for (i = 0; i < n; i++) {
        v3_t r = v3_sub(right_centroid, right_pts[i]);
        v3_t l = v3_sub(left_centroid, left_pts[i]);
	
	sum_num += v3_magsq(r);
	sum_den += v3_magsq(l);
    }

    scale = sqrt(sum_num / sum_den);

    /* Fill in the matrix M */
    for (i = 0; i < n; i++) {
        v3_t r = v3_sub(right_centroid, right_pts[i]);
        v3_t l = v3_sub(left_centroid, left_pts[i]);

	M[0][0] += Vx(r) * Vx(l);
	M[0][1] += Vx(r) * Vy(l);
	M[0][2] += Vx(r) * Vz(l);

	M[1][0] += Vy(r) * Vx(l);
	M[1][1] += Vy(r) * Vy(l);
	M[1][2] += Vy(r) * Vz(l);

	M[2][0] += Vz(r) * Vx(l);
	M[2][1] += Vz(r) * Vy(l);
	M[2][2] += Vz(r) * Vz(l);
    }

    /* Compute MTM */
    matrix_transpose(3, 3, (double *)M, (double *)MT);
    matrix_product(3, 3, 3, 3, (double *)MT, (double *)M, (double *)MTM);

    /* Calculate Sinv, the inverse of the square root of MTM */
    dgeev_driver(3, (double *)MTM, (double *)evec, eval);

    /* Sort the eigenvalues */
    qsort_descending();
    qsort_perm(3, eval, perm);
    
    memcpy(evec_tmp[0], evec[perm[0]], sizeof(double) * 3);
    memcpy(evec_tmp[1], evec[perm[1]], sizeof(double) * 3);
    memcpy(evec_tmp[2], evec[perm[2]], sizeof(double) * 3);
    memcpy(evec, evec_tmp, sizeof(double) * 9);

    sqrteval_inv[0] = 1.0 / sqrt(eval[0]);
    sqrteval_inv[1] = 1.0 / sqrt(eval[1]);

    if (eval[2] < 1.0e-8 * eval[0]) {
        sqrteval_inv[2] = 0.0;
    } else {
        sqrteval_inv[2] = 1.0 / sqrt(eval[2]);
    }

    Sinv[0][0] = 
        sqrteval_inv[0] * evec[0][0] * evec[0][0] +
        sqrteval_inv[1] * evec[1][0] * evec[1][0] + 
        sqrteval_inv[2] * evec[2][0] * evec[2][0];
    Sinv[0][1] = 
        sqrteval_inv[0] * evec[0][0] * evec[0][1] +
        sqrteval_inv[1] * evec[1][0] * evec[1][1] + 
        sqrteval_inv[2] * evec[2][0] * evec[2][1];
    Sinv[0][2] = 
        sqrteval_inv[0] * evec[0][0] * evec[0][2] +
        sqrteval_inv[1] * evec[1][0] * evec[1][2] + 
        sqrteval_inv[2] * evec[2][0] * evec[2][2];

    Sinv[1][0] = 
        sqrteval_inv[0] * evec[0][1] * evec[0][0] +
        sqrteval_inv[1] * evec[1][1] * evec[1][0] +
        sqrteval_inv[2] * evec[2][1] * evec[2][0];
    Sinv[1][1] = 
        sqrteval_inv[0] * evec[0][1] * evec[0][1] +
        sqrteval_inv[1] * evec[1][1] * evec[1][1] +
        sqrteval_inv[2] * evec[2][1] * evec[2][1];
    Sinv[1][2] = 
        sqrteval_inv[0] * evec[0][1] * evec[0][2] +
        sqrteval_inv[1] * evec[1][1] * evec[1][2] +
        sqrteval_inv[2] * evec[2][1] * evec[2][2];
    
    Sinv[2][0] = 
        sqrteval_inv[0] * evec[0][2] * evec[0][0] +
        sqrteval_inv[1] * evec[1][2] * evec[1][0] +
        sqrteval_inv[2] * evec[2][2] * evec[2][0];
    Sinv[2][1] = 
        sqrteval_inv[0] * evec[0][2] * evec[0][1] +
        sqrteval_inv[1] * evec[1][2] * evec[1][1] +
        sqrteval_inv[2] * evec[2][2] * evec[2][1];
    Sinv[2][2] = 
        sqrteval_inv[0] * evec[0][2] * evec[0][2] +
        sqrteval_inv[1] * evec[1][2] * evec[1][2] +
        sqrteval_inv[2] * evec[2][2] * evec[2][2];

    /* U = M * Sinv */
    matrix_product(3, 3, 3, 3, (double *)M, (double *)Sinv, (double *)U);

    if (eval[2] < 1.0e-8 * eval[0]) {    
        double u3u3[9], Utmp[9];
        matrix_transpose_product2(3, 1, 3, 1, evec[2], evec[2], u3u3);

        matrix_sum(3, 3, 3, 3, (double *) U, u3u3, Utmp);
        
        if (matrix_determinant3(Utmp) < 0.0) {
            printf("[align_horn_3D] Recomputing matrix...\n");
            matrix_diff(3, 3, 3, 3, (double *) U, u3u3, Utmp);
        }

        memcpy(U, Utmp, 9 * sizeof(double));
    }
    
    /* Fill in the rotation matrix */
    R[0]  = U[0][0]; R[1]  = U[0][1]; R[2]  = U[0][2]; R[3]  = 0.0;
    R[4]  = U[1][0]; R[5]  = U[1][1]; R[6]  = U[1][2]; R[7]  = 0.0;
    R[8]  = U[2][0]; R[9]  = U[2][1]; R[10] = U[2][2]; R[11] = 0.0;
    R[12] = 0.0;     R[13] = 0.0;     R[14] = 0.0;     R[15] = 1.0;
    
    /* Fill in the translation matrix */
    matrix_ident(4, T);
    T[3]  = Vx(right_centroid);
    T[7]  = Vy(right_centroid);
    T[11] = Vz(right_centroid);

    if (scale_xform == 0)
	scale = 1.0;

    Tcenter[0][0] = scale;
    Tcenter[1][1] = scale;
    Tcenter[2][2] = scale;
    
    Tcenter[0][3] = -scale * Vx(left_centroid);
    Tcenter[1][3] = -scale * Vy(left_centroid);
    Tcenter[2][3] = -scale * Vz(left_centroid);

    matrix_product(4, 4, 4, 4, T, R, (double *) Ttmp);
    matrix_product(4, 4, 4, 4, (double *)Ttmp, (double *)Tcenter, Tout);

#if 0
    T[2] = Vx(v3_sub(right_centroid, left_centroid));
    T[5] = Vy(v3_sub(right_centroid, left_centroid));
    T[8] = Vz(v3_sub(right_centroid, left_centroid));
#endif

    /* Now compute the RMS error between the points */
    RMS_sum = 0.0;

    for (i = 0; i < n; i++) {
	double left[4] = { Vx(left_pts[i]), 
			   Vy(left_pts[i]), 
			   Vz(left_pts[i]), 1.0 };
	double left_prime[3];
	double dx, dy, dz;

	matrix_product(4, 4, 4, 1, Tout, left, left_prime);

	dx = left_prime[0] - Vx(right_pts[i]);
	dy = left_prime[1] - Vy(right_pts[i]);
	dz = left_prime[2] - Vz(right_pts[i]);

	RMS_sum += dx * dx + dy * dy + dz * dz;
#if 0
        v3_t r = v3_sub(right_centroid, right_pts[i]);
        v3_t l = v3_sub(left_centroid, left_pts[i]);
	v3_t resid;

	/* Rotate, scale l */
	v3_t Rl, SRl;

	Vx(Rl) = R[0] * Vx(l) + R[1] * Vy(l) + R[2] * Vz(l);
	Vy(Rl) = R[3] * Vx(l) + R[4] * Vy(l) + R[5] * Vz(l);
	Vz(Rl) = R[6] * Vx(l) + R[7] * Vy(l) + R[8] * Vz(l);

	SRl = v3_scale(scale, Rl);
	
	resid = v3_sub(r, SRl);
	RMS_sum += v3_magsq(resid);
#endif
    }
    
    return sqrt(RMS_sum / n);
}
コード例 #6
0
ファイル: hsm.c プロジェクト: abachrach/csm
void hsm_match(struct hsm_params*p, hsm_buffer b1, hsm_buffer b2) {
	sm_log_push("hsm_match");
	/* Let's measure the time */
	clock_t hsm_match_start = clock();
	
	assert(b1->num_angular_cells == b2->num_angular_cells);
	assert(p->max_translation > 0);
	assert(b1->linear_cell_size > 0);

	b1->num_valid_results = 0;

	/* Compute cross-correlation of spectra */
	hsm_circular_cross_corr_stupid(b1->num_angular_cells, b2->hs, b1->hs, b1->hs_cross_corr);

	/* Find peaks in cross-correlation */
	int peaks[p->num_angular_hypotheses], npeaks;
	hsm_find_peaks_circ(b1->num_angular_cells, b1->hs_cross_corr, p->angular_hyp_min_distance_deg, 0, p->num_angular_hypotheses, peaks, &npeaks);

	sm_debug("Found %d peaks (max %d) in cross correlation.\n", npeaks, p->num_angular_hypotheses);

	if(npeaks == 0) {
		sm_error("Cross correlation of spectra has 0 peaks.\n");
		sm_log_pop();
		return;
	}

	sm_log_push("loop on theta hypotheses");
	/* lag e' quanto 2 si sposta a destra rispetto a 1 */
	for(int np=0;np<npeaks;np++) {
		int lag = peaks[np];
		double theta_hypothesis = lag * (2*M_PI/b1->num_angular_cells);

		sm_debug("Theta hyp#%d: lag %d, angle %fdeg\n", np, lag, rad2deg(theta_hypothesis));

		/* Superimpose the two spectra */
		double mult[b1->num_angular_cells];
		for(int r=0;r<b1->num_angular_cells;r++)
			mult[r] = b1->hs[r] * b2->hs[pos_mod(r-lag, b1->num_angular_cells)];

		/* Find directions where both are intense */
		int directions[p->xc_ndirections], ndirections;
		hsm_find_peaks_circ(b1->num_angular_cells, b1->hs_cross_corr, p->xc_directions_min_distance_deg, 1, p->xc_ndirections, directions, &ndirections);

		if(ndirections<2) {
			sm_error("Too few directions.\n");
		}
		
		struct {
			/* Direction of cross correlation */
			double angle;
			int nhypotheses;
			struct {
				double delta;
				double value;
			} hypotheses[p->linear_xc_max_npeaks];
		} dirs[ndirections];


		sm_debug("Using %d (max %d) correlations directions.\n", ndirections, p->xc_ndirections);

		int max_lag = (int) ceil(p->max_translation / b1->linear_cell_size);
		int min_lag = -max_lag;
		sm_debug("Max lag: %d cells (max t: %f, cell size: %f)\n",
			max_lag, p->max_translation, b1->linear_cell_size);

		sm_log_push("loop on xc direction");
		/* For each correlation direction */
		for(int cd=0;cd<ndirections;cd++) {

 			dirs[cd].angle =  theta_hypothesis + (directions[cd]) * (2*M_PI/b1->num_angular_cells);

			printf(" cd %d angle = %d deg\n", cd, (int) rad2deg(dirs[cd].angle));

			/* Do correlation */
			int    lags  [2*max_lag + 1];
			double xcorr [2*max_lag + 1];

			int i1 = pos_mod(directions[cd]        , b1->num_angular_cells);
			int i2 = pos_mod(directions[cd] + lag  , b1->num_angular_cells);
			double *f1 = b1->ht[i1];
			double *f2 = b2->ht[i2];

			hsm_linear_cross_corr_stupid(
				b2->num_linear_cells,f2,
				b1->num_linear_cells,f1,
				xcorr, lags, min_lag, max_lag);

			/* Find peaks of cross-correlation */
			int linear_peaks[p->linear_xc_max_npeaks], linear_npeaks;

			hsm_find_peaks_linear(
				2*max_lag + 1, xcorr, p->linear_xc_peaks_min_distance/b1->linear_cell_size,
				p->linear_xc_max_npeaks, linear_peaks, &linear_npeaks);

			sm_debug("theta hyp #%d: Found %d (max %d) peaks for correlation.\n",
				cd, linear_npeaks, p->linear_xc_max_npeaks);

			dirs[cd].nhypotheses = linear_npeaks;
			sm_log_push("Considering each peak of linear xc");
			for(int lp=0;lp<linear_npeaks;lp++) {
				int linear_xc_lag = lags[linear_peaks[lp]];
				double value = xcorr[linear_peaks[lp]];
				double linear_xc_lag_m = linear_xc_lag * b1->linear_cell_size;
				sm_debug("lag: %d  delta: %f  value: %f \n", linear_xc_lag, linear_xc_lag_m, value);
				dirs[cd].hypotheses[lp].delta = linear_xc_lag_m;
				dirs[cd].hypotheses[lp].value = value;
			}
			sm_log_pop();
			
			if(p->debug_true_x_valid) {
				double true_delta = cos(dirs[cd].angle) * p->debug_true_x[0] + 
					sin(dirs[cd].angle) * p->debug_true_x[1];
				sm_debug("true_x    delta = %f \n", true_delta );
			}

		} /* xc direction */
		sm_log_pop();

		sm_debug("Now doing all combinations. How many are there?\n");
		int possible_choices[ndirections];
		int num_combinations = 1;
		for(int cd=0;cd<ndirections;cd++) {
			possible_choices[cd] = dirs[cd].nhypotheses;
			num_combinations *= dirs[cd].nhypotheses;
		}
		sm_debug("Total: %d combinations\n", num_combinations);
		sm_log_push("For each combination..");
		for(int comb=0;comb<num_combinations;comb++) {
			int choices[ndirections];
			hsm_generate_combinations(ndirections, possible_choices, comb, choices);

			/* Linear least squares */
			double M[2][2]={{0,0},{0,0}}; double Z[2]={0,0};
			/* heuristic quality value */
			double sum_values = 0;
			for(int cd=0;cd<ndirections;cd++) {
				double angle = dirs[cd].angle;
				double c = cos(angle), s = sin(angle);
				double w = dirs[cd].hypotheses[choices[cd]].value;
				double y = dirs[cd].hypotheses[choices[cd]].delta;

				M[0][0] += c * c * w;
				M[1][0] += c * s * w;
				M[0][1] += c * s * w;
				M[1][1] += s * s * w;
				Z[0] += w * c * y;
				Z[1] += w * s * y;

				sum_values += w;
			}

			double det = M[0][0]*M[1][1]-M[0][1]*M[1][0];
			double Minv[2][2];
			Minv[0][0] = M[1][1] * (1/det);
			Minv[1][1] = M[0][0] * (1/det);
			Minv[0][1] = -M[0][1] * (1/det);
			Minv[1][0] = -M[1][0] * (1/det);

			double t[2] = {
				Minv[0][0]*Z[0] + Minv[0][1]*Z[1],
				Minv[1][0]*Z[0] + Minv[1][1]*Z[1]};

			/* copy result in results slot */

			int k = b1->num_valid_results;
			b1->results[k][0] = t[0];
			b1->results[k][1] = t[1];
			b1->results[k][2] = theta_hypothesis;
			b1->results_quality[k] = sum_values;
			b1->num_valid_results++;
		}
		sm_log_pop();

	} /* theta hypothesis */
	sm_log_pop();

/*	for(int i=0;i<b1->num_valid_results;i++) {
		printf("#%d %.0fdeg %.1fm %.1fm  quality %f \n",i,
			rad2deg(b1->results[i][2]),
			b1->results[i][0],
			b1->results[i][1],
			b1->results_quality[i]);
	}*/


	/* Sorting based on values */
	int indexes[b1->num_valid_results];
	for(int i=0;i<b1->num_valid_results;i++)
		indexes[i] = i;

	qsort_descending(indexes, (size_t) b1->num_valid_results, b1->results_quality);

	/* copy in the correct order*/
	double*results_tmp[b1->num_valid_results];
	double results_quality_tmp[b1->num_valid_results];
	for(int i=0;i<b1->num_valid_results;i++) {
		results_tmp[i] = b1->results[i];
		results_quality_tmp[i] = b1->results_quality[i];
	}

	for(int i=0;i<b1->num_valid_results;i++) {
		b1->results[i] = results_tmp[indexes[i]];
		b1->results_quality[i] = results_quality_tmp[indexes[i]];
	}

	for(int i=0;i<b1->num_valid_results;i++) {
		char near[256]="";
		double *x = b1->results[i];
		if(p->debug_true_x_valid) {
			double err_th = rad2deg(fabs(angleDiff(p->debug_true_x[2],x[2])));
			double err_m = hypot(p->debug_true_x[0]-x[0],
				p->debug_true_x[1]-x[1]);
			const char * ast = (i == 0) && (err_th > 2) ? "   ***** " : "";
			sprintf(near, "th err %4d  err_m  %5f %s",(int)err_th ,err_m,ast);
		}
		if(i<10)
		printf("after #%d %3.1fm %.1fm %3.0fdeg quality %5.0f \t%s\n",i,
			x[0],
			x[1], rad2deg(x[2]), b1->results_quality[i], near);
	}
	
	
	/* How long did it take? */
	clock_t hsm_match_stop = clock();
	int ticks = hsm_match_stop-hsm_match_start;
	double ctime = ((double)ticks) / CLOCKS_PER_SEC;
	sm_debug("Time: %f sec (%d ticks)\n", ctime, ticks);
	
	sm_log_pop();
}