eliminar las anotaciones de píxeles en la imagen dicom

Estoy analizando imágenes médicas. Todas las imágenes tienen un marcador con la posición. Se parece a esto introduzca la descripción de la imagen aquí

Es la anotación “TRH RMLO” en esta imagen, pero puede ser diferente en otras imágenes. También varía el tamaño. La imagen está recortada, pero se ve que el tejido comienza en el lado derecho. Encontré que la presencia de estos marcadores distorsiona mi análisis.

¿Cómo puedo eliminarlos?

Cargo la imagen en python así.

import dicom import numpy as np img = dicom.read_file(my_image.dcm) img_array = img.pixel_array 

La imagen es entonces una matriz numpy. El texto en blanco siempre está rodeado por un área negra grande (el negro tiene valor cero). El marcador está en una posición diferente en cada imagen.

¿Cómo puedo eliminar el texto en blanco sin dañar los datos del tejido?

ACTUALIZAR

agregó una segunda imagen

introduzca la descripción de la imagen aquí

ACTUALIZACIÓN2 : Aquí están dos de los archivos originales de dicom. Toda la información personal ha sido eliminada.

Al observar los valores de píxeles reales de la imagen que proporcionó, puede ver que el marcador es casi blanco (99.99%) y esto no ocurre en ninguna otra parte de la imagen, por lo que puede aislarlo con un simple umbral de 99.99%.

Prefiero ImageMagick en la línea de comandos, así que haría esto:

 convert sample.dcm -threshold 99.99% -negate mask.png 

introduzca la descripción de la imagen aquí

 convert sample.dcm mask.png -compose darken -composite result.jpg 

introduzca la descripción de la imagen aquí

Por supuesto, si la imagen de muestra no es representativa, es posible que tenga que trabajar más. Veamos eso …

Si el umbral simple no funciona para sus imágenes, me gustaría ver “Hit and Miss Morphology” . Básicamente, tiene un umbral de su imagen a blanco y negro puro, aproximadamente el 90%, y luego busca formas específicas, como los marcadores de esquina en la etiqueta. Entonces, si queremos buscar la esquina superior izquierda de un rectángulo blanco sobre un fondo negro, y usamos 0 para indicar “este píxel debe ser negro” , 1 para indicar “este píxel debe ser blanco” y - para “No nos importa” , usaríamos este patrón:

 0 0 0 0 0 0 1 1 1 1 0 1 - - - 0 1 - - - 0 1 - - - 

Esperemos que pueda ver la esquina superior izquierda de un rectángulo blanco allí. Eso sería así en la Terminal:

 convert sample.dcm -threshold 90% \ -morphology HMT '5x5:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' result.png 

Ahora también queremos buscar las esquinas superior derecha, inferior izquierda e inferior derecha, por lo que necesitamos rotar el patrón, lo que ImageMagick hace fácilmente cuando agrega la bandera > :

 convert sample.dcm -threshold 90% \ -morphology HMT '5x5>:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' result.png 

introduzca la descripción de la imagen aquí

Esperamos que pueda ver puntos demarcando las esquinas del logotipo ahora, por lo que podríamos pedirle a ImageMagick que recorte la imagen de todos los negros extraños y simplemente deje los puntos blancos y luego nos diga el cuadro delimitador:

 cconvert sample.dcm -threshold 90% \ -morphology HMT '5x5>:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' -format %@ info: 308x198+1822+427 

Entonces, si dibujo un cuadro rojo alrededor de esas coordenadas, puedes ver dónde se ha detectado la etiqueta. Por supuesto, en la práctica dibujaría un cuadro negro para cubrirlo, pero te explico la idea:

 convert sample.dcm -fill "rgba(255,0,0,0.5)" -draw "rectangle 1822,427 2130,625" result.png 

introduzca la descripción de la imagen aquí

Si desea que un script lo haga de forma automática, usaría algo como esto, guardándolo como HideMarker :

 #!/bin/bash input="$1" output="$2" # Find corners of overlaid marker using Hit and Miss Morphology, then get crop box IFS="x+" read wh x1 y1 < <(convert "$input" -threshold 90% -morphology HMT '5x5>:0,0,0,0,0 0,1,1,1,1 0,1,-,-,- 0,1,-,-,- 0,1,-,-,-' -format %@ info:) # Calculate bottom-right corner from top-left and dimensions ((x1=x1-1)) ((y1=y1-1)) ((x2=x1+w+1)) ((y2=y1+h+1)) convert "$input" -fill black -draw "rectangle $x1,$y1 $x2,$y2" "$output" 

Entonces harías esto para hacerlo ejecutable:

 chmod +x HideMarker 

Y ejecútalo así:

 ./HideMarker someImage.dcm result.png 

