Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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();
}
Ejemplo n.º 3
0
//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;
}
Ejemplo n.º 5
0
/**
 * @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;
}