¿Cómo puedo eliminar automáticamente de forma digital las motas de polvo del sensor de movimiento de una gran serie de fotos?

Mientras estaba en el desierto, mi sensor se volvió polvoriento. Estuve fuera durante semanas y no me di cuenta de esto hasta el final de mi viaje, así que tengo cientos de fotos con sensores sucios. A lo largo de las vacaciones, el polvo empeoró gradualmente ya que cambiaba de lentes con frecuencia. Después de mis vacaciones, hice que un profesional limpiara el sensor y las fotos nuevas no tienen manchas, pero estoy buscando una solución para las fotos de las vacaciones.

Para limpiar mis fotos, usé The Gimp para producir una máscara de las ubicaciones de las peores piezas de polvo:

las peores ubicaciones de polvo

luego usé gmic para eliminarlos de la línea de comandos:

gmic 08-34-51.jpg ../../../dustmask_20180606_sky_flat_neg.png +inpaint_patchmatch[0] [1],10,7,4,2,1,0 -o[2] 08-34-51-clean.jpg

Aunque esta no es una solución óptima porque esencialmente vuelve a pintar esas áreas desde cero (sin usar la información de fondo), proporciona resultados satisfactorios en el cielo azul. Pensé que de esta manera podría automatizar el proceso sobre los cientos de imágenes afectadas. Desafortunadamente, el polvo no es estacionario , así que esto no funciona. Se desplaza del orden de 20 píxeles, lo que corresponde a unos 80 µm. No sé si esto se debe a que el polvo se mueve físicamente o si puede deberse al procesamiento de imágenes en la cámara, como la estabilización de imagen o la corrección de la lente. Tomé algunas imágenes tanto en RAW como en JPEG, y para esas imágenes puedo ver un ligero cambio en la forma de la imagen.

Es muy sutil, pero si comparas las siguientes dos imágenes, la pieza de polvo más grande y prominente ha pasado de estar centrada en un píxel (1677, 619)a estar centrada en un píxel (1655, 603). En el otro extremo, un píxel menos prominente a la derecha se ha movido de (4919, 1485)a (4940, 1483). ¿Quizás no debería ser demasiado sorprendente que las piezas de polvo puedan moverse y se desplacen en relación con el sensor?

Imagen 1 con polvo en el cielo

Imagen 2 con polvo en el cielo

Las fotos se toman aproximadamente con 90 minutos de diferencia. Las imágenes que publiqué se reducen en un factor 2.

Los datos EXIF ​​incluyen datos de Sony Makernote, que pueden incluir información sobre la estabilización de imagen, como ImageStabilization = 1. No sé si incluye más detalles sobre la estabilización de imagen. Incluye un campo Sony_0x201f = 128 17 2 0, que parece variar entre las imágenes, pero es idéntico entre las dos imágenes que se muestran arriba, por lo que no identifica (únicamente) la información para corregir la estabilización de la imagen. No sé si algún otro campo lo hace. Los datos exif completos (según lo informado por exiftool -v) para una imagen muestran:

  ExifToolVersión = 10.10
  Nombre de archivo = 08-35-11.jpg
  Directorio = .
  Tamaño de archivo = 9440161
  Fecha de modificación del archivo = 1528067625
  Fecha de acceso al archivo = 1529519016
  FileInodeChangeDate = 1528150970
  Permisos de archivo = 33204
  Tipo de archivo = JPEG
  Extensión de tipo de archivo = JPG
  Tipo MIME = imagen/jpeg
