void read_images(DistortedLines<T>& distLines, int& w, int& h, int argc, char ** argv, int beginIdx, int endIdx) { int w_tmp = 0, h_tmp = 0; ntuple_ll point_set,p; image_double image; int length_thresh; double down_factor, x, y; int total_nb_lines, total_threshed_nb_lines, threshed_nb_lines; ntuple_list convolved_pts; /* check parameters */ if( argc < 4 ) error("use: %s length_threshold sampling_factor <input1.pgm> [input2.pgm...] <polyout_filename>", argv[0]); assert(beginIdx >= 3 && beginIdx < argc-1 && endIdx >= 3 && endIdx < argc-1); length_thresh = (int)(atoi(argv[1])); down_factor = (double)(atoi(argv[2])); printf("There are %d input images. The minimal length of lines is set to %d\n", endIdx+1-beginIdx, length_thresh); /* initialize memory */ point_set = new_ntuple_ll(1); total_nb_lines = 0; total_threshed_nb_lines = 0; /* process each of the input images */ for(int i = beginIdx; i <= endIdx; i++) { threshed_nb_lines = 0; /* open image, compute edge points, close it */ image = read_pgm_image_double(argv[i]); p = straight_edge_points(image,sigma,th_low,th_hi,min_length); w = image->xsize; h = image->ysize; if (i == beginIdx) {w_tmp = w; h_tmp = h;} else { assert(w == w_tmp && h == h_tmp); } free_image_double(image); /* copy the points set in the new image to the global set of points */ for(int j=0; j<(int)p->size; j++) { if((int)p->list[j]->size > length_thresh) { add_ntuple_list(point_set, p->list[j]); p->list[j] = 0; } else threshed_nb_lines += 1; } printf("For image %d, there are totally %d lines detected and %d of them are eliminated.\n", i-2, p->size, threshed_nb_lines); total_nb_lines += p->size; total_threshed_nb_lines += threshed_nb_lines; free_ntuple_ll(p); } distLines.pushMemGroup((int)point_set->size); int countL = 0; for(unsigned int i=0; i<point_set->size; i++) { /* Gaussian convolution and sub-sampling */ convolved_pts = gaussian_convol_on_curve(unit_sigma, Nsigma, resampling, eliminate_border, up_factor, down_factor, point_set->list[i]); countL++; /* Save points to DistortionLines structure */ for(unsigned int j = 0; j < convolved_pts->size; j++) { x = convolved_pts->values[j*convolved_pts->dim]; y = convolved_pts->values[j*convolved_pts->dim+1]; distLines.pushPoint(countL-1,x,y); } } printf("Totally there are %d lines detected and %d of them are eliminated.\n", total_nb_lines, total_threshed_nb_lines); /* free memory */ free_ntuple_ll(point_set); free_ntuple_list(convolved_pts); }
int main(int argc, char **argv) { if (argc < 2 || argc > 2) { std::cout << "Usage: lsd_opencv_example imageName" << std::endl; return; } cv::Mat src = cv::imread(argv[1], CV_LOAD_IMAGE_COLOR); cv::Mat tmp, src_gray; cv::cvtColor(src, tmp, CV_RGB2GRAY); tmp.convertTo(src_gray, CV_64FC1); int cols = src_gray.cols; int rows = src_gray.rows; image_double image = new_image_double(cols, rows); image->data = src_gray.ptr<double>(0); ntuple_list ntl = lsd(image); cv::Mat lsd = cv::Mat::zeros(rows, cols, CV_8UC1); cv::Point pt1, pt2; for (int j = 0; j != ntl->size ; ++j) { pt1.x = ntl->values[0 + j * ntl->dim]; pt1.y = ntl->values[1 + j * ntl->dim]; pt2.x = ntl->values[2 + j * ntl->dim]; pt2.y = ntl->values[3 + j * ntl->dim]; double width = ntl->values[4 + j * ntl->dim]; cv::line(lsd, pt1, pt2, cv::Scalar(255), width, CV_AA); } free_ntuple_list(ntl); cv::namedWindow("src", CV_WINDOW_AUTOSIZE); cv::imshow("src", src); cv::namedWindow("lsd", CV_WINDOW_AUTOSIZE); cv::imshow("lsd", lsd); cv::waitKey(0); cv::destroyAllWindows(); }
//static image_float gaussian_sampler( float* in, int width,int height, int d, float scale, //float sigma_scale ) image_float gaussian_sampler( image_float in, float scale, float sigma_scale ) { image_float aux,out; ntuple_list kernel; unsigned int N,M,h,n,x,y,i; int xc,yc,j,float_x_size,float_y_size; float sigma,xx,yy,sum,prec; /* compute new image size and get memory for images */ if( in->xsize * scale > (float) UINT_MAX || in->ysize * scale > (float) UINT_MAX ) error("gaussian_sampler: the output image size exceeds the handled size."); N = (unsigned int) ceil( in->xsize * scale ); M = (unsigned int) ceil( in->ysize * scale ); aux = new_image_float(N,in->ysize); out = new_image_float(N,M); /* sigma, kernel size and memory for the kernel */ sigma = scale < 1.0 ? sigma_scale / scale : sigma_scale; /*Como para ingresar a este codigo scale <1 (se evalua en la funcion LineSegmentDetection), siempre se va a cumplir que sigma = sigma_scale / scale */ /* The size of the kernel is selected to guarantee that the the first discarded term is at least 10^prec times smaller than the central value. For that, h should be larger than x, with e^(-x^2/2sigma^2) = 1/10^prec. Then, x = sigma * sqrt( 2 * prec * ln(10) ). */ prec = 3.0; h = (unsigned int) ceil( sigma * sqrt( 2.0 * prec * log(10.0) ) ); /*La funcion log() corresponde al logaritmo neperiano*/ n = 1+2*h; /* kernel size */ kernel = new_ntuple_list(n); /* auxiliary float image size variables */ float_x_size = (int) (2 * in->xsize); float_y_size = (int) (2 * in->ysize); gaussian_kernel( kernel, sigma, (float) h ); float scale_inv=1/scale; /* First subsampling: x axis */ for(x=3;x<aux->xsize-2;x++) { /* x is the coordinate in the new image. xx is the corresponding x-value in the original size image. xc is the integer value, the pixel coordinate of xx. */ xx = (float) x * scale_inv; /*Esto es para recorrer toda la imagen porque aux-> size = width*scale*/ /* coordinate (0.0,0.0) is in the center of pixel (0,0), so the pixel with xc=0 get the values of xx from -0.5 to 0.5 */ xc = (int) floor( xx + 0.5 ); /*Aca redondeamos el valor. Seria lo mismo que hacer round(xx)*/ // gaussian_kernel( kernel, sigma, (float) h + xx - (float) xc ); /* the kernel must be computed for each x because the fine offset xx-xc is different in each case */ for(y=0;y<aux->ysize;y++) { sum = 0.0; for(i=0;i<kernel->dim;i++) { j = xc - h + i; sum += in->data[ j + y * in->xsize ] * kernel->values[i]; } aux->data[ x + y * aux->xsize ] = sum; } } /* Second subsampling: y axis */ for(y=3;y<out->ysize-2;y++) { /* y is the coordinate in the new image. yy is the corresponding x-value in the original size image. yc is the integer value, the pixel coordinate of xx. */ yy = (float) y * scale_inv; /* coordinate (0.0,0.0) is in the center of pixel (0,0), so the pixel with yc=0 get the values of yy from -0.5 to 0.5 */ yc = (int) floor( yy + 0.5 ); //gaussian_kernel( kernel, sigma, (float) h + yy - (float) yc ); /* the kernel must be computed for each y because the fine offset yy-yc is different in each case */ for(x=0;x<out->xsize;x++) { sum = 0.0; for(i=0;i<kernel->dim;i++) { j = yc - h + i; sum += aux->data[ x + j * aux->xsize ] * kernel->values[i]; } out->data[ x + y * out->xsize ] = sum; } } /* free memory */ free_ntuple_list(kernel); free_image_float(aux); return out; }
/*--------------------------------------------------------------------------*/ ntuple_list gaussian_convol_on_curve(double unit_sigma, double Nsigma, bool resampling, bool eliminate_border, double up_factor, double down_factor, ntuple_list orig_edges) { double x1, y1, x2, y2, sumx, sumy, d, norm, w; int j, k; double line_length, sample_step = 0.0; ntuple_list upsampled_edges, convolved_upsampled_edges, each_seg_length, output_pts; each_seg_length = new_ntuple_list(1); double residual_d = 0.0, lambda; int low_bound, high_bound; int size_lambda, begin_lambda; double small_seg_x, small_seg_y; double sigma; int flag, nb_sigma, not_border_flag; double real_down_factor; unsigned int nb_pts; nb_pts = orig_edges->size; upsampled_edges = new_ntuple_list(2); /*length of the whole line*/ line_length = 0.0; /*the total length of the line and the lenth of each segment*/ for(j = 0; j < (int)nb_pts-1; j++) { x1 = orig_edges->values[j*orig_edges->dim + 0]; y1 = orig_edges->values[j*orig_edges->dim + 1]; x2 = orig_edges->values[(j+1)*orig_edges->dim + 0]; y2 = orig_edges->values[(j+1)*orig_edges->dim + 1]; d = dist(x1, y1, x2, y2); add_1tuple(each_seg_length, d); line_length += d; } /*the average distance between two points for a line (original line)*/ sample_step = line_length / (nb_pts-1); if (resampling) { /*TANG: the edge points are not regularly sampled, so first do an interpolation to get regularly sampled points*/ if (up_factor < 1.0) error("up_factor must be greater than 1!\n"); /*the line is upsampled, the average distance becomes smaller*/ sample_step /= up_factor; /* Resampling */ for(j = 0; j < (int)nb_pts-1; j++) { flag = 0; x1 = orig_edges->values[j*orig_edges->dim + 0]; y1 = orig_edges->values[j*orig_edges->dim + 1]; x2 = orig_edges->values[(j+1)*orig_edges->dim + 0]; y2 = orig_edges->values[(j+1)*orig_edges->dim + 1]; if (j == 0) residual_d = 0.0; size_lambda = (int)floor((each_seg_length->values[j]+residual_d)/sample_step); begin_lambda = 0; if (j != 0) begin_lambda = 1; for(k = begin_lambda; k <= size_lambda; k++) { lambda = (-residual_d + k*sample_step) / each_seg_length->values[j]; small_seg_x = (1-lambda)*x1 + lambda*x2; small_seg_y = (1-lambda)*y1 + lambda*y2; add_2tuple(upsampled_edges, small_seg_x, small_seg_y); flag = 1; } if(flag == 1) residual_d = dist(x2, y2, small_seg_x, small_seg_y); else residual_d += each_seg_length->values[j]; } } else /* no resampling, copy 'orig_edges' to 'upsampled_edges' */ copy_ntuple(orig_edges, upsampled_edges); /* convolution */ convolved_upsampled_edges = new_ntuple_list(2); for(j=0; j<(int)upsampled_edges->size; j++) { norm = 0.0; sumx = 0.0; sumy = 0.0; sigma = unit_sigma * sqrt(down_factor*down_factor - 1.0); nb_sigma = (int)floor( Nsigma * sigma / sample_step ); low_bound = j - nb_sigma; if(low_bound < 0) low_bound = 0; high_bound = j + nb_sigma; if(high_bound > (int)upsampled_edges->size-1) high_bound = upsampled_edges->size-1; if(eliminate_border) { if(high_bound - low_bound == 2*nb_sigma) not_border_flag = 1; else not_border_flag = 0; } else not_border_flag = 1; if(not_border_flag == 1) { for (k = low_bound; k <= high_bound; k++) { /*x1 = upsampled_edges->list[i]->values[upsampled_edges->list[i]->dim*j]; y1 = upsampled_edges->list[i]->values[upsampled_edges->list[i]->dim*j+1]; x2 = upsampled_edges->list[i]->values[upsampled_edges->list[i]->dim*k]; y2 = upsampled_edges->list[i]->values[upsampled_edges->list[i]->dim*k+1]; d = dist(x1, y1, x2, y2);*/ x2 = upsampled_edges->values[upsampled_edges->dim*k]; y2 = upsampled_edges->values[upsampled_edges->dim*k+1]; d = sample_step * (k-j); w = exp( -d*d / 2.0 / sigma / sigma ); sumx += w*x2; sumy += w*y2; norm += w; } sumx /= norm; sumy /= norm; add_2tuple(convolved_upsampled_edges, sumx, sumy); } } /* if resampling is enabled */ /* output_pts = new_ntuple_list(2); if(resampling) { real_down_factor = (int)(down_factor * up_factor); nb = convolved_upsampled_edges->size / real_down_factor + 1; for(j = 0; j < nb; j++) add_2tuple(output_pts, convolved_upsampled_edges->values[j*real_down_factor*convolved_upsampled_edges->dim], convolved_upsampled_edges->values[j*real_down_factor*convolved_upsampled_edges->dim+1]); } else copy_ntuple(upsampled_edges, output_pts); */ output_pts = new_ntuple_list(2); if(resampling) real_down_factor = down_factor * up_factor; else real_down_factor = down_factor; /* nb = (int)((double)convolved_upsampled_edges->size / real_down_factor); for(j = 0; j < nb; j++) add_2tuple(output_pts, convolved_upsampled_edges->values[(int)(j*real_down_factor*convolved_upsampled_edges->dim)], convolved_upsampled_edges->values[(int)(j*real_down_factor*convolved_upsampled_edges->dim)+1]); */ j = 0; while(j < (int)convolved_upsampled_edges->size) { add_2tuple(output_pts, convolved_upsampled_edges->values[(int)(j*convolved_upsampled_edges->dim)], convolved_upsampled_edges->values[(int)(j*convolved_upsampled_edges->dim)+1]); j = floor(j + real_down_factor); } free_ntuple_list(upsampled_edges); free_ntuple_list(convolved_upsampled_edges); free_ntuple_list(each_seg_length); return output_pts; }
/** * @brief Coarse detection of the pattern by using segments detected from LSD * @param in - input image float * @return Array of floats containing the OPQR 2D point positions of the * pattern */ static float *detect_pattern_coarse(ImageFloat in) { image_double in_lsd; ntuple_list seg; float min_val, max_val; double *seg_length, *seg_midpoint_x, *seg_midpoint_y; char is_in_distance; double xO, xP, xQ, xR, yO, yQ, yP, yR, l; int *has_seg, *has_all_seg, point; /* To keep track of the error from the optimal segment position * just to choose the closest segment to the optimal location */ double seg_error[NUM_SEG]; double xi1, xi2, yi1, yi2, xj1, xj2, yj1, yj2, xjN1, xjN2, yjN1, yjN2; double xoMp, xpMq, xqMr, xrMo, yoMp, ypMq, yqMr, yrMo; double xC, yC; /* Structure of the Pattern Seg0,Seg1,...,Seg10,Seg_Orient0,Seg_Orient1 */ const double x1S[] = { 3, 6, 7, 7, 7, 6, 3, 0, -2, -2, -2, 1, 8 }; const double y1S[] = { 0, 0, -1, -4, -7, -9, -9, -9, -7, -4, -1, 1, 0 }; const double x2S[] = { 3, 6, 8, 8, 8, 6, 3, 0, -1, -1, -1, 1, 7 }; const double y2S[] = { 1, 1, -1, -4, -7, -8, -8, -8, -7, -4, -1, 0, 0 }; int i = 0, j = 0, k = 0, c = 0; double errorc; double actual_scale; char ready; float *opqr = (float *) malloc(8 * sizeof(float)); /* Execute LSD */ /* Convert between images types and renormalize the image to [0,255]*/ min_val = BIG_NUMBER; max_val = 0; for (i=0; i< in->ncol *in->nrow;i++) { if(in->val[i] < min_val) min_val = in->val[i]; if(in->val[i] > max_val) max_val = in->val[i]; } in_lsd = new_image_double((unsigned int) in->ncol, (unsigned int) in->nrow); for (i = 0; i < in->ncol * in->nrow; i++) in_lsd->data[i] = (double) 255/(max_val-min_val)*(in->val[i]-min_val); /* We do a LOOP from INITIAL_SCALE_LSD to MAX_SCALE_LSD */ actual_scale = INITIAL_SCALE_LSD; ready = 0; while (actual_scale < MAX_SCALE_LSD && !ready) { printf(" -->LSD scale =%f\n",actual_scale); seg = lsd_scale(in_lsd, actual_scale); /* allocate the array or exit with an error */ if ((seg_length = (double *) malloc(seg->size * sizeof(double))) == NULL || (seg_midpoint_x = (double *) malloc(seg->size * sizeof(double))) == NULL || (seg_midpoint_y = (double *) malloc(seg->size * sizeof(double))) == NULL) { error("PSF_ESTIM - Unable to allocate double array space"); exit(EXIT_FAILURE); } /* The i component, of the n-tuple number j, of an n-tuple list 'ntl' is accessed with: */ for (i = 0; i < (int) seg->size; i++) { /* segment length */ seg_length[i] = dist_l2(seg->values[i * seg->dim], seg->values[i * seg->dim + 1], seg->values[i * seg->dim + 2], seg->values[i * seg->dim + 3]); /* segment midpoint */ seg_midpoint_x[i] = 0.5 * (seg->values[i * seg->dim] + seg->values[i * seg->dim + 2]); seg_midpoint_y[i] = 0.5 * (seg->values[i * seg->dim + 1] + seg->values[i * seg->dim + 3]); } /* Accessing to segment j=0...12 associated to segment i * has_seg[NUM_SEG*i+j], initialization default to 0 */ if ((has_seg = (int *) malloc(NUM_SEG * seg->size * sizeof(int))) == NULL || (has_all_seg = (int *) malloc(seg->size * sizeof(int))) == NULL) { error("PSF_ESTIM - Unable to allocate double array space"); exit(EXIT_FAILURE); } /* has_seg[], Initialization default to -1 */ for (i = 0; i < NUM_SEG * (int) seg->size; i++) { has_seg[i] = -1; } /* has_all_seg[], Initialization default to 0 */ /* First pass */ for (i = 0; i < (int) seg->size; i++) { xi1 = seg->values[i * seg->dim]; xi2 = seg->values[i * seg->dim + 2]; yi1 = seg->values[i * seg->dim + 1]; yi2 = seg->values[i * seg->dim + 3]; /* Reinitialize the error track */ for (j = 0; j < NUM_SEG; j++) { seg_error[j] = BIG_NUMBER; } for (j = 0; j < (int) seg->size; j++) { xj1 = seg->values[j * seg->dim]; xj2 = seg->values[j * seg->dim + 2]; yj1 = seg->values[j * seg->dim + 1]; yj2 = seg->values[j * seg->dim + 3]; /* Convert the (x,y) coordinates to a new Coordinate System * (xN, yN) having: * (xi1,yi1) at (0,0) * (xi2,yi2) at (0,1) * The vectors x1s,y1s,x2s,y2s are given within this * new (xN,yN) coordinate system */ l = seg_length[i]; xjN1 = 1 / (l * l) * ((yi2 - yi1) * (xj1 - xi1) - (xi2 - xi1) * (yj1 - yi1)); yjN1 = 1 / (l * l) * ((xi2 - xi1) * (xj1 - xi1) + (yi2 - yi1) * (yj1 - yi1)); xjN2 = 1 / (l * l) * ((yi2 - yi1) * (xj2 - xi1) - (xi2 - xi1) * (yj2 - yi1)); yjN2 = 1 / (l * l) * ((xi2 - xi1) * (xj2 - xi1) + (yi2 - yi1) * (yj2 - yi1)); for (c = 0; c < NUM_SEG; c++) { is_in_distance = (fabs(xjN1 - x1S[c]) < TOL * (2 + fabs(x1S[c]))) && (fabs(yjN1 - y1S[c]) < TOL * (2 + fabs(y1S[c]))) && (fabs(xjN2 - x2S[c]) < TOL * (2 + fabs(x2S[c]))) && (fabs(yjN2 - y2S[c]) < TOL * (2 + fabs(y2S[c]))); if (is_in_distance) { /* Need to check that there isn't a previous segment * closer to the optimal location and already marked * as good (errorc). I just keep the segment with * minimum total error l1. */ errorc = fabs(xjN1 - x1S[c]) + fabs(yjN1 - y1S[c]) + fabs(xjN2 - x2S[c]) + fabs(yjN2 - y2S[c]); if (errorc < seg_error[c]) { has_seg[i * NUM_SEG + c] = j; seg_error[c] = errorc; } } } } /*has_all_seg[i] will be one if all segments are present */ has_all_seg[i] = 1; for (j=0;j< NUM_SEG;j++) { has_all_seg[i] = has_all_seg[i] && (has_seg[i * NUM_SEG + j] >= 0); } if (has_all_seg[i]) { point = i; k++; } } ready = (k==1); actual_scale *= 1.15; } if (k > 1) { printf("More than one pattern was detected."); printf("\nCrop the image surounding the desired pattern and re-run."); exit(EXIT_SEVERAL_PATTERNS_DETECTED); } else if(k<1) { printf("No pattern was detected. Use another image"); exit(EXIT_NO_PATTERN_DETECTED); } /*Calculate C - center, u = unit_length, theta = angle */ /* 1/3*(DET + 0 + 1) = oMp */ xoMp = 0.33333 * (seg_midpoint_x[point] + seg_midpoint_x[has_seg[point * NUM_SEG + 0]] + seg_midpoint_x[has_seg[point * NUM_SEG + 1]]); yoMp = 0.33333 * (seg_midpoint_y[point] + seg_midpoint_y[has_seg[point * NUM_SEG + 0]] + seg_midpoint_y[has_seg[point * NUM_SEG + 1]]); /* 1/3*(2 + 3 + 4) = pMq */ xpMq = 0.33333 * (seg_midpoint_x[has_seg[point * NUM_SEG + 2]] + seg_midpoint_x[has_seg[point * NUM_SEG + 3]] + seg_midpoint_x[has_seg[point * NUM_SEG + 4]]); ypMq = 0.33333 * (seg_midpoint_y[has_seg[point * NUM_SEG + 2]] + seg_midpoint_y[has_seg[point * NUM_SEG + 3]] + seg_midpoint_y[has_seg[point * NUM_SEG + 4]]); /* 1/3*(5 + 6 + 7) = qMr */ xqMr = 0.33333 * (seg_midpoint_x[has_seg[point * NUM_SEG + 5]] + seg_midpoint_x[has_seg[point * NUM_SEG + 6]] + seg_midpoint_x[has_seg[point * NUM_SEG + 7]]); yqMr = 0.33333 * (seg_midpoint_y[has_seg[point * NUM_SEG + 5]] + seg_midpoint_y[has_seg[point * NUM_SEG + 6]] + seg_midpoint_y[has_seg[point * NUM_SEG + 7]]); /* 1/3*(8 + 9 + 10) = rMo */ xrMo = 0.33333 * (seg_midpoint_x[has_seg[point * NUM_SEG + 8]] + seg_midpoint_x[has_seg[point * NUM_SEG + 9]] + seg_midpoint_x[has_seg[point * NUM_SEG + 10]]); yrMo = 0.33333 * (seg_midpoint_y[has_seg[point * NUM_SEG + 8]] + seg_midpoint_y[has_seg[point * NUM_SEG + 9]] + seg_midpoint_y[has_seg[point * NUM_SEG + 10]]); /*Center */ xC = 0.25 * (xoMp + xpMq + xqMr + xrMo); yC = 0.25 * (yoMp + ypMq + yqMr + yrMo); /*O = C + CoMr + CoMp */ xO = xC + (xrMo - xC) + (xoMp - xC); yO = yC + (yrMo - yC) + (yoMp - yC); /*P = C + CpMq + CoMp */ xP = xC + (xpMq - xC) + (xoMp - xC); yP = yC + (ypMq - yC) + (yoMp - yC); /*Q = C + CqMr + CpMq */ xQ = xC + (xqMr - xC) + (xpMq - xC); yQ = yC + (yqMr - yC) + (ypMq - yC); /*R = C + CrMo + CqMr */ xR = xC + (xrMo - xC) + (xqMr - xC); yR = yC + (yrMo - yC) + (yqMr - yC); /*Array of OPQR coordinates*/ opqr[0] = (float) xO; opqr[1] = (float) yO; opqr[2] = (float) xP; opqr[3] = (float) yP; opqr[4] = (float) xQ; opqr[5] = (float) yQ; opqr[6] = (float) xR; opqr[7] = (float) yR; /* free memory */ free_image_double(in_lsd); free_ntuple_list(seg); free(seg_length); free(seg_midpoint_y); free(seg_midpoint_x); free(has_seg); free(has_all_seg); return opqr; }