Registrarse
Resultados 1 al 1 de 1
  1. #1
    Ingreso
    07 Mar, 06
    Ubicación
    Madrid (a ratos Alicante)
    Mensajes
    9,458
    Post Thanks / Like

    Función scale_colors() comentada

    Jugando con la última versión del revelador de Manuel que trae el punto de negro y saturación, me he dado cuenta de un funcionamiento de los mismos que no me esperaba (lo comento al final, es lo de menos); para entender el porqué me he estudiado un poco la función scale_colors() que es la que aplica dichas correcciones.

    La pongo aquí porque es quizá la función más interesante de DCRAW y que reciclaremos para Perfect Blend. scale_colors() tiene las funciones:
    • Calcular el balance de blancos automático
    • Llamada a la reducción de ruido Wavelet
    • Calcular los multiplicadores normalizados del balance de blancos
    • Aplicar la sustracción del nivel negro y escalar al punto de saturación
    • Aplicar el balance de blancos (se hace a la vez que el anterior punto)
    • Aplicar la corrección de la Aberración cromática



    Código:
    void CLASS scale_colors()
    {
      unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8];
    
    /* DARKNESS: dark */
      int val, dark, sat;
      double dsum[8], dmin, dmax;
      float scale_mul[4], fr, fc;
      ushort *img=0, *pix;
    
      if (user_mul[0])
        memcpy (pre_mul, user_mul, sizeof pre_mul);
    
    /* WB automático */
      if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) {
        memset (dsum, 0, sizeof dsum);
        bottom = MIN (greybox[1]+greybox[3], height);
        right  = MIN (greybox[0]+greybox[2], width);
        for (row=greybox[1]; row < bottom; row += 8)
          for (col=greybox[0]; col < right; col += 8) {
    	memset (sum, 0, sizeof sum);
    	for (y=row; y < row+8 && y < bottom; y++)
    	  for (x=col; x < col+8 && x < right; x++)
    	    FORC4 {
    	      if (filters) {
    		c = FC(y,x);
    		val = BAYER(y,x);
    	      } else
    		val = image[y*width+x][c];
    
    	      /* Nivel cercano a saturar (maximum-25) */
                   /* se descarta para cálculo de WB */
    	      if (val > maximum-25) goto skip_block;
    	      if ((val -= black) < 0) val = 0;
    	      sum[c] += val;
    	      sum[c+4]++;
    	      if (filters) break;
    	    }
    	FORC(8) dsum[c] += sum[c];
    skip_block: ;
          }
        FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c];
      }
    
    /* Se ha pedido WB de la cámara Y existe WB de la cámara */
      if (use_camera_wb && cam_mul[0] != -1) {
        memset (sum, 0, sizeof sum);
        for (row=0; row < 8; row++)
          for (col=0; col < 8; col++) {
    	c = FC(row,col);
    	if ((val = white[row][col] - black) > 0)
    	  sum[c] += val;
    	sum[c+4]++;
          }
        if (sum[0] && sum[1] && sum[2] && sum[3])
          FORC4 pre_mul[c] = (float) sum[c+4] / sum[c];
        else if (cam_mul[0] && cam_mul[2])
          memcpy (pre_mul, cam_mul, sizeof pre_mul);
        else
          fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname);
      }
    
      if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1;
    
    /*  Nivel de negro calculado de píxels ocultos: black */
      dark = black;
      sat = maximum;
      if (threshold) wavelet_denoise();
    
    /* maximum se corrige a la baja por el nivel de negro */
      maximum -= black;
    
    /* dmax normalizará los multiplicadores para que */
    /* el menor (o el mayor) valga siempre 1.0 */
      for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) {
        if (dmin > pre_mul[c])
    	dmin = pre_mul[c];
        if (dmax < pre_mul[c])
    	dmax = pre_mul[c];
      }
      if (!highlight) dmax = dmin;
    
    /* Se introduce EN LOS MULTIPLICADORES el escalado para */
    /* ajustar por maximum corregido: 65535.0 / maximum */
      FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum;
      if (verbose) {
        fprintf (stderr,
          _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat);
        FORC4 fprintf (stderr, " %f", pre_mul[c]);
        fputc ('\n', stderr);
      }
    
    /* Se aplica sobre la imagen el reescalado y el */
    /* balance de blancos a la vez */
      size = iheight*iwidth;
      for (i=0; i < size*4; i++) {
        val = image[0][i];
        if (!val) continue;        /* Nivel vacío (aún no se ha interpolado Bayer) */
        val -= black;              /* Restamos nivel de negro */
        val *= scale_mul[i & 3];   /* Escalamos (WB + ajuste sat.) */
        image[0][i] = CLIP(val);
      }
    
    /* Corrección de aberración cromática */
      if ((aber[0] != 1 || aber[2] != 1) && colors == 3) {
        if (verbose)
          fprintf (stderr,_("Correcting chromatic aberration...\n"));
        for (c=0; c < 4; c+=2) {
          if (aber[c] == 1) continue;
          img = (ushort *) malloc (size * sizeof *img);
          merror (img, "scale_colors()");
          for (i=0; i < size; i++)
    	img[i] = image[i][c];
          for (row=0; row < iheight; row++) {
    	ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5;
    	if (ur > iheight-2) continue;
    	fr -= ur;
    	for (col=0; col < iwidth; col++) {
    	  uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5;
    	  if (uc > iwidth-2) continue;
    	  fc -= uc;
    	  pix = img + ur*iwidth + uc;
    	  image[row*iwidth+col][c] =
    	    (pix[     0]*(1-fc) + pix[       1]*fc) * (1-fr) +
    	    (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr;
    	}
          }
          free(img);
        }
      }
    }
    Me he dado cuenta de que cuando se revela en DCRAW indicando un nivel de saturación con -S, no necesariamente los niveles que queden por encima del valor suministrado en cada canal serán recortados. Cuando el balance de blancos es conservador (multiplicadores <=1.0) puede haber valores de los canales corregidos superiores al nivel de saturación que por la acción de dicho escalado de balance de blancos entren a formar parte de la imagen final al quedar por debajo del punto de saturación, y por tanto resultar tras el reescalado con valor <=65535.

    No tiene gran trascendencia porque el punto de saturación sirve para eso, para saber donde satura el RAW de una cámara y pasado dicho punto no debería haber ningún nivel. Pero el comportamiento comentado significa que -S no se puede usar para establecer el nivel a partir del cual se quieren recortar las altas luces; solo ocurrirá cuando se revele con multiplicadores >=1 (-H 0) o directamente sin balance de blancos (-r 1 1 1 1).

    Una pregunta sobre nomenclatura C:
    Para aplicar el balance de blancos se accede a la imagen con:

    Código:
    for (i=0; i < size*4; i++) {
        val = image[0][i];
    pero en otro punto se refiere al mismo array con:

    Código:
    for (c=0; c < 4; c++)
      for (y=row; y < row+8 && y < bottom; y++)
        for (x=col; x < col+8 && x < right; x++)
          val = image[y*width+x][c];
    Entiendo que son equivalentes no? se hace así por comodidad, simplemente image es una tira de memoria llena de datos y en un caso ha sido más fácil accederla con 3 índices y en el otro a piñón como un array monodimensional.
    Última edición por Guillermo Luijk; 24/05/2008 a las 17:06
    "En ocasiones veo halos."

    http://www.guillermoluijk.com para suscribirte haz clic aquí
    Último contenido: EL MITO DEL TRÍPODE QUE ASESINÓ A UN ESTABILIZADOR


 

Marcadores

Marcadores

Permisos de publicación

  • No puedes crear nuevos temas
  • No puedes responder temas
  • No puedes subir archivos adjuntos
  • No puedes editar tus mensajes
  •