Пример #1
0
CImgList<uint8_t>* ph_getKeyFramesFromVideo(const char *filename){

    long N =  GetNumberVideoFrames(filename);

    if (N < 0){
        return NULL;
    }

    float frames_per_sec = 0.5*fps(filename);
    if (frames_per_sec < 0){
        return NULL;
    }

    int step = (int)(frames_per_sec + ROUNDING_FACTOR(frames_per_sec));
    long nbframes = (long)(N/step);

    float *dist = (float*)malloc((nbframes)*sizeof(float));
    if (!dist){
        return NULL;
    }
    CImg<float> prev(64,1,1,1,0);

    VFInfo st_info;
    st_info.filename = filename;
    st_info.nb_retrieval = 100;
    st_info.step = step;
    st_info.pixelformat = 0;
    st_info.pFormatCtx = NULL;
    st_info.width = -1;
    st_info.height = -1;

    CImgList<uint8_t> *pframelist = new CImgList<uint8_t>();
    if (!pframelist){
        return NULL;
    }
    int nbread = 0;
    int k=0;
    do {
        nbread = NextFrames(&st_info, pframelist);
        if (nbread < 0){
            delete pframelist;
            free(dist);
            return NULL;
        }
        unsigned int i = 0;
        while ((i < pframelist->size()) && (k < nbframes)){
            CImg<uint8_t> current = pframelist->at(i++);
            CImg<float> hist = current.get_histogram(64,0,255);
            float d = 0.0;
            dist[k] = 0.0;
            cimg_forX(hist,X){
                d =  hist(X) - prev(X);
                d = (d>=0) ? d : -d;
                dist[k] += d;
                prev(X) = hist(X);
            }
            k++;
        }
        pframelist->clear();
    } while ((nbread >= st_info.nb_retrieval)&&(k < nbframes));
Пример #2
0
int main(int argc, char *argv[]) {
    //@ Leer filtro, aplicar filtro, convolve con filtro de distinta medida. Filtra segun un umbral

    const char* _input = cimg_option("-i", "../images/hubble.tif", "Input Image File");
    const char* _filter = cimg_option("-m", "filtro_ej3.txt", "Input filter File");
    const unsigned int _lado = cimg_option("-l", 5, "Input filter File");
    const unsigned int _umbral = cimg_option("-u", 150, "Input filter File");

    CImg<unsigned char> img(_input), output, output_grises(img.width(), img.height(), 1 , 1 , 0), 
                            img_binaria(img.width(), img.height(), 1 , 1 , 0);

    //Creamos el filtro de promediado
    utils::genArchivoMascara(_filter, _lado, _lado);
    CImg<double> filtro = utils::get_filtro(_filter);

    //Convolucionamos
    output = img.get_convolve(filtro);

    //Binarizamos la imagen a partir del umbral definido
    cimg_forXY(output, x , y) {
        if (output(x,y) > _umbral ) {
            img_binaria(x,y) = 255;
            output_grises(x,y) = img(x,y);
        }
    }

    //Dibujamos
    CImgList<double> lista;
    lista.assign(img, output, img_binaria, output_grises );
    lista.display();
}
Пример #3
0
void inciso3() {
    
    unsigned int w = 256;
    unsigned int h = 256;

    CImg<double> linea_vertical = lineaVertical(w,h,w/2).get_normalize(0,255);
    CImg<double> linea_horizontal = lineaHorizontal(w,h,h/2).get_normalize(0,255);
    CImg<double> cuadrado = rectCentrado(w,h,w/40,h/4).get_normalize(0,255);
    CImg<double> rectangulo = rectCentrado(w,h,w/2,h/10).get_normalize(0,255);
    CImg<double> circulo = circuloCentrado(w,0).get_normalize(0,255);

    CImgList<double> lista;
    lista.assign(linea_vertical,linea_horizontal,cuadrado,rectangulo,circulo);
    lista.display();

  //CImgList<double> f_linea_vertical = linea_vertical.get_FFT();
  //CImgList<double> f_linea_horizontal = linea_horizontal.get_FFT();
  //CImgList<double> f_cuadrado = cuadrado.get_FFT();
  //CImgList<double> f_rectangulo = rectangulo.get_FFT();
  //CImgList<double> f_circulo = circulo.get_FFT();

    CImg<double> fm_linea_vertical = magn_tdf(linea_vertical, true); 
    CImg<double> fm_linea_horizontal = magn_tdf(linea_horizontal, true); 
    CImg<double> fm_cuadrado = magn_tdf(cuadrado, true); 
    CImg<double> fm_rectangulo = magn_tdf(rectangulo, true); 
    CImg<double> fm_circulo = magn_tdf(circulo, true); 

    CImgList<double> lista_fft;
    lista_fft.assign(fm_linea_vertical,  fm_linea_horizontal, fm_cuadrado, fm_rectangulo, fm_circulo);
    lista_fft.display();
}
int main() {
 
  //Reading the image 
  const CImg<double> img = CImg<double>("marilyn1.png").resize(256,256).save("original.png");

  //Applying fourier transform. Referenced it frm CImg.h. 
  //Returns list in 0 and 1 column. We assummed the values in 0 column are magnitude and 1 column are phase
  CImgList<double> F = img.get_FFT();

  //FFT Shift. Referenced from CImg.h
  cimglist_apply(F,shift)(img.width()/2,img.height()/2,0,0,2);
  
  complex<double> H[256][256];   //Complex double array for saving Gaussian mask

  double D0,D;
  double B[65536];   //65536 is the total number pixels available in the image
  double S[65536];  

 //Calculating the gaussian mask. Magnitude and the Phase values are saved in seperate arrays.
 //Referenced from Online source. The mask is for low pass filter.
  int i = 0;
  for ( int u = 0; u < img.width() ; u++){
    for ( int v = 0; v < img.height() ; v++){
      D0 = 15;
      D = sqrt(pow((double)u - ((double)img.width()/2),2) + pow((double)v - ((double)img.height()/2),2));
      H[u][v] =  exp(complex<double>(0.0,-(double)((double)pow(D, 2)/ (double)(2* pow(D0,2)))));
      B[i] = std::abs(H[u][v]);
      S[i] = std::arg(H[u][v]); 
      i++;

       }
   }

 printf("%d",i); 
//Multiplying the Magnitude of Gaussian Mask with Magnitude of FFT result
 for (int z=0; z< i; z++)
 {
  F[0][z] = (F[0][z]*B[i]); 
 }  
  
//Taking Inverse FFT of the Result
  CImgList<double> FT = F.get_FFT(true);

  const CImg<double> mag = ((FT[0].get_pow(2) + FT[1].get_pow(2)).sqrt() + 1).log().normalize(0,255);

  CImgList<double> visu(img,mag);
  mag.save("fftimage.png");
  
}
Пример #5
0
int main( int argc, char **argv ) {
    const char *filename = cimg_option( "-f",
                                        "../../imagenes/estanbul.tif",
                                         "ruta archivo imagen" );
    int umbral = cimg_option( "-u", 127, "umbral" );

    CImgDisplay disp, disp2, disp3, disp4, disp5, disp6, disp7, disp8;
    
    CImg<double> img ( filename ), gx, gy, gxy, gyx;
    img.channel(0);
    img.display(disp);

    gx = img.get_convolve( masks::sobel_gx() );

    gy = img.get_convolve( masks::sobel_gy() );

    gxy = img.get_convolve( masks::sobel_gxy() );

    gyx = img.get_convolve( masks::sobel_gyx() );

    CImgList<double> list ( gx, gy, gxy ,gyx );
    list.display(disp3);
    disp3.set_title("deteccion de bordes: sobel gx - gy - gxy - gyx");

    (gx+gy+gxy+gyx).normalize(0,255).display(disp4);
    disp4.set_title("deteccion de bordes: sobel gx + gy + gxy + gyx");

    CImgList<double> list2 ( gx.get_normalize(0,255).get_threshold( umbral ),
                             gy.get_normalize(0,255).get_threshold( umbral ),
                             gxy.get_normalize(0,255).get_threshold( umbral ),
                             gyx.get_normalize(0,255).get_threshold( umbral ) );

    list2.display(disp7);
    disp7.set_title("sobel umbral: gx - gy - gxy - gyx");

    CImgList<double> list3 ( masks::sobel_gx().resize(100,100),
                             masks::sobel_gy().resize(100,100),
                             masks::sobel_gxy().resize(100,100),
                             masks::sobel_gyx().resize(100,100) );
    list3.display(disp8);
    disp8.set_title("masks sobel: gx - gy - gxy - gyx");

    
    while ( (!disp.is_closed() &&  !disp.is_keyQ()) ) {
        disp.wait_all();
    }
    return 0;
}
Пример #6
0
void insert_fiber(const CImg<T>& fiber, const CImg<te>& eigen, const CImg<tc>& palette,
                  const int xm, const int ym, const int zm,
                  const float vx, const float vy, const float vz,
                  CImgList<tp>& points, CImgList<tf>& primitives, CImgList<tc>& colors) {
  const int N0 = points.size();
  float x0 = fiber(0,0), y0 = fiber(0,1), z0 = fiber(0,2), fa0 = eigen.linear_atXYZ(x0,y0,z0,12);
  points.insert(CImg<>::vector(vx*(x0  -xm),vy*(y0 - ym),vz*(z0 - zm)));
  for (int l = 1; l<fiber.width(); ++l) {
    float x1 = fiber(l,0), y1 = fiber(l,1), z1 = fiber(l,2), fa1 = eigen.linear_atXYZ(x1,y1,z1,12);
    points.insert(CImg<tp>::vector(vx*(x1 - xm),vy*(y1 - ym),vz*(z1 - zm)));
    primitives.insert(CImg<tf>::vector(N0 + l - 1,N0 + l));
    const unsigned char
      icol = (unsigned char)(fa0*255),
      r = palette(icol,0),
      g = palette(icol,1),
      b = palette(icol,2);
    colors.insert(CImg<unsigned char>::vector(r,g,b));
    x0 = x1; y0 = y1; z0 = z1; fa0 = fa1;
  }
}
void insert_ellipsoid(const CImg<t>& tensor,const float X,const float Y,const float Z,const float tfact,
                      const float vx, const float vy, const float vz,
                      CImgList<tp>& points, CImgList<tf>& faces, CImgList<tc>& colors,
                      const unsigned int res1 = 20, const unsigned int res2 = 20) {

  // Compute eigen elements
  const float l1 = tensor[0], l2 = tensor[1], l3 = tensor[2], fa = get_FA(l1,l2,l3);

  CImg<> vec = CImg<>::matrix(tensor[3],tensor[6],tensor[9],
                              tensor[4],tensor[7],tensor[10],
                              tensor[5],tensor[8],tensor[11]);
  const int
    r = (int)cimg::min(30+1.5f*cimg::abs(255*fa*tensor[3]),255.0f),
    g = (int)cimg::min(30+1.5f*cimg::abs(255*fa*tensor[4]),255.0f),
    b = (int)cimg::min(30+1.5f*cimg::abs(255*fa*tensor[5]),255.0f);

  // Define mesh points
  const unsigned int N0 = points.size;
  for (unsigned int v=1; v<res2; v++)
    for (unsigned int u=0; u<res1; u++) {
      const float
        alpha = (float)(u*2*cimg::valuePI/res1),
        beta = (float)(-cimg::valuePI/2 + v*cimg::valuePI/res2),
        x = (float)(tfact*l1*std::cos(beta)*std::cos(alpha)),
        y = (float)(tfact*l2*std::cos(beta)*std::sin(alpha)),
        z = (float)(tfact*l3*std::sin(beta));
      points.insert((CImg<tp>::vector(X,Y,Z)+vec*CImg<tp>::vector(x,y,z)).mul(CImg<tp>::vector(vx,vy,vz)));
    }
  const unsigned int N1 = points.size;
  points.insert((CImg<tp>::vector(X,Y,Z)+vec*CImg<tp>::vector(0,0,-l3*tfact)));
  points.insert((CImg<tp>::vector(X,Y,Z)+vec*CImg<tp>::vector(0,0,l3*tfact)));
  points[points.size-2](0)*=vx; points[points.size-2](1)*=vy;  points[points.size-2](2)*=vz;
  points[points.size-1](0)*=vx; points[points.size-1](1)*=vy;  points[points.size-1](2)*=vz;

  // Define mesh triangles
  for (unsigned int vv=0; vv<res2-2; vv++)
    for (unsigned int uu=0; uu<res1; uu++) {
      const int nv = (vv+1)%(res2-1), nu = (uu+1)%res1;
      faces.insert(CImg<tf>::vector(N0+res1*vv+nu,N0+res1*nv+uu,N0+res1*vv+uu));
      faces.insert(CImg<tf>::vector(N0+res1*vv+nu,N0+res1*nv+nu,N0+res1*nv+uu));
      colors.insert(CImg<tc>::vector(r,g,b));
      colors.insert(CImg<tc>::vector(r,g,b));
    }
  for (unsigned int uu=0; uu<res1; uu++) {
    const int nu = (uu+1)%res1;
    faces.insert(CImg<tf>::vector(N0+nu,N0+uu,N1));
    faces.insert(CImg<tf>::vector(N0+res1*(res2-2)+nu, N1+1,N0+res1*(res2-2)+uu));
    colors.insert(CImg<tc>::vector(r,g,b));
    colors.insert(CImg<tc>::vector(r,g,b));
  }
}
Пример #8
0
void inciso4() {
    unsigned int w = 512;
    unsigned int h = 512;

    CImg<double> linea = lineaVertical(w,h,w/2).get_normalize(0,255);
    CImg<double> rotada = linea.get_rotate(20);

    CImg<double> c_linea = linea.get_crop(w/4,h/4,3*w/4, 3*h/4);
    CImg<double> c_rotada = rotada.get_crop(w/4+100,h/4,3*w/4+100, 3*h/4);

    CImgList<double> lista;
    lista.assign(linea,rotada,c_linea,c_rotada);
    lista.display();

    CImg<double> fm_linea = magn_tdf(c_linea, true); 
    CImg<double> fm_rotada = magn_tdf(c_rotada, true); 

    CImgList<double> lista_fft;
    lista_fft.assign(fm_linea, fm_rotada);
    lista_fft.display();

}
Пример #9
0
int main(int argc, char *argv[]) {
    //@ Leer filtro, aplicar filtro, convolve con filtro de distinta medida

    const char* _input = cimg_option("-i", "../images/cameraman.tif", "Input Image File");
    const char* _filter = cimg_option("-m", "filtro_examen_m1.txt", "Input filter File");
    const char* _filter2 = cimg_option("-s", "filtro_examen_m2.txt", "Input filter File");

    CImg<double> img(_input), m1, m2;
    
    CImg<double> filtro = get_filtro(_filter);
    CImg<double> filtro2 = get_filtro(_filter2);


    m1 = img.get_convolve(filtro);
    m2 = m1.get_convolve(filtro2);

    CImgList<unsigned char> lista;
    lista.assign(img, m1, m2);
    lista.display();

   
}
Пример #10
0
//@ Aplica el operador derivada segun el parametro opcion
//0: Gradiente de Roberts
//1: Gradiente de Prewitt
//2: Gradiente de Sobel
//3: Laplaciano de 4 vecinos
//4: Laplaciano de 8 vecinos
//5: LoG, Laplaciano del Gaussiano
//Devuelve una lista con todos los resultados de aplicar todas las mascaras del operador en particular
CImgList<double> aplicarDerivada(CImg<double> img, unsigned int opcion = 0) {
    CImgList<double> derivada;
    if (opcion == 0) 
        derivada = operadorRoberts();
    if (opcion == 1) 
        derivada = operadorPrewitt();
    if (opcion == 2) 
        derivada = operadorSobel();
    if (opcion == 3)
        derivada = operadorLaplaciano4();
    if (opcion == 4)
        derivada = operadorLaplaciano8();
    if (opcion == 5)
        derivada = operadorLoG();

    CImgList<double> resultados;
    unsigned int cantidad = derivada.size();
    for (unsigned int i = 0; i < cantidad; i++) {
        resultados.push_back(img.get_convolve(derivada[i]));
    }
     
    return resultados;
}
Пример #11
0
int main(int argc, char *argv[]) {

  if ( !argv[1] ){
    printf( "%s: Convoluciona la imagen con un kernel de 3x3.\n", argv[0] );
    printf( "uso: %s <archivo_imagen>\n", argv[0] );
    return 1;
  }

  CImg<double> kernel ( 3,3,1,1,1);

  kernel(0,0)=0; kernel(1,0)=1; kernel(2,0)=2;
  kernel(0,1)=1; kernel(1,1)=2; kernel(2,1)=1;
  kernel(0,2)=2; kernel(1,2)=1; kernel(2,2)=0;

  CImg<double> imagen( argv[1] );

  CImgList<double> result ( imagen.get_normalize(0,255),
			    kernel.get_normalize(0,255),
			    imagen.get_convolve( kernel ).get_normalize(0,255) );

  result.display();
  
  return 0;
}
Пример #12
0
//@ Toma una lista de imagenes y le aplica el umbral especificado a cada imagen
CImgList<bool> umbralizarLista(CImgList<double> l_img, double umbral) {
    CImgList<bool> ret_val;
    //Recorre la lista
    for (unsigned int i = 0; i < l_img.size(); i++) {
        //Temporal a pushear
        CImg<bool> tempy(l_img[i].width(), l_img[i].height(), l_img[i].depth(), l_img[i].spectrum(), false);
        //Recorre la imagen
        cimg_forXY(l_img[i],x,y) {
            if (fabs(l_img[i](x,y)) > umbral) {
                tempy(x,y) = true;
            }
        }
        ret_val.push_back(tempy);
    }
    return ret_val;
}
Пример #13
0
int main(int argc, char *argv[]) {
    //@ Compara el resultado de ecualizar una imagen a partir de cada canal RGB y la intensidad de HSI

    const char* _input = cimg_option("-i", "../images/futbol.jpg", "Input Image File");


    //Declaramos imagenes a trabajar
    CImg<double> input(_input), output(input.width(), input.height(), input.depth(), 3 , 0) ;

    (input.get_RGBtoHSI().get_channel(0), input.get_RGBtoHSI().get_channel(1)).display();


    CImg<double> recorte = input.get_crop(132,105,203,230);
    // recorte.display();

    // CImg<unsigned char> histograma_r = recorte.get_channel(0).get_histogram(256, 0, 255);
    // CImg<unsigned char> histograma_g = recorte.get_channel(1).get_histogram(256, 0, 255);
    // CImg<unsigned char> histograma_b = recorte.get_channel(2).get_histogram(256, 0, 255);
    // histograma_r.display_graph("",3);
    // histograma_g.display_graph("",3);
    // histograma_b.display_graph("",3);


    CImg<bool> mascara_binaria(input.width(), input.height());

    CImg<double> c1 = input.get_channel(0);
    CImg<double> c2 = input.get_channel(1);
    CImg<double> c3 = input.get_channel(2);
    
    cimg_forXY(input, x , y) {
        if (dentro_circulo(c1(x,y), 40, 20) &&  //rojo
            dentro_circulo(c2(x,y), 85, 10) &&  //verde
            dentro_circulo(c3(x,y), 150, 105)) { //azul

            mascara_binaria(x,y) = true;
            
            output(x,y,0,0) = input(x,y,0,0);
            output(x,y,0,1) = input(x,y,0,1);
            output(x,y,0,2) = input(x,y,0,2);
        } else {
            mascara_binaria(x,y) = false;
        }
    }

        // //Display! 
    CImgList<double> lista;

    lista.assign(input, mascara_binaria.normalize(0,255) , output );
    lista.display();

    // CImg<double> output_RGB(_input);
    // CImg<double> output_HSI(_input);

    // CImg<double> filtro = get_filtro(_filtro);

    //     //Temporales necesarios
    // CImg<double> c1, c2, c3;
    
    // //Ecualización de la RGB
    //     //Obtenemos los canales
    // c1 = output_RGB.get_channel(0);
    // c2 = output_RGB.get_channel(1);
    // c3 = output_RGB.get_channel(2);
    //     //Los ecualizamos
    // c1.convolve(filtro);
    // c2.convolve(filtro);
    // c3.convolve(filtro);
    //     //Recomponemos la imágen
    // c1.append(c2, 'c');
    // c1.append(c3, 'c');
    // output_RGB = c1;


    // //Ecualizamos la imagen HSI
    // output_HSI.RGBtoHSI();
    //       //Obtenemos los canales
    // c1 = output_HSI.get_channel(0);
    // c2 = output_HSI.get_channel(1);
    // c3 = output_HSI.get_channel(2);
    //     //Ecualizo el canal de Intensidad solamente
    // c3.convolve(filtro);
    //     //Recomponemos la imágen
    // c1.append(c2, 'c');
    // c1.append(c3, 'c');
    // output_HSI = c1;
    // output_HSI.HSItoRGB();






    // return 0;
}
Пример #14
0
// Main procedure
//----------------
int main(int argc,char **argv) {

  // Read command line arguments.
  cimg_usage("Render an image as a surface");
  const char *file_i    = cimg_option("-i",cimg_imagepath "logo.bmp","Input image");
  const char *file_o    = cimg_option("-o",(char*)0,"Output 3D object");
  const float sigma     = cimg_option("-smooth",1.0f,"Amount of image smoothing");
  const float ratioz    = cimg_option("-z",0.25f,"Aspect ratio along z-axis");
  const unsigned int di = cimg_option("-di",10,"Step for isophote skipping");

  // Load 2D image file.
  std::fprintf(stderr,"\n- Load file '%s'",cimg::basename(file_i)); std::fflush(stderr);
  const CImg<unsigned char>
    img  = CImg<>(file_i).blur(sigma).resize(-100,-100,1,3),
    norm = img.get_norm().normalize(0,255);

  // Compute surface with triangles.
  std::fprintf(stderr,"\n- Create image surface"); std::fflush(stderr);
  CImgList<unsigned int> primitives;
  CImgList<unsigned char> colors;
  const CImg<> points = img.get_elevation3d(primitives,colors,norm*-ratioz);

  // Compute image isophotes.
  std::fprintf(stderr,"\n- Compute image isophotes"); std::fflush(stderr);
  CImgList<unsigned int> isoprimitives;
  CImgList<unsigned char> isocolors;
  CImg<> isopoints;
  for (unsigned int i = 0; i<255; i+=di) {
    CImgList<> prims;
    const CImg<> pts = norm.get_isoline3d(prims,(float)i);
    isopoints.append_object3d(isoprimitives,pts,prims);
  }
  cimglist_for(isoprimitives,l) {
    const unsigned int i0 = isoprimitives(l,0);
    const float x0 = isopoints(i0,0), y0 = isopoints(i0,1);
    const unsigned char
      r = (unsigned char)img.linear_atXY(x0,y0,0),
      g = (unsigned char)img.linear_atXY(x0,y0,1),
      b = (unsigned char)img.linear_atXY(x0,y0,2);
    isocolors.insert(CImg<unsigned char>::vector(r,g,b));
  }
  cimg_forX(isopoints,ll) isopoints(ll,2) = -ratioz*norm.linear_atXY(isopoints(ll,0),isopoints(ll,1));

  // Save object if necessary
  if (file_o) {
    std::fprintf(stderr,"\n- Save 3d object as '%s'",cimg::basename(file_o)); std::fflush(stderr);
    points.save_off(primitives,colors,file_o);
  }

  // Enter event loop
  std::fprintf(stderr,
               "\n- Enter interactive loop.\n\n"
               "Reminder : \n"
               " + Use mouse to rotate and zoom object\n"
               " + key 'F'          : Toggle fullscreen\n"
               " + key 'Q' or 'ESC' : Quit\n"
               " + Any other key    : Change rendering type\n\n"); std::fflush(stderr);
  const char *const title = "Image viewed as a surface";
  CImgDisplay disp(800,600,title,0);
  unsigned int rtype = 2;
  CImg<float> pose = CImg<float>::identity_matrix(4);

  while (!disp.is_closed()) {
    const unsigned char white[3]={ 255, 255, 255 };
    CImg<unsigned char> visu(disp.width(),disp.height(),1,3,0);
    visu.draw_text(10,10,"%s",white,0,1,24,
                rtype==0?"Points":(rtype==1?"Lines":(rtype==2?"Faces":(rtype==3?"Flat-shaded faces":
               (rtype==4?"Gouraud-shaded faces":(rtype==5?"Phong-shaded faces":"Isophotes"))))));
    static bool first_time = true;
    if (rtype==6) visu.display_object3d(disp,isopoints,isoprimitives,isocolors,first_time,1,-1,true,
                                        500.0f,0.0f,0.0f,-5000.0f,0.0f,0.0f,true,pose.data());
    else visu.display_object3d(disp,points,primitives,colors,first_time,rtype,-1,true,
                               500.0f,0.0f,0.0f,-5000.0f,0.0f,0.0f,true,pose.data());
    first_time = false;
    switch (disp.key()) {
    case 0: break;
    case cimg::keyBACKSPACE: rtype = (7 + rtype - 1)%7; break;
    case cimg::keyQ:
    case cimg::keyESC: disp.close(); break;
    case cimg::keyF:
      if (disp.is_fullscreen()) disp.resize(800,600); else disp.resize(disp.screen_width(),disp.screen_height());
      disp.toggle_fullscreen();
      break;
    default: rtype = (rtype + 1)%7; break;
    }
  }

  return 0;
}
Пример #15
0
//' Display image list using CImg library
//'
//' @param imlist a list of cimg objects
//' @export
// [[Rcpp::export]]
void display_list(List imlist)
{
   CImgList<double> L = sharedCImgList(imlist);
   L.display();
   return;
}
Пример #16
0
// Main procedure
//----------------
int main (int argc, char **argv) {

  cimg_usage("Compute the skeleton of a shape, using Hamilton-Jacobi equations");

  // Read command line arguments
  cimg_help("Input/Output options\n"
            "--------------------");
  const char* file_i = cimg_option("-i",cimg_imagepath "milla.bmp","Input (black&white) image");
  const int median = cimg_option("-median",0,"Apply median filter");
  const bool invert = cimg_option("-inv",false,"Invert image values");
  const char* file_o = cimg_option("-o",(char*)0,"Output skeleton image");
  const bool display = cimg_option("-visu",true,"Display results");

  cimg_help("Skeleton computation parameters\n"
            "-------------------------------");
  const float thresh = cimg_option("-t",-0.3f,"Threshold");
  const bool curve = cimg_option("-curve",false,"Create medial curve");

  cimg_help("Torsello correction parameters\n"
            "------------------------------");
  const bool correction = cimg_option("-corr",false,"Torsello correction");
  const float dlt1 = 2;
  const float dlt2 = cimg_option("-dlt",1.0f,"Discrete step");

  // Load the image (forcing it to be scalar with 2 values { 0,1 }).
  CImg<unsigned int> image0(file_i), image = image0.get_norm().quantize(2).normalize(0.0f,1.0f);
  if (median) image.blur_median(median);
  if (invert) (image-=1)*=-1;
  if (display) (image0.get_normalize(0,255),image.get_normalize(0,255)).display("Input image - Binary image");

  // Compute distance map.
  CImgList<float> visu;
  CImg<float> distance = image.get_distance(0);
  if (display) visu.insert(distance);

  // Compute the gradient of the distance function, and the flux (divergence) of the gradient field.
  const CImgList<float> grad = distance.get_gradient("xyz");
  CImg<float> flux = image.get_flux(grad,1,1);
  if (display) visu.insert(flux);

  // Use the Torsello correction of the flux if necessary.
  if (correction) {
    CImg<float>
      logdensity = image.get_logdensity(distance,grad,flux,dlt1),
      nflux = image.get_corrected_flux(logdensity,grad,flux,dlt2);
    if (display) visu.insert(logdensity).insert(nflux);
    flux = nflux;
  }

  if (visu) {
    cimglist_apply(visu,normalize)(0,255);
    visu.display(visu.size()==2?"Distance function - Flux":"Distance function - Flux - Log-density - Corrected flux");
  }

  // Compute the skeleton
  const CImg<unsigned int> skel = image.get_skeleton(flux,distance,curve,thresh);
  if (display) {
    (image0.resize(-100,-100,1,3)*=0.7f).get_shared_channel(1)|=skel*255.0;
    image0.draw_image(0,0,0,0,image*255.0,0.5f).display("Image + Skeleton");
  }

  // Save output image if necessary.
  if (file_o) skel.save(file_o);

  return 0;
}
Пример #17
0
CImg<> get_fibertrack(CImg<T>& eigen,
                      const int X0, const int Y0, const int Z0, const float lmax=100,
                      const float dl=0.1f, const float FAmin=0.7f, const float cmin=0.5f) {
#define align_eigen(i,j,k) \
  { T &u = eigen(i,j,k,3), &v = eigen(i,j,k,4), &w = eigen(i,j,k,5); \
    if (u*cu + v*cv + w*cw<0) { u=-u; v=-v; w=-w; }}

  CImgList<> resf;

  // Forward tracking
  float normU = 0, normpU = 0, l = 0, X = (float)X0, Y = (float)Y0, Z = (float)Z0;
  T
    pu = eigen(X0,Y0,Z0,3),
    pv = eigen(X0,Y0,Z0,4),
    pw = eigen(X0,Y0,Z0,5);
  normpU = (float)std::sqrt(pu*pu + pv*pv + pw*pw);
  bool stopflag = false;

  while (!stopflag) {
    if (X<0 || X>eigen.width() - 1 || Y<0 || Y>eigen.height() - 1 || Z<0 || Z>eigen.depth() - 1 ||
        eigen((int)X,(int)Y,(int)Z,12)<FAmin || l>lmax) stopflag = true;
    else {
      resf.insert(CImg<>::vector(X,Y,Z));

      const int
        cx = (int)X, px = (cx - 1<0)?0:cx - 1, nx = (cx + 1>=eigen.width())?eigen.width() - 1:cx + 1,
        cy = (int)Y, py = (cy - 1<0)?0:cy - 1, ny = (cy + 1>=eigen.height())?eigen.height() - 1:cy + 1,
        cz = (int)Z, pz = (cz - 1<0)?0:cz - 1, nz = (cz + 1>=eigen.depth())?eigen.depth() - 1:cz + 1;
      const T cu = eigen(cx,cy,cz,3), cv = eigen(cx,cy,cz,4), cw = eigen(cx,cy,cz,5);

      align_eigen(px,py,pz); align_eigen(cx,py,pz); align_eigen(nx,py,pz);
      align_eigen(px,cy,pz); align_eigen(cx,cy,pz); align_eigen(nx,cy,pz);
      align_eigen(px,ny,pz); align_eigen(cx,ny,pz); align_eigen(nx,ny,pz);
      align_eigen(px,py,cz); align_eigen(cx,py,cz); align_eigen(nx,py,cz);
      align_eigen(px,cy,cz);                        align_eigen(nx,cy,cz);
      align_eigen(px,ny,cz); align_eigen(cx,ny,cz); align_eigen(nx,ny,cz);
      align_eigen(px,py,nz); align_eigen(cx,py,nz); align_eigen(nx,py,nz);
      align_eigen(px,cy,nz); align_eigen(cx,cy,nz); align_eigen(nx,cy,nz);
      align_eigen(px,ny,nz); align_eigen(cx,ny,nz); align_eigen(nx,ny,nz);

      const T
        u0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,3),
        v0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,4),
        w0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,5),
        u1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,3),
        v1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,4),
        w1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,5),
        u2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,3),
        v2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,4),
        w2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,5),
        u3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,3),
        v3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,4),
        w3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,5);
      T
        u = u0/3 + 2*u1/3 + 2*u2/3 + u3/3,
        v = v0/3 + 2*v1/3 + 2*v2/3 + v3/3,
        w = w0/3 + 2*w1/3 + 2*w2/3 + w3/3;
      if (u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
      normU = (float)std::sqrt(u*u + v*v + w*w);
      const float scal = (u*pu + v*pv + w*pw)/(normU*normpU);
      if (scal<cmin) stopflag=true;

      X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
      normpU = normU;
      l+=dl;
    }
  }

  // Backward tracking
  l = dl; X = (float)X0; Y = (float)Y0; Z = (float)Z0;
  pu = eigen(X0,Y0,Z0,3);
  pv = eigen(X0,Y0,Z0,4);
  pw = eigen(X0,Y0,Z0,5);
  normpU = (float)std::sqrt(pu*pu + pv*pv + pw*pw);
  stopflag = false;

  while (!stopflag) {
    if (X<0 || X>eigen.width() - 1 || Y<0 || Y>eigen.height() - 1 || Z<0 || Z>eigen.depth() - 1 ||
        eigen((int)X,(int)Y,(int)Z,12)<FAmin || l>lmax) stopflag = true;
    else {

      const int
        cx = (int)X, px = (cx - 1<0)?0:cx - 1, nx = (cx + 1>=eigen.width())?eigen.width() - 1:cx + 1,
        cy = (int)Y, py = (cy - 1<0)?0:cy - 1, ny = (cy + 1>=eigen.height())?eigen.height() - 1:cy + 1,
        cz = (int)Z, pz = (cz - 1<0)?0:cz - 1, nz = (cz + 1>=eigen.depth())?eigen.depth() - 1:cz + 1;
      const T cu = eigen(cx,cy,cz,3), cv = eigen(cx,cy,cz,4), cw = eigen(cx,cy,cz,5);

      align_eigen(px,py,pz); align_eigen(cx,py,pz); align_eigen(nx,py,pz);
      align_eigen(px,cy,pz); align_eigen(cx,cy,pz); align_eigen(nx,cy,pz);
      align_eigen(px,ny,pz); align_eigen(cx,ny,pz); align_eigen(nx,ny,pz);
      align_eigen(px,py,cz); align_eigen(cx,py,cz); align_eigen(nx,py,cz);
      align_eigen(px,cy,cz);                        align_eigen(nx,cy,cz);
      align_eigen(px,ny,cz); align_eigen(cx,ny,cz); align_eigen(nx,ny,cz);
      align_eigen(px,py,nz); align_eigen(cx,py,nz); align_eigen(nx,py,nz);
      align_eigen(px,cy,nz); align_eigen(cx,cy,nz); align_eigen(nx,cy,nz);
      align_eigen(px,ny,nz); align_eigen(cx,ny,nz); align_eigen(nx,ny,nz);

      const T
        u0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,3),
        v0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,4),
        w0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,5),
        u1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,3),
        v1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,4),
        w1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,5),
        u2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,3),
        v2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,4),
        w2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,5),
        u3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,3),
        v3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,4),
        w3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,5);
      T
        u = u0/3 + 2*u1/3 + 2*u2/3 + u3/3,
        v = v0/3 + 2*v1/3 + 2*v2/3 + v3/3,
        w = w0/3 + 2*w1/3 + 2*w2/3 + w3/3;
      if (u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
      normU = (float)std::sqrt(u*u + v*v + w*w);
      const float scal = (u*pu + v*pv + w*pw)/(normU*normpU);
      if (scal<cmin) stopflag=true;

      X-=(pu=u); Y-=(pv=v); Z-=(pw=w);
      normpU=normU;
      l+=dl;

      resf.insert(CImg<>::vector(X,Y,Z),0);
    }
  }

  return resf>'x';
}
Пример #18
0
// Main procedure
//----------------
int main(int argc,char **argv) {

  // Read and init data
  //--------------------
  cimg_usage("A viewer of Diffusion-Tensor MRI volumes.");
  const char *file_i   = cimg_option("-i",(char*)0,"Input : Filename of tensor field (volume wxhxdx6)");
  const char* vsize    = cimg_option("-vsize","1x1x1","Input : Voxel aspect");
  const bool normalize = cimg_option("-normalize",true,"Input : Enable tensor normalization");
  const char *file_f   = cimg_option("-f",(char*)0,"Input : Input fibers\n");
  const float dl       = cimg_option("-dl",0.5f,"Fiber computation : Integration step");
  const float famin    = cimg_option("-famin",0.3f,"Fiber computation : Fractional Anisotropy threshold");
  const float cmin     = cimg_option("-cmin",0.2f,"Fiber computation : Curvature threshold");
  const float lmin     = cimg_option("-lmin",10.0f,"Fiber computation : Minimum length\n");
  const float lmax     = cimg_option("-lmax",1000.0f,"Fiber computation : Maximum length\n");
  const float tfact    = cimg_option("-tfact",1.2f,"Display : Tensor size factor");
  const char *bgcolor  = cimg_option("-bg","0,0,0","Display : Background color");
  unsigned int bgr = 0, bgg = 0, bgb = 0;
  std::sscanf(bgcolor,"%u%*c%u%*c%u",&bgr,&bgg,&bgb);

  CImg<> tensors;
  if (file_i) {
    std::fprintf(stderr,"\n- Loading tensors '%s'",cimg::basename(file_i));
    tensors.load(file_i);
  } else {
    // Create a synthetic tensor field here
    std::fprintf(stderr,"\n- No input files : Creating a synthetic tensor field");
    tensors.assign(32,32,32,6);
    cimg_forXYZ(tensors,x,y,z) {
      const float
        u = x - tensors.width()/2.0f,
        v = y - tensors.height()/2.0f,
        w = z - tensors.depth()/2.0f,
        norm = (float)std::sqrt(1e-5f + u*u + v*v + w*w),
        nu = u/norm, nv = v/norm, nw = w/norm;
      const CImg<>
        dir1 = CImg<>::vector(nu,nv,nw),
        dir2 = CImg<>::vector(-nv,nu,nw),
        dir3 = CImg<>::vector(nw*(nv - nu),-nw*(nu + nv),nu*nu + nv*nv);
      tensors.set_tensor_at(2.0*dir1*dir1.get_transpose() +
                            1.0*dir2*dir2.get_transpose() +
                            0.7*dir3*dir3.get_transpose(),
                            x,y,z);
    }
  }
  float voxw = 1, voxh = 1, voxd = 1;
  std::sscanf(vsize,"%f%*c%f%*c%f",&voxw,&voxh,&voxd);

  std::fprintf(stderr," : %ux%ux%u image, voxsize=%gx%gx%g.",
               tensors.width(),tensors.height(),tensors.depth(),
               voxw,voxh,voxd);

  CImgList<> fibers;
  if (file_f) {
    std::fprintf(stderr,"\n- Loading fibers '%s'.",cimg::basename(file_f));
    fibers.load(file_f);
  }

  const CImg<unsigned char> fiber_palette =
    CImg<>(2,1,1,3).fill(200,255,0,255,0,200).RGBtoHSV().resize(256,1,1,3,3).HSVtoRGB();

  // Compute eigen elements
  //------------------------
  std::fprintf(stderr,"\n- Compute eigen elements.");
  CImg<unsigned char> coloredFA(tensors.width(),tensors.height(),tensors.depth(),3);
  CImg<> eigen(tensors.width(),tensors.height(),tensors.depth(),13);
  CImg<> val,vec;
  float eigmax = 0;
  cimg_forXYZ(tensors,x,y,z) {
    tensors.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
    eigen(x,y,z,0) = val[0]; eigen(x,y,z,1) = val[1]; eigen(x,y,z,2) = val[2];
    if (val[0]<0) val[0] = 0;
    if (val[1]<0) val[1] = 0;
    if (val[2]<0) val[2] = 0;
    if (val[0]>eigmax) eigmax = val[0];
    eigen(x,y,z,3) = vec(0,0); eigen(x,y,z,4)  = vec(0,1); eigen(x,y,z,5)  = vec(0,2);
    eigen(x,y,z,6) = vec(1,0); eigen(x,y,z,7)  = vec(1,1); eigen(x,y,z,8)  = vec(1,2);
    eigen(x,y,z,9) = vec(2,0); eigen(x,y,z,10) = vec(2,1); eigen(x,y,z,11) = vec(2,2);
    const float fa = get_FA(val[0],val[1],val[2]);
    eigen(x,y,z,12) = fa;
    const int
      r = (int)cimg::min(255.0f,1.5f*cimg::abs(255*fa*vec(0,0))),
      g = (int)cimg::min(255.0f,1.5f*cimg::abs(255*fa*vec(0,1))),
      b = (int)cimg::min(255.0f,1.5f*cimg::abs(255*fa*vec(0,2)));
    coloredFA(x,y,z,0) = (unsigned char)r;
    coloredFA(x,y,z,1) = (unsigned char)g;
    coloredFA(x,y,z,2) = (unsigned char)b;
  }
Пример #19
0
void display3D(CImg<T> image,
               const char *file_o,const float ratioz,const unsigned int di,
               const char *file_pose_i,const char *file_pose_o,
               unsigned int rtype,bool color_type)
{
    std::cout<<"display image as 3D surface"<<std::flush;
    const CImg<unsigned char> norm=image.get_norm().normalize(0,255);
    // Compute surface with triangles.
    std::fprintf(stderr,"\n- Create image surface");
    std::fflush(stderr);
    CImgList<unsigned int> primitives;
    ////image colors
    CImgList<unsigned char> colors;
    const CImg<> points = image.get_elevation3d(primitives,colors,norm*-ratioz);
    ////constant colors
    CImgList<unsigned char> colors2;
    colors2=colors;
    cimglist_for(colors2,l) colors2(l).fill(255);//white

    // Compute image isophotes.
    std::fprintf(stderr,"\n- Compute image isophotes");
    std::fflush(stderr);
    CImgList<unsigned int> isoprimitives;
    ////image colors
    CImgList<unsigned char> isocolors;
    CImg<> isopoints;
    for (unsigned int i = 0; i<255; i+=di) {
        CImgList<> prims;
        const CImg<> pts = norm.get_isoline3d(prims,(float)i);
        isopoints.append_object3d(isoprimitives,pts,prims);
    }
    cimglist_for(isoprimitives,l) {
        const unsigned int i0 = isoprimitives(l,0);
        const float x0 = isopoints(i0,0), y0 = isopoints(i0,1);
        const unsigned char
        r = (unsigned char)image.linear_atXY(x0,y0,0),
        g = (unsigned char)image.linear_atXY(x0,y0,1),
        b = (unsigned char)image.linear_atXY(x0,y0,2);
        isocolors.insert(CImg<unsigned char>::vector(r,g,b));
    }
    cimg_forX(isopoints,l) isopoints(l,2) = -ratioz*norm.linear_atXY(isopoints(l,0),isopoints(l,1));
    ////constant colors
    CImgList<unsigned char> isocolors2;
    isocolors2=isocolors;
    cimglist_for(isocolors2,l) isocolors2(l).fill(255);//white

    // Save object if necessary
    if (file_o)
    {
        std::fprintf(stderr,"\n- Save 3d object as '%s'",cimg::basename(file_o));
        std::fflush(stderr);
        points.save_off(primitives,colors,file_o);
    }

    //display GUI information
    std::fprintf(stderr,
                 "\n- Enter interactive loop.\n\n"
                 "GUI reminder: \n"
                 " + Use mouse to rotate and zoom object\n"
                 " + key 'F'          : toggle Fullscreen\n"
                 " + key 'Q' or 'ESC' : Quit (i.e. exit)\n"
                 " load or save file:\n"
                 " + key 'S'          : Save displayed image (i.e. 3D view)\n"
                 " + key 'O'          : save pOse (i.e. 3D view parameters)\n"
                 " + key 'R'          : Read pose (i.e. 3D view parameters)\n"
                 " render type:\n"
                 " + key 'C'          : color render (image or constant)\n"
                 " + key 'T'          : poinTs render\n"
                 " + key 'L'          : Lines render\n"
                 " + key 'A'          : fAces render\n"
                 " + key 'H'          : flat-sHaded faces render\n"
                 " + key 'G'          : Gouraud-shaded faces render\n"
                 " + key 'P'          : Phong-shaded faces render\n"
                 " + key 'I'          : Isophotes render\n"
                 " + key 'BackSpace'  : change rendering type (i.e. decrement type)\n"
                 " + Any other key    : change rendering type (i.e. increment type)\n\n"
                );
    std::fflush(stderr);
    const char *const title = "Image viewed as a surface";
    CImgDisplay disp(800,600,title,0);
    CImg<float> pose=CImg<float>::identity_matrix(4);
    //load pose if set
    if(file_pose_i) {
        std::cerr<<"- read pose from file \""<<file_pose_i<<"\"\n"<<std::flush;
        pose.load(file_pose_i);
    }
//pose.print("pose");std::cerr<<std::flush;

    //GUI loop
    while (!disp.is_closed())
    {
        const unsigned char text_color[3]= {123,234,234};
        CImg<unsigned char> visu(disp.width(),disp.height(),1,3,0);
        visu.draw_text(10,10,"%s",text_color,0,1,24,
                       rtype==0?"Points (0,T)":(rtype==1?"Lines (1,L)":(rtype==2?"Faces (2,A)":(rtype==3?"Flat-shaded faces (3,H)":
                                                (rtype==4?"Gouraud-shaded faces (4,G)":(rtype==5?"Phong-shaded faces (5,P)":"Isophotes (6,I)"))))));
        static bool first_time=(file_pose_i)?false:true;
        if (rtype==6) visu.display_object3d(disp,isopoints,isoprimitives,(color_type)?isocolors:isocolors2,first_time,1,-1,true,
                                                500.0f,0.0f,0.0f,-5000.0f,0.0f,0.0f,true,pose.data());
        else visu.display_object3d(disp,points,primitives,(color_type)?colors:colors2,first_time,rtype,-1,true,
                                       500.0f,0.0f,0.0f,-5000.0f,0.0f,0.0f,true,pose.data());
        first_time=false;
//pose.print("pose");std::cerr<<std::flush;
        switch (disp.key())
        {
        case 0:
            break;
        case cimg::keyBACKSPACE:
            rtype=(7+rtype-1)%7;
            break;
        case cimg::keyQ:
        case cimg::keyESC:
            disp.close();
            break;
        //fullscreen display or not
        case cimg::keyF:
            if (disp.is_fullscreen()) disp.resize(800,600);
            else disp.resize(disp.screen_width(),disp.screen_height());
            disp.toggle_fullscreen();
            break;
        //save display
        case cimg::keyS: {
            std::string file_tmp="CImg_surface3D.png";
            std::cerr<<"saving display as image in \""<<file_tmp<<"\".\n"<<std::flush;
            CImg<unsigned char> tmp;
            disp.snapshot(tmp);
            tmp.save(file_tmp.c_str());
        }
        break;
        //save pose
        case cimg::keyO: {
            std::cerr<<"saving pose in file \""<<file_pose_o<<"\".\n"<<std::flush;
            pose.save(file_pose_o);
        }
        break;
        //load pose
        case cimg::keyR: {
            std::cerr<<"loading pose from file \""<<file_pose_i<<"\".\n"<<std::flush;
            pose.load(file_pose_i);
        }
        break;
        //display type
        case cimg::keyC:
            color_type=(color_type)?false:true;
            break;//color type
        case cimg::keyT:
            rtype=0;
            break;//poinTs
        case cimg::keyL:
            rtype=1;
            break;//Lines
        case cimg::keyA:
            rtype=2;
            break;//fAces
        case cimg::keyH:
            rtype=3;
            break;//flat-sHaded faces
        case cimg::keyG:
            rtype=4;
            break;//Gouraud-shaded faces
        case cimg::keyP:
            rtype=5;
            break;//Phong-shaded faces
        case cimg::keyI:
            rtype=6;
            break;//Isophotes
        default:
            rtype = (rtype+1)%7;
            break;
        }//Key switch
    }//GUI loop
}