Si estas anotaciones se encuentran en el archivo DICOM, hay un par de formas en que se pueden almacenar (consulte https://stackoverflow.com/a/4857782/1901261 ). El método actualmente soportado se puede eliminar simplemente eliminando los atributos del grupo 60xx de los archivos.

Para el método en desuso (que todavía se usa comúnmente) puede borrar las anotaciones de bits altos no utilizadas manualmente sin desordenar los otros datos de la imagen también. Algo como:

 int position = object.getInt( Tag.OverlayBitPosition, 0 ); if( position == 0 ) return; int bit = 1 << position; int[] pixels = object.getInts( Tag.PixelData ); int count = 0; for( int pix : pixels ) { int overlay = pix & bit; pixels[ count++ ] = pix - overlay; } object.putInts( Tag.PixelData, VR.OW, pixels ); 

Si realmente están grabados en los datos de la imagen, probablemente esté atascado usando una de las otras recomendaciones aquí.

Tengo otra idea. Esta solución está en OpenCV usando python. Es una solución más bien.

  1. En primer lugar, obtener el umbral binario de la imagen.

    ret,th = cv2.threshold(img,2,255, 0) introduzca la descripción de la imagen aquí

  2. Realizar dilatación morfológica:

dilate = cv2.morphologyEx(th, cv2.MORPH_DILATE, kernel, 3) introduzca la descripción de la imagen aquí

  1. Para unir las brechas, utilicé el filtrado de mediana:

median = cv2.medianBlur(dilate, 9) introduzca la descripción de la imagen aquí

Ahora puede usar las propiedades de contorno para eliminar el contorno más pequeño y retener el otro que contiene la imagen.

También funciona para la segunda imagen:

introduzca la descripción de la imagen aquí

Lo bueno es que estas marcas de agua están probablemente en un total aislado de negro, lo que lo hace más fácil (aunque es cuestionable si la eliminación se realiza de acuerdo con el uso indicado; licencia-cosas).

Sin ser un experto, aquí hay una idea . Puede ser un bosquejo de un enfoque muy poderoso adaptado a este problema, pero debe decidir si la complejidad de la implementación y la complejidad algorítmica (muy dependiente de las estadísticas de la imagen) valen la pena:

Idea básica

  • Detectar la semi-cruz como bordes (4)
  • Calcula el rectángulo definido a partir de estos
  • Apagar este rectángulo

Pasos

0

Binarizar

1

  • Utilice un detector de bordes basado en degradado para obtener todos los bordes horizontales
  • Puede haber múltiples; puede intentar dar una longitud mínima (tal vez se necesite alguna morfología para conectar los píxeles que no están conectados según el ruido en la fuente o el algoritmo)

2

  • Utilice un detector de bordes basado en degradado para obtener todos los bordes horizontales
  • Como la anterior, pero con una orientación diferente.

3

  • Realice algunos cálculos de componentes conectados para obtener algunos objetos que son líneas verticales y horizontales

  • Ahora puede probar diferentes opciones de componentes candidatos (8 reales) con los siguientes conocimientos

    • dos de estos componentes se pueden describir por la misma línea (forma de pendiente-intersección; problema de regresión lineal) -> línea que bordea el rectángulo
    • es probable que los mejores 4 pares de selección (según la pérdida de regresión lineal) sean los bordes válidos de este rectángulo
    • puede agregar el supuesto de que los bordes verticales y horizontales son ortogonales entre sí

4 – Calcule el rectángulo a partir de estos bordes – Amplíelo por unos pocos píxeles (hiper-parámetro) – Ennegrezca ese rectángulo

Ese es el enfoque básico.

Alternativa

Este es mucho menos trabajo, usa herramientas más especializadas y asume los hechos en la apertura:

  • Lo que hay que eliminar está en una parte completamente negra de la imagen.
  • es un poco aislado La distancia a los datos médicos es alta.

Pasos

  • Ejecutar un OCR general para detectar personajes
  • Obtener los píxeles / bordes ocupados de alguna manera (no estoy seguro de qué devuelven las herramientas OCR)
  • Calcule algunos rectangularjs exteriores y oscurecimiento (usando un espacio de ampliación predefinido; este debe ser mucho más grande que el de arriba)

Alternativa 2

Solo boceto: la idea es usar algo como el cierre binario en la imagen de alguna manera para construir componentes completamente conectados de los píxeles de origen (mientras se llenan pequeños huecos / huecos), de modo que tenemos un gran componente que describe los datos médicos y uno para la marca de agua. Luego solo quita el más pequeño.

El marcador está en una posición diferente en cada imagen.

Mis suposiciones:

  1. El marcador siempre es texto.
  2. El marcador no está dentro del tejido.

=> Sugerencia:

  1. Encuentre la ubicación con OCR (por ejemplo, localmente con Tesseract, o use una API en línea como OCR.space ). Obtendrá el cuadro delimitador de las palabras devueltas como JSON:

      "TextOverlay" : { "Lines" : [ { "Words": [ { "WordText": "RMLO", "Left": 106, "Top": 91, "Height": 9, "Width": 11 }, 
  2. Ahora que tiene las coordenadas, puede oscurecer el rectángulo.

Esta solución se corresponde con la segunda opción de Sascha.

Estoy seguro de que esto puede optimizarse, pero … Podría crear 4 parches de tamaño 3×3 o 4×4 e inicializarlos con el contenido exacto de los valores de píxeles para cada una de las esquinas individuales del marco que rodea el texto de la anotación. Luego puede iterar sobre toda la imagen (o hacer que una inicialización inteligente busque solo en el área negra) y encontrar la coincidencia exacta para esos parches. No es muy probable que tenga la misma estructura regular (esquina de 90 grados rodeada por casi 0) en el tejido, por lo que esto podría darle el cuadro delimitador.

Todavía es posible uno más simple.

Solo implementa el siguiente después (img_array = img.pixel_array)

img_array [img_array> X] = Y

En el que X es el umbral de intensidad que desea eliminar después de eso. También Y es el valor de intensidad que desea considerar en lugar de eso.

Por ejemplo: img_array [img_array> 4000] = 0

Reemplace la materia blanca mayor que 4000 con intensidad negra 0.