OJODIGITAL

 
Debates sobre la programación Para tratar temas sobre programación

Respuesta
  #1 (permalink)  
Antiguo 24-may-2008, 17:40
Avatar de _GUI_
Gurú Ojodigitalero
 
Fecha de Ingreso: marzo-2006
Ubicación: Madrid (a ratos Alicante)
Mensajes: 6.330
Enviar un mensaje por MSN a _GUI_
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.
__________________
"En ocasiones veo halos."

Canon EOS 350D | EOS 300 | 10-22 | 24-70 f2.8L | 70-200 f4L | 300 f4L IS
http://www.guillermoluijk.com para suscribirte pulsa aquí

Última edición por _GUI_; 24-may-2008 a las 18:06.
Responder Citando
Respuesta

Marcadores

Herramientas
Desplegado

Normas de Publicación
No puedes crear nuevos temas
No puedes responder temas
No puedes subir archivos adjuntos
No puedes editar tus mensajes

Los Códigos BB están Activado
Las Caritas están Activado
[IMG] está Activado
El Código HTML está Desactivado
Trackbacks are Activado
Pingbacks are Activado
Refbacks are Activado
Ir al Foro