Emule la duración del obturador en fotos RAW usando el apilamiento de exposición

Así que he estado en este problema durante aproximadamente un año y no he podido resolverlo. Me di por vencido hace un tiempo, pero ahora estoy investigando y listo para obtener una respuesta.

Estoy tratando de fingir una exposición prolongada tomando múltiples fotos RAW y haciendo algo con los valores del filtro Bayer para obtener el efecto de haber dejado el obturador abierto durante tanto tiempo.

La idea que tengo en mente es que, intuitivamente, la exposición prolongada funciona dejando el obturador abierto durante más tiempo, por lo que los valores del sensor de luz (que almacenan las imágenes RAW) son simplemente una agregación de múltiples valores de fotos más cortas .

Por ejemplo, si tengo tres fotos de 1/3 de segundo de duración tomadas sin mover la cámara, deberían almacenar la misma información que una foto de 1 segundo de duración.

El problema que tengo es cómo puedo cuantificar esa agregación. Descubrí que muchos métodos diferentes fallan y no estoy seguro de por qué. Si simplemente promedio las múltiples fotos, obtengo una gran reducción de ruido . Así que es bueno tener esa parte. Más tarde puedo usar Camera Raw para iluminar la foto y obtendré una aproximación cercana a lo que habría obtenido con una exposición prolongada de 1 segundo. El problema es que quiero hacer eso en el dispositivo. Actualmente estoy usando un iPhone para probar, pero no creo que eso deba importar.

Configuración actual y fórmula

Estoy usando tres exposiciones de 1/3 de segundo para tratar de falsificar una foto de 1 segundo. Mi fórmula actual es simple:

out_picture[x][y] = picture1[x][y] + picture2[x][y] + picture3[x][y]

El problema es que eso me da imágenes realmente rosadas como esta:

Versión JPEG del archivo RAW

Probé múltiples variaciones diferentes de la fórmula anterior. Una que pensé que era prometedora era la derivada de la función sigmoidea . La razón por la que utilicé la derivada del sigmoide es porque realicé un estudio de caso en el que estudié el efecto de las salidas RGB finales en función del valor del control deslizante "EV" en Photoshop Camera Raw y encontré un patrón similar al sigmoide. Esto es lo que parece cuando lo trazo para algunos píxeles:

Sigmoide tal vez?

Así que pensé que tal vez la derivada del sigmoide (cambios altos para valores medios, cambios bajos para valores de filtro altos y bajos) arreglaría las cosas. Normalicé los valores del filtro a un rango de 0-1 usando el nivel de negro de la cámara y el valor máximo de bits. Hice algunas modificaciones a la derivada para que encajara dentro del rango de valores 0-1, esta es la función con la que terminé. Luego multipliqué por el número de fotografías tomadas, para emular el EVcontrol deslizante en Camera Raw.

Aquí está la fórmula para eso (en python):

def exposureAdjust(x):
   black_level = 528    ## iPhone RAW Photos have a black_level of 528
   max_pixel_value = 2**14 - 1    ## 14-bit depth
   normalized = (x - black_level)/max_pixel_value    ## now x is between [0,1]
   EV = num_pics    ## faking EV value
   adjustment = EV * (np.exp(-10 *(x - 0.25)))/(np.exp(-10*(x - 0.25)) + 1)^2

   return min(x * (1+adjustment), max_pixel_value)    ## Cap at 2**14 


num_pics = 3
out_picture[x][y] = picture1[x][y] + picture2[x][y] + picture3[x][y]
out_picture[x][y] = exposureAdjust(out_picture[x][y]/3)

Ejecutando esta fórmula, obtengo un resultado similar:

Aún roto


Conclusión y observaciones

Como puede ver, todavía es rosado. Las fotos de arriba son JPEG, sí, pero en realidad estoy trabajando con RAW. Solo tuve que subirlos como archivos JPEG para poder adjuntarlos en línea.

El rosa sucede cuando falta el verde. La cámara tiene un diseño de filtro bayer de RGGB, pero realmente no veo cómo podría obtener este efecto. Alguien tiene alguna idea de cuál es el culpable aquí y cómo puedo ajustarlo programáticamente. Tengo toda la canalización configurada. Solo necesito la fórmula, pero de alguna manera no funciona. He codificado esto en Python y Swift, y los resultados son los mismos. Definitivamente hay un problema con la fórmula que usa los valores de filtro RAW Bayer. Creo que este es un desafío genial, pero he llegado al final de mi ingenio en esto.

¿Alguna idea?


ACTUALIZACIÓN: Aquí están los resultados del histograma para la imagen antes y después deexposureAdjust aplicar la función. ¿Parece que el canal verde debe ajustarse de manera diferente?

