#include #include #include #include /* --------------------- constantes ------ */ #define SCREENWIDTH 512 #define SCREENHEIGHT 512 #define NULL 0 #define ERR -1 #define OK 1 #define W_ARESTA 15 #define N_MATCH 400 /* --------------------- estruturas de tipos ------------- */ /* Estrutura das arestas */ struct aresta{ int x_ini, /* coordenada x inicial e */ x_fim; /* final da aresta */ float x_med; /* posicao nominal da aresta */ int pix_ini, /* pixel da esquerda da aresta */ pix_fim; /* pixel da direita */ int valor; /* valor inerente a aresta */ struct aresta *prev, /* aponta para proxima estrutura */ *next; }; /* Estrutura de pontos casados no espaco */ struct depth{ float x, /* coordenadas x, y, z dos pontos */ y, /* casados */ z; float fator; /* fator de casamento */ struct depth *prev, *next; } ; /* --------------------- variaveis globais -------------*/ struct depth *start_depth = NULL, /* inicio e fim da lista */ *end_depth = NULL; /* de profundidade */ unsigned char line_left[SCREENWIDTH], /* buffers para leitura de */ line_right[SCREENWIDTH]; /* linhas das imagens */ /* apontam para o inicio e fim da lista de aresta de cada linha das imagens */ struct aresta *lista_left[SCREENHEIGHT][2], *lista_right[SCREENHEIGHT][2]; FILE *image_left, *image_right; /* apontador para os arquivos das imagens */ char left_image[50], right_image[50]; /* nome das imagens de entrada */ int sizex; /* largura da imagem em pixels */ int sizey; /* altura da imagem em pixels */ int larg_min, maxaresta, disparity, delta; float foco, baseline, alfa, beta; float disparity_inf, disparity_sup; int nmatch; float nmax_match, nmin_match; /* --------------------------- funcao para medida de tempo ------------ */ /* now() - retorna uma medida da hora atual em micro segundos */ double now(void) { struct rusage ru; getrusage(RUSAGE_SELF, &ru); return(((double)ru.ru_utime.tv_sec)*1000000.0 + ((double)ru.ru_utime.tv_usec)); } /* ----------------------------- filtro mediana --------------------------- */ /* ordena um vetor v de tamanho tamf */ void ordena_vetor(v,tamf) int *v; int tamf; { int i, j, a; for(i = 0; i=sizex) continue; f[j] = line_image[ix+j-meio]; } for(j = 0; j < tamf; j++) o[j] = f[j]; ordena_vetor(o,tamf); aux_line[ix] = o[meio]; /* line_image[ix] = o[meio];*/ } for(ix = 0; ix < sizex; ix++) line_image[ix] = aux_line[ix]; } /* ----------------------------- fun_arq ---------------------------- */ /* abre_arq() - Abre arquivos das imagens e le cabecalho de 4 linhas */ void abre_arq(void) { char carac; char s[512]; image_left = fopen(left_image, "r"); image_right = fopen(right_image, "r"); /* leitura e verificacao de cabecalho p/imagem da direita */ fgets(s, 510, image_right); if(strcmp(s, "P5\n") != 0) { fprintf(stdout," Imagem da direita com formato diferente de PGM \n"); exit(1); } carac = getc(image_right); while(carac == '#') { fgets(s, 510,image_right); carac = getc(image_right); } ungetc(carac, image_right); fscanf(image_right,"%d %d\n",&sizex,&sizey); fprintf(stdout,"imagem direita: sizex = %d sizey = %d\n",sizex,sizey); fgets(s, 510, image_right); /* leitura da ultima linha = niveis de cinza */ /* leitura e verificacao de cabecalho p/imagem da esquerda */ fgets(s, 510, image_left); if(strcmp(s, "P5\n") != 0) { fprintf(stdout," Imagem da esquerda com formato diferente de PGM \n"); exit(1); } carac = getc(image_left); while(carac == '#') { fgets(s, 510,image_left); carac = getc(image_left); } ungetc(carac, image_left); /* carac = getc(image_left); if(carac == '#') fgets(s, 510,image_left); else ungetc(carac, image_left); */ fscanf(image_left,"%d %d\n",&sizex,&sizey); fprintf(stdout,"imagem esquerda: sizex = %d sizey = %d\n\n",sizex,sizey); fgets(s, 510, image_left); /* leitura da ultima linha = niveis de cinza */ } /* Inicializa vetor que aponta para listas de degraus */ void inicia_lista(void) { int i; for(i=0 ; i< sizey; i++) { lista_left[i][0] = NULL; lista_left[i][1] = NULL; lista_right[i][0] = NULL; lista_right[i][1] = NULL; } } /* Le linha dos arquivos, filtra-as com filtro da mediana e as escrevem no buffer */ void le_linha(void) { fread(line_left, sizeof(unsigned char), sizex, image_left); filtro_mediana(line_left); fread(line_right, sizeof(unsigned char), sizex, image_right); filtro_mediana(line_right); } /* --------------------------- carreiras ---------------------------- */ /* ins_blk - insere um novo bloco na lista de blocos de arestas */ unsigned char ins_blk(ini_lista, fim_lista) struct aresta **ini_lista, **fim_lista; { struct aresta *ptr, *elemento; ptr = (struct aresta *)malloc(sizeof (struct aresta)); if ( ptr == NULL ) return ( ERR ); if ( *ini_lista == NULL ) { *ini_lista = ptr; *fim_lista = ptr; ptr->next = NULL; ptr->prev = NULL; } else { elemento = *fim_lista; elemento->next = ptr; ptr->prev = elemento; ptr->next = NULL; *fim_lista = ptr; } return ( OK ); } /* valor_aresta() calcula um valor inerente a aresta */ int valor_aresta(x_ini, x_fim, pix_ini, pix_fim) int x_ini, x_fim; int pix_ini, pix_fim; { int valor; valor = abs(pix_fim - pix_ini) * (W_ARESTA - (x_fim - x_ini)); return(valor); } /* Calcula o centro nominal da aresta: */ float centro_aresta(int r, int s, unsigned char line[]) { float pos, pa, pb; /* int i = r + 1; float avg = (((float) line[r]) + ((float)line[s]))/2.0; if (line[r] < line[s]) { while (line[i] <= avg) i++; } else { while (line[i] >= avg) i++; } pa = line[i-1]; pb = line[i]; pos = ((float) (i-1)) + (avg - pa)/(pb - pa); */ pos = ((float)(r+s))/2.0; return (pos); } /* carreira() procura arestas pelo metodo de carreiras */ void carreira() { int pix_fim1, pix_ini2, x_fim1, x_ini2, ix, iy, p1, p2; int larg, /* largura da carreira corrente */ num_carr, /* numero =1 ou 2(para duas carr consecutivas) */ valor; /* valor inerente da aresta */ unsigned char flag; /* flag para teste de contagem de carreira */ int num_aresta; /* Contador do num. de arestas em cada linha */ struct aresta *ptr, *point, *min_point; for(iy=0; iy= larg_min) { if(flag ==1) num_carr++; flag = 0; if(num_carr == 2) /* existe aresta.inserir na lista */ { valor = valor_aresta(x_fim1, x_ini2, pix_fim1, pix_ini2); if(num_aresta >= maxaresta) { min_point = lista_left[iy][0]; point = min_point->next; while(point) { if(point->valor < min_point->valor) min_point = point; point = point->next; } if(min_point->valor < valor) { ptr = min_point; ptr->x_ini = x_fim1; ptr->x_fim = x_ini2; ptr->x_med = centro_aresta(ptr->x_ini, ptr->x_fim, line_left); ptr->pix_ini = pix_fim1; ptr->pix_fim = pix_ini2; ptr->valor = valor; } } else { ins_blk(&lista_left[iy][0], &lista_left[iy][1]); num_aresta++; ptr = lista_left[iy][1]; ptr->x_ini = x_fim1; ptr->x_fim = x_ini2; ptr->x_med = centro_aresta(ptr->x_ini, ptr->x_fim, line_left); ptr->pix_ini = pix_fim1; ptr->pix_fim = pix_ini2; ptr->valor = valor; } num_carr = 1; } } } /* fim codigo de analise da imagem da esquerda */ /* codigo para analise da imagen da direita */ num_aresta = 0; larg = 1; num_carr = 0; flag =1; for(ix=1; ix= larg_min) { if(flag ==1) num_carr++; flag = 0; if(num_carr == 2) /* existe aresta.inserir na lista */ { valor = valor_aresta(x_fim1, x_ini2, pix_fim1, pix_ini2); if(num_aresta >= maxaresta) { min_point = lista_right[iy][0]; point = min_point->next; while(point) { if(point->valor < min_point->valor) min_point = point; point = point->next; } if(min_point->valor < valor) { ptr = min_point; ptr->x_ini = x_fim1; ptr->x_fim = x_ini2; ptr->x_med = centro_aresta(ptr->x_ini, ptr->x_fim, line_right); ptr->pix_ini = pix_fim1; ptr->pix_fim = pix_ini2; ptr->valor = valor; } } else { ins_blk(&lista_right[iy][0], &lista_right[iy][1]); num_aresta++; ptr = lista_right[iy][1]; ptr->x_ini = x_fim1; ptr->x_fim = x_ini2; ptr->x_med = centro_aresta(ptr->x_ini, ptr->x_fim, line_right); ptr->pix_ini = pix_fim1; ptr->pix_fim = pix_ini2; ptr->valor = valor; } num_carr = 1; } } } /* fim codigo de analise da imagem da direita */ } } /* --------------------------- match ---------------------------- */ /* ins_depth - insere um novo bloco na lista de blocos de profundidade */ unsigned char ins_depth(ini_lista, fim_lista) struct depth **ini_lista, **fim_lista; { struct depth *ptr, *elemento; ptr = (struct depth *)malloc(sizeof (struct depth)); if ( ptr == NULL ) return ( ERR ); if ( *ini_lista == NULL ) { *ini_lista = ptr; *fim_lista = ptr; ptr->next = NULL; ptr->prev = NULL; } else { elemento = *fim_lista; elemento->next = ptr; ptr->prev = elemento; ptr->next = NULL; *fim_lista = ptr; } return ( OK ); } /* funcao para o calculo do max e minimo entre modulos de diferencas */ void min_max(pixl1, pixl2, pixr1, pixr2, min, max) int pixl1,pixl2, pixr1,pixr2; /* pixels das imagens esq e dir */ int *min, *max; /* valores retornados */ { int dif1, dif2; dif1 = abs(pixl1 - pixr1); dif2 = abs(pixl2 - pixr2); if(dif1 >= dif2) { *min = dif2; *max = dif1; } else { *min = dif1; *max = dif2; } /*fputs(" passou por mim_max",stderr);*/ } /* f_normaliza calcula x, y, z normalizados */ void f_normaliza(xl, xr, yl, yr, x, y, z) float xl, xr, yl, yr; float *x, *y, *z; { *x = (xl + xr)/2.0; *z = (xl - xr)/2.0; *y = yr/1.414214; /* sqrt(2) */ } /* f_depth() ----!!!!!VERIFICAR CALCULOS DAS COORDENADAS funcao para calculo das coordenadas X, Y, Z de um pto a partir das coordenadas X,Y de imagens estereoscopicas */ void f_depth(xl, xr, yl, yr, x, y, z) float xl, xr, yl, yr; float *x, *y, *z; { if((xl - xr) >= 0) { *x = (baseline/2)*(xl + xr - (sizex-1))/(xl - xr); *z = foco * baseline /(xl - xr); *y = (baseline/2)*(yr + yl)/(xl - xr); } /*fputs(" passou por depth",stderr);*/ } /* escalonar() funcao para mapear ptos em diferentes escalas. Mapeia variacoes de x0 a x1 em variacoes de h0 a h1. */ float escalonar(x, x0, x1, h0, h1) float x, x0, x1, h0, h1; { float h; /* h e' funcao de x */ h = x*(h1 - h0)/(x1 - x0) + (h0*x1 - h1*x0)/(x1 -x0); /* fputs(" passou por escalonar",stderr);*/ return(h); } /* rotina para escolher entre nmin e nmax melhores dentre nin dados. os dados estao no vetor value em ordem crescente de valores. voce quer os nmax menores valores retorna indice do ultimo valor nao incluido*/ int n_melhor(int nmin, int nmax, float value[]) { int nout; nout = nmin; if (nmin > 1) { float avggap = (value[nmin-1]-value[0])/((float)nmin); float lastgap = value[nmin-1]-value[nmin-2]; float tiegap = (lastgap < avggap ? lastgap : avggap); while( (nout < nmax) && ((value[nout]-value[nout-1]) <= tiegap) ) nout++; } return(nout); } /* funcao para ordenar em ordem crescente um vetor de valores e um respectivo vetor de inteiros */ void sort(int n, float value[], int elem[]) { int p, q, r, mx; float cc, vmax; int ccelem; /* 1. Build heap with largest element at value[0] */ for (p = 0; p 0) { q = (r-1) / 2; if (value[q] < cc) { value[r] = value[q]; elem[r] = elem[q]; } else break; r = q; } value[r] = cc; elem[r] = ccelem; } /* 2. Remove elements from heap and insert at end */ for (p = n-1; p > 0; p--) { /* save value[p] */ cc = value[p]; ccelem = elem[p]; /* Move largest heap element to povalue[p] */ value[p] = value[0]; elem[p] = elem[0]; /* Insert cc in remaining heap, from root down */ q = 0; while(1) { value[q] = cc; elem[q] = ccelem; r = 2*q+1; /* Find largest among cc, value[LEFT(q)], value[RIGHT(q)] */ mx = q; vmax = cc; if ((rvmax)) { mx = r; vmax = value[r]; } r++; if((rvmax)) { mx = r; vmax = value[r]; } /* See who won */ if (mx==q) break; /* Promote child and advance */ value[q] = value[mx]; elem[q] = elem[mx]; q = mx; } } } /* funcao de casamento de ptos correspondentes */ void match() { int iy, i, kmatch; int min, max; /* max e min entre pixels */ int num_match; /* numero de casamentos correntes por linha */ float x_left, /* coordenadas das arestas das imagens */ x_right, /* em */ y_left; /* pixels. */ /* y_right = y_left */ float x3d, y3d, z3d; /* coordenadas no espaco calculadas por depth() */ float fator; /* fator de casamento */ float matriz_depth[N_MATCH][4]; /* matriz com os dados do casamento [][0] = xl [][1] = xr [][2] = y = yr = yl [][3] = fator de casamento */ float vetor_fator[N_MATCH]; /* vetor aux para ordenacao dos fatores */ int vetor_index[N_MATCH]; /* vetor indice dos fatores ordenados */ struct aresta *ptr_left, *ptr_right; struct depth *max_ptr, *ptr; for(iy=0; iyx_med; x_right = ptr_right->x_med; /* ------- restricao da epipolar line */ if(x_left <= (x_right + disparity_inf)) { ptr_right = ptr_right->next; continue; } if(x_left >= (x_right + disparity_sup)) { ptr_right = ptr_right->next; continue; } /* --------------------- */ /* restricao da epipolar line utlizada if(x_left <= x_right + disparity) { ptr_right = ptr_right->next; continue; } */ min_max(ptr_left->pix_ini, ptr_left->pix_fim, ptr_right->pix_ini, ptr_right->pix_fim, &min, &max); fator = alfa * min + beta * max; matriz_depth[num_match][0] = x_left; matriz_depth[num_match][1] = x_right; matriz_depth[num_match][2] = y_left; matriz_depth[num_match][3] = fator; vetor_fator[num_match] = fator; vetor_index[num_match] = num_match; /* -- if(iy==210) { fprintf(stderr,"%d %d %f ", (int)x_left, (int)x_right,fator); } if(iy==210) { fprintf(stderr,"%d %d %d %d %d %d\n", ptr_left->pix_ini, ptr_left->pix_fim, ptr_right->pix_ini, ptr_right->pix_fim,min,max); } ---*/ /* if(iy==240) { fprintf(stderr,"%d %d %d %d \n", ptr_left->pix_ini, ptr_left->pix_fim, ptr_right->pix_ini, ptr_right->pix_fim); fprintf(stderr,"%d %d %.4f\n",min,max,fator); } */ num_match++; ptr_right = ptr_right->next; } ptr_left = ptr_left->next; } if(num_match == 0) continue; sort(num_match, vetor_fator, vetor_index); { int nleft = 0; int nright = 0; int nmaxlr, nmax, nmin; struct aresta *p; p = lista_right[iy][0]; while(p) { nright++; p = p->next; } p = lista_left[iy][0]; while(p) { nleft++; p = p->next; } nmaxlr = (nleft > nright ? nleft : nright); nmax = (int)(nmax_match * (float) nmaxlr) + 1; if(num_match < nmax) nmax = num_match; nmin = (int)(nmin_match * (float)nmaxlr) +1; if (nmin > nmax) nmin = nmax; kmatch = n_melhor(nmin, nmax, vetor_fator); /* -- fprintf(stderr, "linha %d: nleft = %d nright = %d num_match = %d nmin = %d nmax = %d kmatch = %d\n", iy, nleft, nright, num_match, nmin, nmax, kmatch ); ---- */ } for(i=0; ifator = fator; /* --ESTA ERRADO ---*/ ptr->x = x3d; ptr->y = y3d; ptr->z = z3d; } } /*fputs(" passou por match",stderr);*/ } void main(argc, argv) int argc; char *argv[]; { char parametros[50], saida[50], saida_degraus_l[50], saida_degraus_r[50], saida_casa_2d[50], saida_casa_3d[50], saida_casa_iso[50]; char aux[100]; double start, stop; /* para medida de tempo de execucao */ FILE *arq_parametros; float zmax, zmin; strcpy(right_image, argv[1]); strcat(right_image, "_r.pgm"); strcpy(left_image, argv[1]); strcat(left_image, "_l.pgm"); strcpy(parametros, argv[2]); strcat(parametros, ".parms"); /* ENTRADA DE DADOS */ if((arq_parametros = fopen(parametros, "r")) == NULL) { fprintf(stderr,"\n ---- Arquivo de parametros nao pode ser aberto -EXIT\n"); exit(1); } fgets(aux, 98, arq_parametros); /* leitura do cabecalho */ fgets(aux, 98, arq_parametros); /* leitura de duas linhas do arquivo de */ fgets(aux, 98, arq_parametros); /* entrada que e usada apenas em tese-seg */ fscanf(arq_parametros,"foco = %f\n",&foco); fscanf(arq_parametros,"baseline = %f\n",&baseline); fscanf(arq_parametros,"delta = %d\n",&delta); fscanf(arq_parametros,"larg_min = %d\n",&larg_min); fscanf(arq_parametros,"maxaresta = %d\n",&maxaresta); fscanf(arq_parametros,"alfa = %f\n",&alfa); fscanf(arq_parametros,"beta = %f\n",&beta); fscanf(arq_parametros,"disparity = %d\n",&disparity); fscanf(arq_parametros,"nmax_match = %f\n",&nmax_match); fprintf(stderr," TESTE cod. ( %s )\n",saida); /* --- ---*/ fprintf(stderr,"zmin = "); scanf("%f",&zmin); fprintf(stderr,"\nzmax = "); scanf("%f",&zmax); disparity_inf = foco*baseline/zmax; disparity_sup = foco*baseline/zmin; fprintf(stderr,"\ndisp_inf = %f\n",disparity_inf); fprintf(stderr,"disp_sup = %f\n",disparity_sup); fprintf(stderr,"\n nmin_match = "); scanf("%f",&nmin_match); /* preparacao dos nomes dos arquivos de saidas */ strcpy(saida, argv[1]); strcat(saida, "-"); strcat(saida, argv[2]); strcpy(saida_degraus_l, saida); strcpy(saida_degraus_r, saida); strcpy(saida_casa_2d, saida); strcpy(saida_casa_3d, saida); strcpy(saida_casa_iso, saida); strcat(saida_degraus_l, "_l.degraus"); strcat(saida_degraus_r, "_r.degraus"); strcat(saida_casa_2d, "_2d.casa"); strcat(saida_casa_3d, "_3d.casa"); strcat(saida_casa_iso, "_iso.casa"); nmatch = maxaresta * maxaresta; if(nmatch>N_MATCH) { fprintf(stdout," ****---- nmatch > NMATCH -----******\n"); fprintf(stdout," Programa abortado em match\n"); exit(1); } inicia_lista(); abre_arq(); start = now(); carreira(); stop = now(); fprintf(stdout,"ARESTA - Total time (ms) = %.0f\n",(stop -start)/1000.0); fclose(image_left); fclose(image_right); start = now(); match(); stop = now(); fprintf(stdout,"MATCH - Total time (ms) = %.0f\n",(stop -start)/1000.0); fprintf(stdout,"\n\n\n -----------------***********------------\n\n\n"); /* saida para arquivos de degraus e casamento */ { FILE *degraus_l, /* arquivo da degraus da esquerda */ *degraus_r, /* arquivo da degraus da direita */ *casa_2d, /* arquivo de casamentos reais em 2d */ *casa_3d; /* arquivo de casamentos reais em 3d */ FILE *casa_iso; /* aponta para arquivo de saida com pontos em 3d isometricos */ struct aresta *ptr; struct depth *point; int i, x, nptos; float const_cord_x; float const_cord_y; float x3d, y3d, z3d; /* coordenadas em 3d do range-map */ int x2d, y2d; const_cord_x = ((float)sizex-1.0)/2.0; const_cord_y = ((float)sizey-1.0)/2.0; degraus_l = fopen(saida_degraus_l, "w"); if(degraus_l == NULL) { fputs(" Erro ao criar arquivo aresta_l. \n",stdout); fputs(" ********* Programa abortado ******\n",stdout); exit(1); } degraus_r = fopen(saida_degraus_r, "w"); if(degraus_r == NULL) { fputs(" Erro ao criar arquivo aresta_r. \n",stdout); fputs(" ********* Programa abortado ******\n",stdout); exit(1); } casa_2d = fopen(saida_casa_2d, "w"); if(casa_2d == NULL) { fputs(" Erro ao criar arquivo casa-2d. \n",stdout); fputs(" ********* Programa abortado ******\n",stdout); exit(1); } casa_3d = fopen(saida_casa_3d, "w"); if(casa_3d == NULL) { fputs(" Erro ao criar arquivo casa-3d. \n",stdout); fputs(" ********* Programa abortado ******\n",stdout); exit(1); } casa_iso = fopen(saida_casa_iso, "w"); if(casa_iso == NULL) { fputs(" Erro ao criar arquivo casa-iso. \n",stdout); fputs(" ********* Programa abortado ******\n",stdout); exit(1); } for(i=0; ix_med + 0.5); fprintf(degraus_l,"%d %d\n",x,i); ptr = ptr->next; } ptr = lista_right[i][0]; while( ptr ) { x = (int)(ptr->x_med + 0.5); fprintf(degraus_r,"%d %d\n",x,i); ptr = ptr->next; } } nptos = 0; point = start_depth; while( point ) { nptos++; point = point->next; } /* escrita em arquivo de saida em coordenadas isotropicas */ fprintf(casa_iso,"%d\n",nptos); point = start_depth; while( point ) { x3d = point->x; y3d = point->y; z3d = point->z; fprintf(casa_iso,"%f %f %f\n",x3d,y3d,z3d); point = point->next; } /* --- escrita em arquivo de saida em coordenadas reais 3D ---*/ fprintf(casa_3d,"nptos = %d\n",nptos); fprintf(casa_3d,"foco = %f\n",foco); point = start_depth; while( point ) { x3d = baseline * (point->x - const_cord_x)/(2.0*point->z); y3d = baseline * (point->y*1.414214 - const_cord_y)/(2.0*point->z); z3d = foco*baseline/(2.0*point->z); fprintf(casa_3d,"%f %f %f\n",x3d,y3d,z3d); point = point->next; } /* escrita do casamento em coordenadas reais projetadas em 2D*/ /* fprintf(casa_2d,"%d\n",nptos);*/ point = start_depth; while( point ) { x3d = baseline * (point->x - const_cord_x)/(2.0*point->z); y3d = baseline * (point->y*1.414214 - const_cord_y)/(2.0*point->z); z3d = foco*baseline/(2.0*point->z); x2d =(int) (foco * x3d/z3d + const_cord_x); y2d =(int) (foco * y3d/z3d + const_cord_y); fprintf(casa_2d,"%5d %5d\n",x2d,y2d); point = point->next; } /* imprimir parametros lidos do stdout */ fprintf(stdout," TESTE cod. ( %s )\n",saida); fprintf(stdout,"delta = %d\n",delta); fprintf(stdout,"larg_min = %d\n",larg_min); fprintf(stdout,"maxaresta = %d\n",maxaresta); fprintf(stdout,"alfa = %f\n",alfa); fprintf(stdout,"beta = %f\n",beta); fprintf(stdout,"foco = %f\n",foco); fprintf(stdout,"baseline = %f\n",baseline); fprintf(stdout,"disparity = %d\n",disparity); fprintf(stdout,"nmax_match = %f\n",nmax_match); fprintf(stdout,"\nNptos casados = %d\n",nptos); } }