Tema Cerrado
Resultados 1 al 1 de 1

Tema: Función scale_colors() comentada

  1. #1
    Avatar de Guillermo Luijk
    Guillermo Luijk no ha iniciado sesión RAW RAW la botella de RAW
    Fecha de Ingreso
    07 Mar, 06
    Ubicación
    Madrid (a ratos Alicante)
    Mensajes
    7,749

    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 PM
    "En ocasiones veo halos."

    http://www.guillermoluijk.com para suscribirte pulsa aquí
    Últimos contenidos: EL HISTOGRAMA. ESE INVITADO INESPERADO y EL ESTABILIZADOR COMO REDUCTOR DE RUIDO

Tema Cerrado

Permisos de Publicación

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