En tu ejemplo, ¿a qué estás tomando una foto? Parece muy oscuro y subexpuesto.
Espere un minuto, ¿está trabajando directamente con valores sin procesar o con datos desbayerizados?
@scottbb solo algunos cables en mi escritorio. Trabajando directamente con los valores brutos. Está intencionalmente oscuro y subexpuesto para que mi exposición prolongada pueda ser más brillante. Puedo agregar una foto mejor
FWIW, esto es exactamente lo que hace el "Modo nocturno" en Android reciente.
¿Tiene un código de trabajo para mostrar correctamente una sola imagen tomada con una exposición media ("correcta")?
Entonces, sí, mi código realmente funciona cuando simplemente emito el promedio de todas las imágenes (¡también se reduce el ruido!) Solo quiero iluminarlo ahora. También me di cuenta de que mi código no reflejaba que paso el promedio a la función de ajuste de exposición, no la suma.
Creo que tiene un malentendido sobre el apilamiento: no subexponga cada toma individual en la pila, esperando aumentar sustancialmente la exposición en la publicación. Use el rango completo de su cámara para cada toma y promedie las tomas juntas.
Santo f... Soy un idiota. Eso tiene mucho sentido, me da algo con lo que trabajar por ahora. Sin embargo, por curiosidad, me gustaría una solución a esto. Voy a leer un rato.

Respuestas (2)

Observaciones:

  1. Está sumando los valores de cada píxel, pero su exposureAdjust()función asume que después del condicionamiento, cada píxel estará en el rango [0, 1). Esto no es correcto. Suponga que el valor de un píxel en cada una de las 3 imágenes de entrada es, digamos, 50 % de escala completa (por lo tanto, 2 13 = 8192). Sumando eso tres veces da 3 * 8192 = 24,576. Luego, el resultado posterior normalized = (x - black_level)/max_pixel_valuees aproximadamente 1.47, definitivamente no normalizado a menos de 1.

  2. Elimine su adjustment =línea sigmoidea hasta que resuelva el resto de la lógica (como arriba). Aquí hay un gráfico de su función sigmoidea:

    ingrese la descripción de la imagen aquí

    Tenga en cuenta que para los valores de x por encima de 0,4, el aumento de x produce rápidamente valores más pequeños de y (su valor "ajustado". A modo de comparación, un valor no ajustado debería corresponder a la gráfica lineal y = x en el gráfico.

  3. Para la normalización (suponiendo entradas correctamente delimitadas de [0, ]), probablemente también max_pixel_value - 1debería reducir el denominador (es decir, ). Si no lo hace, entonces sus valores normalizados están en el rango de [0, ∼0.969) (precisamente, (2 13 - 511) / (2 14 - 1)).black_levelnormalized = (x - black_level)/(max_pixel_value - black_level)

1. El primer bloque de código fue solo mi prueba inicial. Estoy 100% de acuerdo en que ese no se normalizó correctamente, solo quería mostrar cómo la entrada mal normalizada produjo el mismo resultado.
2. Entonces, la razón por la que quería tener esa función era porque pensaba que había algo de no linealidad en la forma en que se escalaban los valores de Bayer. y=x sería ideal, pero pensé que tal vez la causa del problema era que los píxeles oscuros (0-0,5) no se escalaban lo suficiente.
3. Claro, este es un punto justo, seguro que es un error en mis cálculos. Desafortunadamente, no creo que esto solucione el problema :/

Sus resultados son decididamente magenta y eso es lo opuesto a lo que deberían ser. Deben ser verdes para un bayer RGB sin corregir.

Sospecho que su corrección sigmoidea observada estuvo fuertemente influenciada por los datos sin procesar que ya tenían una corrección de balance de blancos aplicada en ACR. Es posible que incluso obtenga una "corrección duplicada" en este punto, pero no lo sé.

Este artículo sobre Uni-WB tiene mucha información sobre las correcciones/métodos de datos sin procesar y los factores de corrección de WB. http://www.guillermoluijk.com/tutorial/uniwb/index_en.htm

Los datos RAW se aplican directamente de las fotos tomadas desde la cámara, nunca pasan por ACR. Tiene razón en que definitivamente algo anda mal con los canales, ya que estos son los resultados antes y después de la función de ajuste de exposición. Claramente, los canales rojo y azul se ven afectados de manera completamente diferente.
Dijo que se le ocurrió una corrección sigmoidea basada en lo que observó con Photoshop Camera Raw... a esa observación se le aplicaron correcciones de balance de blancos. ¿Qué programa está utilizando para procesar los datos sin procesar manipulados ahora? AFAIK, el único programa que puede procesar un archivo sin formato sin aplicar correcciones WB es DCRAW; tal vez RawDigger.