JPEG APP1 (44908 bytes):
  ExifByteOrder = II
  + [Directorio IFD0 con 13 entradas]
  | 0) Software de procesamiento = digiKam-5.6.0
  | 1) Descripción de la imagen =                                
  | 2) Marca = SONY
  | 3) Modelo = ILCE-6000
  | 4) Orientación = 1
  | 5) Resolución X = 350 (350/1)
  | 6) YResolución = 350 (350/1)
  | 7) Unidad de resolución = 2
  | 8) Software = ILCE-6000 v3.20
  | 9) Fecha de modificación = 2018:05:11 08:35:11
  | 10) Posicionamiento YCbCr = 2
  | 11) ExifOffset (Subdirectorio) -->
  | + [Directorio ExifIFD con 38 entradas]
  | | 0) Tiempo de exposición = 0,003125 (1/320)
  | | 1) Número F = 11 (110/10)
  | | 2) Programa de exposición = 3
  | | 3) ISO = 100
  | | 4) Tipo de sensibilidad = 2
  | | 5) Índice de exposición recomendado = 100
  | | 6) Versión Exif = 0230
  | | 7) FechaHoraOriginal = 2018:05:11 08:35:11
  | | 8) Fecha de creación = 2018:05:11 08:35:11
  | | 9) Configuración de componentes = 1 2 3 0
  | | 10) Bits comprimidos por píxel = 3 (3/1)
  | | 11) Valor de brillo = 10.76328125 (27554/2560)
  | | 12) Compensación de exposición = 0 (0/10)
  | | 13) MaxApertureValue = 3.6171875 (926/256)
  | | 14) Modo de medición = 5
  | | 15) Fuente de luz = 0
  | | 16) Destello = 16
  | | 17) Longitud focal = 18 (180/10)
  | | 18) MakerNoteSony (Subdirectorio) -->
  | | + [Directorio de MakerNotes con 94 entradas]
  | | | 0) Sony_0x1003 = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  | | | 1) Sony_0x2000 = 0
  | | | 2) Imagen de vista previa =
  | | | 3) Calificación = 0
  | | | 4) Sony_0x2003 =
  | | | 5) Contraste = 0
  | | | 6) Saturación = 0
  | | | 7) Nitidez = 0
  | | | 8) Brillo = 0
  | | | 9) Reducción de ruido de exposición prolongada = 1
  | | | 10) Reducción de ruido ISO alto = 2
  | | | 11) HDR = 0 0
  | | | 12) Sony_0x200c = 0 0 0
  | | | 13) Sony_0x200d = 1 (10/10)
  | | | 14) WBShiftAB_GM = 0 0
  | | | 15) ShotInfo (Subdirectorio) -->
  | | | + [directorio BinaryData, 390 bytes]
  | | | | FaceInfoOffset = 94
  | | | | Fecha y hora de Sony = 2018:05:11 08:35:11
  | | | | SonyImageHeight = 4000
  | | | | Ancho de imagen de Sony = 6000
  | | | | Rostros detectados = 0
  | | | | FaceInfoLength = 37
  | | | | MetaVersión = DC7303320222000
  | | | 16) Estilo Creativo = Estándar
  | | | 17) Temperatura de color = 0
  | | | 18) Filtro de compensación de color = 0
  | | | 19) Modo de escena = 0
  | | | 20) Coincidencia de zona = 0
  | | | 21) DynamicRangeOptimizer = 3
  | | | 22) Estabilización de imagen = 1
  | | | 23) Modo de color = 0
  | | | 24) Tamaño de imagen completa = 4000 6000
  | | | 25) PreviewImageSize = 1080 1616
  | | | 26) formato de archivo = 3 3 1 0
  | | | 27) Calidad = 2
  | | | 28) FlashExposureComp = 0 (0/10)
  | | | 29) WhiteBalanceFineTune = 0
  | | | 30) Balance de blancos = 0
  | | | 31) ID de modelo de Sony = 312
  | | | 32) Teleconvertidor = 0
  | | | 33) Reducción de ruido de múltiples cuadros = 0
  | | | 34) Efecto de imagen = 0
  | | | 35) Efecto Piel Suave = 0
  | | | 36) Corrección de viñetas = 2
  | | | 37) Aberración cromática lateral = 2
  | | | 38) Configuración de corrección de distorsión = 0
  | | | 39) Sony_0x2015 = 65535
  | | | 40) Tipo de lente = 65535
  | | | 41) Especificaciones de la lente = ...5c
  | | | 42) Retrato automático enmarcado = 0
  | | | 43) Acción Flash = 0
  | | | 44) Sony_0x2018 = 0
  | | | 45) Sony_0x2019 = 0
  | | | 46) Sony_0x201a = 1
  | | | 47) Modo de enfoque = 2
  | | | 48) AFAreaModeSetting = 1
  | | | 49) Posición del punto flexible = 0 0
  | | | 50) AFZoneSeleccionado = 0
  | | | 51) Sony_0x201f = 128 17 2 0
  | | | 52) AFPointsUsed = 0 0 0 0 0 0 0 0 0 0
  | | | 53) Sony_0x2021 = 0
  | | | 54) FocalPlaneAFPointsUsed = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  | | | 55) Sony_0x2023 = 0
  | | | 56) Sony_0x5001 = 0 (0/1000)
  | | | 57) Sony_0x5002 = 128
  | | | 58) Modo de exposición = 7
  | | | 59) Sony_0xb045 = 0
  | | | 60) Sony_0xb046 = 0
  | | | 61) Calidad JPEG = 65535
  | | | 62) Nivel de destello = 0
  | | | 63) Modo de liberación = 0
  | | | 64) Número de secuencia = 0
  | | | 65) Antidesenfoque = 2
  | | | 66) Sony_0xb04c = 1 (10/10)
  | | | 67) Sony_0xb04d = 0
  | | | 68) DynamicRangeOptimizer = 1
  | | | 69) Sony_0xb050 = 65535
  | | | 70) Sony_0xb051 = 0
  | | | 71) Autointeligente = 0
  | | | 72) Sony_0xb053 = 0
  | | | 73) Balance de blancos = 0
  | | | 74) Tag9400c (Subdirectorio) -->
  | | | + [directorio BinaryData, 556 bytes]
  | | | | Modo de liberación2 = 0
  | | | | ShotNumberSincePowerUp = 2
  | | | | SequenceImageNumber = 0
  | | | | Longitud de secuencia = 1
  | | | | Número de archivo de secuencia = 0
  | | | | Longitud de secuencia = 1
  | | | | Orientación de la cámara = 1
  | | | | Calidad2 = 0
  | | | | SonyImageHeight = 500
  | | | | ModeloReleaseYear = 14
  | | | 75) Sony_0x9401 = ..f....pW..).6Q.\.(.GG..6\6.GG..6\6..$..........^. ..3..s.[recorte]
  | | | 76) Tag9402 (Subdirectorio) -->
  | | | + [directorio BinaryData, 400 bytes]
  | | | | Temperatura ambiente = 21
  | | | | Modo de enfoque = 2
  | | | | AFAreaMode = 1
  | | | | Posición de enfoque2 = 202
  | | | 77) Tag9403 (Subdirectorio) -->
  | | | + [directorio BinaryData, 1000 bytes]
  | | | 78) Tag9404b (Subdirectorio) -->
  | | | + [directorio BinaryData, 556 bytes]
  | | | | Posición del zoom de la lente = 27
  | | | 79) Tag9405b (Subdirectorio) -->
  | | | + [directorio BinaryData, 1992 bytes]
  | | | | Sony ISO = 4096
  | | | | Base ISO = 4096
  | | | | ParadasSobreBaseISO = 4096
  | | | | SonyExposureTime2 = 6208
  | | | | Tiempo de exposición = 0,003125
  | | | | SonyFNúmero = 5888
  | | | | SonyMaxApertureValue = 5054
  | | | | SequenceImageNumber = 0
  | | | | Modo de liberación2 = 0
  | | | | Reducción de ruido ISO alto = 2
  | | | | Reducción de ruido de exposición prolongada = 1
  | | | | Efecto de imagen2 = 0
  | | | | Programa de exposición = 1
  | | | | estilo creativo = 0
  | | | | Nitidez = 0
  | | | | Corrección de distorsión = 0
  | | | | formato de lente = 1
  | | | | Montura de lente = 2
  | | | | LensType2 = 32787
  | | | | Posición del zoom de la lente = 27
  | | | 80) Tag9406 (Subdirectorio) -->
  | | | + [directorio BinaryData, 64 bytes]
  | | | | Temperatura de la batería = 87
  | | | | Nivel de batería = 55
  | | | 81) Sony_0x9407 = .2WW.^....AT..W..>.WSi...lw...W.............T..i.... ...T....Wl
  | | | 82) Sony_0x9408 = i....*......\...*..}......u}..C.=..@.[.8k.&...| ......C^..pp..[recorte]
  | | | 83) Sony_0x9409 = . ...l.(....I.........`...s..........i7.@.Sp......>... .....@..........z...%...>.[recorte]
  | | | 86) Tag940c (Subdirectorio) -->
  | | | + [directorio BinaryData, 64 bytes]
  | | | | Montaje de lente2 = 4
  | | | | LensType3 = 32787
  | | | | CameraE-mountVersion = 336
  | | | | LensE-mountVersion = 263
  | | | | Versión de firmware de lente = 1
  | | | 87) Sony_0x940d = ......g......z...?..u.............GO.D.....qUx... ?....el....8[recorte]
  | | | 88) Tag940e (Subdirectorio) -->
  | | | + [directorio BinaryData, 12288 bytes]
  | | | 89) Sony_0xa100 =
  | | | 90) Tag2010g (Subdirectorio) -->
  | | | + [directorio BinaryData, 6556 bytes]
  | | | | Modo de liberación2 = 0
  | | | | Optimizador de rango dinámico = 1
  | | | | ReleaseMode3 = 0
  | | | | Modo de liberación2 = 0
  | | | | modo parpadeo = 1
  | | | | ParadasSobreBaseISO = 4096
  | | | | Valor de brillo = 17245
  | | | | Optimizador de rango dinámico = 1
  | | | | Configuración HDR = 0
  | | | | ExposiciónCompensación = 0
  | | | | Perfil de imagen = 0
  | | | | Perfil de imagen = 0
  | | | | Efecto de imagen2 = 0
  | | | | Calidad2 = 0
  | | | | Modo de medición = 0
  | | | | Programa de exposición = 1
  | | | | WB_RGBLevels = 690 256 427
  | | | | Longitud focal = 180
  | | | | Longitud focal mínima = 180
  | | | | Longitud focal máxima = 2000
  | | | | Sony ISO = 4096
  | | | | formato de lente = 1
  | | | | Montura de lente = 2
  | | | | LensType2 = 32787
  | | | 91) Sony_0x940f = liVi.$........)....@..f.........&....@...Y@)..Y@. @...........[recorte]
  | | | 92) Tag9050 (Subdirectorio) -->
  | | | + [directorio BinaryData, 944 bytes]
  | | | | FlashStatus = 64
  | | | | Número de imágenes = 3836
  | | | | SonyFNúmero = 5888
  | | | | Modo de liberación2 = 0
  | | | | ImageCount2 = 3836
  | | | | SonyDateTime2 = ....#.
  | | | | Modo de liberación2 = 0
  | | | | Número de serie interno = 162 254 226 13
  | | | | Montura de lente = 2
  | | | | formato de lente = 1
  | | | | LensType2 = 32787
  | | | | LensSpecFeatures = .
  | | | | ImageCount3 = 44765
  | | | 93) Sony_0x9412 = ...@.V......................................... ...............[recorte]
  | | 19) Comentario de usuario =
  | | 20) Versión Flashpix = 0100
  | | 21) Espacio de colores = 1
  | | 22) ExifImageAncho = 6000
  | | 23) ExifImageHeight = 4000
  | | 24) InteropOffset (Subdirectorio) -->
  | | + [Directorio InteropIFD con 2 entradas]
  | | | 0) Índice de interoperabilidad = R98
  | | | 1) Versión de interoperabilidad = 0100
  | | 25) Fuente del archivo = 3
  | | 26) Tipo de escena = 1
  | | 27) CustomRendered = 0
  | | 28) Modo de exposición = 0
  | | 29) Balance de blancos = 0
  | | 30) Relación de zoom digital = 1 (16/16)
  | | 31) Longitud focal en formato de 35 mm = 27
  | | 32) Tipo de captura de escena = 0
  | | 33) Contraste = 0
  | | 34) Saturación = 0
  | | 35) Nitidez = 0
  | | 36) LensInfo = 18 200 3,5 6,3 (180/10 2000/10 35/10 63/10)
  | | 37) Modelo de lente = E 18-200 mm F3.5-6.3 OSS
  | 12) ImprimirIM (Subdirectorio) -->
  | + [Directorio PrintIM con 3 entradas]
  | | ImprimirVersiónIM = 0300
  | | 0) ImprimirIM_0x0002 = 1
  | | 1) ImprimirIM_0x0003 = 34
  | | 2) ImprimirIM_0x0101 = 0
  + [Directorio IFD1 con 13 entradas]
  | 0) Compresión = 6
  | 1) Descripción de la imagen =                                
  | 2) Marca = SONY
  | 3) Modelo = ILCE-6000
  | 4) Orientación = 1
  | 5) Resolución X = 72 (72/1)
  | 6) YResolución = 72 (72/1)
  | 7) Unidad de resolución = 2
  | 8) Software = ILCE-6000 v3.20
  | 9) Fecha de modificación = 2018:05:11 08:35:11
  | 10) Desplazamiento de miniaturas = 38476
  | 11) Longitud de la miniatura = 6426
  | 12) Posicionamiento YCbCr = 2
JPEG APP1 (2825 bytes):
  + [directorio XMP, 2796 bytes]
  | XMPToolkit = XMP Core 4.4.0-Exiv2
  | Software = digiKam-5.6.0
  | CreatorTool = digiKam-5.6.0
  | Leyenda = Monumento Nacional Gran Cañón-Parashant, a lo largo de Clayhole Road
  | Título = Monumento Nacional Gran Cañón-Parashant, a lo largo de Clayhole Road
JPEG APP13 (126 bytes):
  + [directorio de Photoshop, 112 bytes]
  | Datos IPTC (Subdirectorio) -->
  | + [directorio IPTC, 99 bytes]
  | | CurrentIPTCDigest = ~.g..z....3P}R..
  | | -- Registro IPTCEnvelope --
  | | Conjunto de caracteres codificados = .%G
  | | -- Registro de aplicación IPTC --
  | | Programa de origen = digiKam
  | | Versión del programa = 5.6.0
  | | ObjectName = Monumento Nacional Grand Canyon-Parashant, a lo largo de Clayhole Roa
JPEG APP2 (156 bytes):
  + [directorio MPF0 con 3 entradas]
  | 0) Versión MPF ​​= 0100
  | 1) NúmeroDeImágenes = 2
  | 2) MPImageList (Subdirectorio) -->
  | + [directorio BinaryData, 16 bytes]
  | | MPImageFlags = 2684354560
  | | MPImageFormat = 0
  | | MPImageType = 196608
  | | MPImageLength = 8768466
  | | MPImageStart = 0
  | | DependentImage1EntryNumber = 2
  | | DependentImage2EntryNumber = 0
  | + [directorio BinaryData, 16 bytes]
  | | MPImageFlags = 1073741824
  | | MPImageFormat = 0
  | | MPImageType = 65538
  | | MPImageLength = 664145
  | | MPImageStart = 8724632
  | | DependentImage1EntryNumber = 0
  | | DependentImage2EntryNumber = 0
JPEG DQT (130 bytes):
JPEG DHT (416 bytes):
JPEG SOF0 (15 bytes):
  Ancho de imagen = 6000
  Altura de la imagen = 4000
  Proceso de codificación = 0
  Bits por muestra = 8
  Componentes de color = 3
JPEG S.O.S.
  Advertencia = [menor] Error al leer PreviewImage
  Imagen de vista previa = ESCALAR (0x19b5ab8)

¿Qué herramientas existen para eliminar automáticamente el polvo del sensor de forma digital de una gran serie de fotos? Tengo cientos de fotos afectadas (esencialmente cualquier cosa tomada en F/8 o menos). Es más evidente cuando la región afectada está en el cielo, por lo que una solución que funcione solo para el cielo es satisfactoria. Suponiendo que el polvo no se mueva demasiado lejos, debería ser posible usar algún tipo de técnica de combinación para calcular una nueva máscara para cada foto, antes de aplicarla usando pintura interna o algún otro método. Aunque en teoría es simple, implementar esto puede ser bastante laborioso en la práctica, y ni siquiera estoy seguro de si volver a pintar es una buena solución.

Aparte de reparar manualmente cada foto (toma 4 minutos de tiempo de cálculo solo en mi antiguo escritorio), qué herramientas existen para reparar toda mi serie de fotos (o al menos aquellas tomadas a F/8 o menos con cielo en las áreas afectadas) ?

Trabajo en Linux y mi kit de herramientas habitual consta de digikam, darktable, gimp y Python. La cámara es una Sony A6000 bastante nueva (cámara de sistema compacto/sin espejo). Algunas fotos se toman con una lente Sony OSS de 18–200 mm, otras con una lente manual Samyang de 12 mm.

Oh hombre, ¡otro trabajo para ML!
@mattdm ML = ¿Aprendizaje automático? ¡Supongo que lo es!
Sí. Estoy pensando que es hora de comenzar un grupo de apuestas para cuando este sitio se fusione con ai.stackexchange.com :)
@xiota He editado la pregunta: Sony A6000; Estoy bastante seguro de que es polvo del sensor porque se acumuló durante las vacaciones, se pudo ver con una lupa y desapareció después de una limpieza profesional del sensor. Supongo que es el polvo que se mueve en relación con el sensor, pero nunca antes había oído hablar de IBIS. ¿Alguna placa transparente frente al sensor que puede desplazarse entre 50 y 100 µm?
@xiota Soy nuevo en align_image_stackesto, ¡veré si me puede ayudar!
¿El cambio de estabilización de imagen está incluido en los metadatos? tal vez podrías usar eso para revertir la traducción del polvo. Alternativamente, ¿qué pasa con un script que le pide que ubique el mapa haciendo clic en el centro de la mancha de polvo más grande en cada imagen? Todavía tendría que hacer clic en cada imagen, pero eso sería un clic en lugar de cientos. También sugeriría el aprendizaje automático, pero creo que es un tema tabú en estas partes.
@PhotoScientist No sé si se incluyen detalles sobre la estabilización de imagen. Creo que no, pero agregué los encabezados exif completos a la pregunta. El guión puede ser una buena idea: si de hecho se debe a la estabilización de la imagen o algún tipo de corrección y no al movimiento del polvo, entonces el cambio de uno puede identificar de manera única el cambio de los demás. No sé por qué el aprendizaje automático sería un tema tabú, pero me temo que puedo caer en la trampa del problema general y que es menos trabajo realizar las correcciones manualmente.
@gerrit Creo que tienes razón. Parece probable que le llevaría menos tiempo encontrar la solución de aprendizaje automático más específica de lo que me ha llevado a mí escribir esto. No obstante, probablemente le llevará más tiempo implementarlo que editar manualmente cada foto y, por lo tanto, solo valdría la pena si le hiciera ganar dinero. Supongo que así es como se crea shareware en primer lugar. En cuanto a los temas tabú, solo trato de respetar la voluntad de la gente. Las soluciones de codificación para los problemas de las fotografías generalmente no son bien recibidas aquí.

Respuestas (1)

Algo como esto actualmente no tiene una solución técnica. Supongo que debe hacerlo manualmente o esperar una solución respaldada por AI/ML.

Dicho esto, puede lograr cierto éxito con esta herramienta:

http://www.batchcrop.com/eliminación-de-manchas-de-polvo.php

Cuesta 49$.

Terminé haciéndolo manualmente (con darktable), tomó mucho tiempo, ¡pero obtuve una buena y detallada vista de muchas fotos de vacaciones!