Fundamentos de Opencv 60- Uso del algoritmo Watershed cv2.distanceTransform() para realizar la segmentación de imágenes y principios y ejemplos de extracción

En el proceso de procesamiento de imágenes, a menudo es necesario segmentar o extraer un objeto de primer plano como imagen objetivo de una imagen. Por ejemplo, en videovigilancia lo que observamos es el contenido del vídeo bajo un fondo fijo, pero no nos interesa el fondo en sí, sino los vehículos, peatones u otros objetos que aparecen en el fondo. Queremos extraer estos objetos del video e ignorar el contenido del video donde no hay objetos en segundo plano.

En los capítulos anteriores, discutimos cómo segmentar imágenes utilizando métodos como transformaciones morfológicas de imágenes, algoritmos de umbral, pirámides de imágenes, contornos de imágenes, detección de bordes, etc. Esta sección presenta el uso del algoritmo de cuenca hidrográfica y el algoritmo GrabCut para segmentar y extraer imágenes.

Principio del algoritmo

González hizo un análisis detallado y una introducción del algoritmo de cuenca hidrográfica en el libro "Procesamiento de imágenes digitales". El sitio web oficial de OpenCV recomienda que los alumnos lean la introducción y la demostración animada del algoritmo de cuenca hidrográfica en el sitio web CMM (Centro de morfología matemática) del Laboratorio de procesamiento de imágenes de MINES ParisTech.

La siguiente es una breve introducción al contenido relevante del algoritmo de cuenca hidrográfica.

Cualquier imagen en escala de grises se puede considerar como una superficie topográfica geográfica. Las áreas con valores altos de escala de grises se pueden considerar picos de montañas, y las áreas con valores bajos de escala de grises se pueden considerar valles. Como se muestra en la Figura 17-1, la imagen de la izquierda es la imagen original y la imagen de la derecha es su correspondiente "superficie del terreno".

Si "infundimos" agua de diferentes colores en cada valle (aquí se usa el sitio web oficial de OpenCV, González expresa la infusión como hacer un agujero en el valle y luego dejar que el agua suba a través del agujero a un ritmo uniforme). Luego, a medida que el nivel del agua continúa subiendo, el agua de diferentes valles se unirá. En este proceso, para evitar que el agua de los diferentes valles converja, necesitamos construir diques donde se puedan encontrar los flujos de agua. Este proceso separa las imágenes en dos conjuntos distintos: cuencas de captación y líneas divisorias de aguas. Los diques que construimos son las líneas divisorias de aguas, que son la segmentación de la imagen original. Este es el algoritmo de la cuenca hidrográfica.

inserte la descripción de la imagen aquí
En la Figura 17-2, la imagen de la izquierda es la imagen original y la imagen de la derecha es el resultado de la segmentación de la imagen obtenido mediante el algoritmo de cuenca hidrográfica. El sitio web de CMM no solo proporciona la imagen de muestra, sino que también proporciona efectos de demostración de animación, los lectores interesados ​​pueden visitar el sitio web para echar un vistazo.

inserte la descripción de la imagen aquí
Debido a la influencia del ruido y otros factores, el algoritmo básico de cuenca hidrográfica mencionado anteriormente a menudo da como resultado una segmentación excesiva. La sobresegmentación dividirá la imagen en pequeños bloques densos independientes, haciendo que la segmentación no tenga sentido.

La figura 17-3 muestra una imagen demasiado segmentada. La imagen de la izquierda es la imagen de la electroforesis, y la imagen de la derecha es la imagen resultante de la sobresegmentación.Se puede ver que el fenómeno de la sobresegmentación es muy grave.

inserte la descripción de la imagen aquí

Para mejorar el efecto de la segmentación de imágenes, se propone un algoritmo mejorado de cuenca hidrográfica basado en máscara. El algoritmo de cuenca hidrográfica mejorado permite al usuario marcar lo que considera que es la misma área segmentada (la parte marcada se denomina máscara). De esta forma, cuando el algoritmo de cuencas hidrográficas esté procesando, procesará la parte etiquetada como la misma área segmentada.
Puede intentar usar la función "eliminar fondo" en Microsoft PowerPoint para profundizar su comprensión de este algoritmo mejorado.

En la Figura 17-4, la imagen de la izquierda es la imagen original, que marcamos, y los tres pequeños bloques de color marcados como color oscuro indican: al usar el algoritmo de cuenca de máscara, los colores contenidos en estas partes se dividirán en la misma área. El resultado de la segmentación obtenido mediante el uso del algoritmo de cuenca hidrográfica de máscara se muestra en la figura de la derecha en la Figura 17-4.

inserte la descripción de la imagen aquí

Utilice el algoritmo de cuenca hidrográfica mejorado para enmascarar la imagen electroforética de la izquierda en la Figura 17-5 y obtenga el resultado de la segmentación a la derecha. Se puede observar que los resultados de la segmentación mejoran significativamente.

inserte la descripción de la imagen aquí

Introducción a la función cv2.watershed()

En OpenCV, la función cv2.watershed() se puede usar para implementar el algoritmo de cuenca hidrográfica. En el proceso de implementación específico, también es necesario
completar la segmentación de la imagen con la ayuda de funciones morfológicas y funciones de transformación de distancia cv2.distanceTransform() y cv2.connectedComponents(). La siguiente es una breve descripción de las funciones utilizadas en el algoritmo de cuenca hidrográfica.

1. Revisión de funciones morfológicas

Antes de usar el algoritmo de cuenca hidrográfica para segmentar la imagen, es necesario realizar un procesamiento morfológico simple en la imagen. Primero repasar las operaciones básicas en morfología.
(1) Operación de apertura
La operación de apertura es una operación de erosión primero y luego de dilatación, y la operación de apertura puede eliminar el ruido de la imagen. Por ejemplo, en la figura 17-6, si primero se corroe la imagen de la izquierda, se obtendrá la imagen del medio y luego se dilatará la imagen del medio para obtener la imagen de la derecha. Después de abrir la imagen de la izquierda (primero la corrosión, luego la dilatación), obtenemos la imagen de la derecha.

Se puede ver a partir de la observación que después de que la imagen de la izquierda se convierte en la imagen de la derecha después de la operación de apertura, se han eliminado las rebabas (información de ruido) en ella.

inserte la descripción de la imagen aquí
Abrir la imagen puede eliminar el ruido de la imagen. Antes de utilizar el algoritmo de cuenca hidrográfica para procesar la imagen, se debe eliminar el ruido de la imagen mediante la operación abierta, para evitar la posible interferencia causada por el ruido en la segmentación de la imagen.

(2) Obtención del límite de la imagen
El límite de la imagen puede obtenerse mediante operaciones morfológicas y operaciones de sustracción.

Por ejemplo, en la figura 17-7, la imagen de la izquierda es la imagen original y la imagen del medio es la imagen obtenida al corroerla.Restar las dos da como resultado la imagen de la derecha. Se puede ver a partir de la observación que la imagen de la derecha es el límite de la imagen de la izquierda.

inserte la descripción de la imagen aquí

Ejemplo: Utilice la transformación morfológica para obtener la información de los límites de una imagen y observe el efecto.

Imagen original:

inserte la descripción de la imagen aquí

import cv2
import numpy as np
import matplotlib.pyplot as plt
o=cv2.imread("rice.png",cv2.IMREAD_UNCHANGED)
#构造一个5*5的结构元素
k=np.ones((5,5),np.uint8)
#腐蚀
e=cv2.erode(o,k)
#膨胀
b=cv2.subtract(o,e)

plt.subplot(131)
plt.imshow(o)
plt.axis('off')
plt.subplot(132)
plt.imshow(e)
plt.axis('off')
plt.subplot(133)
plt.imshow(b)
plt.axis('off')
plt.show()

resultado de la operación:

inserte la descripción de la imagen aquí
La imagen de la izquierda es la imagen original, la imagen del medio es
la imagen obtenida al corroerla y la imagen de la derecha es la imagen límite obtenida al restar la imagen corroída de la imagen original. Se puede ver que la imagen de la derecha muestra con mayor precisión la información de los límites del objeto de primer plano en la imagen de la izquierda.

Del análisis anterior, se puede ver que la información de los límites de la imagen se puede obtener usando la operación morfológica y la operación de resta. Sin embargo, las operaciones morfológicas solo son aplicables a imágenes relativamente simples. Si los objetos de primer plano de la imagen están conectados, los límites de cada subimagen no se pueden obtener con precisión mediante operaciones morfológicas.

2. La función de transformación de distancias distanceTransform

Cuando los subgráficos de la imagen no están conectados, el objeto de primer plano se puede determinar directamente mediante la operación de erosión morfológica, pero si los subgráficos de la imagen están conectados entre sí, es difícil determinar el objeto de primer plano. En este punto,
el objeto en primer plano se puede extraer fácilmente mediante la función de transformación de distancia cv2.distanceTransform().

La transformación de distancia 函数 cv2.distanceTransform()calcula la distancia desde cualquier punto de la imagen binaria hasta el punto de fondo más cercano. En general, esta función calcula la distancia desde un píxel de valor distinto de cero en la imagen hasta el píxel de valor cero más cercano, es decir, calcula la distancia entre todos los píxeles de la imagen binaria y su píxel más cercano con un valor de 0. Por supuesto, si el valor del píxel en sí es 0, entonces esta distancia también es 0.

El resultado del cálculo de la función de transformación de distancia cv2.distanceTransform() refleja la
relación de distancia entre cada píxel y el fondo (el píxel con un valor de 0). generalmente:

  • Si el centro (centroide) del objeto de primer plano está más alejado de un píxel con un valor de 0, obtendrá un valor mayor.
  • Si el borde del objeto de primer plano está más cerca del píxel con un valor de 0, obtendrá un valor más pequeño.

Si los resultados de los cálculos anteriores tienen un umbral, se puede obtener información como el centro y el esqueleto de la subimagen en la imagen. La función de transformación de distancia cv2.distanceTransform() se puede usar para calcular el centro del objeto y también puede refinar el contorno, obtener el primer plano de la imagen, etc., y tiene muchas funciones.
El formato de sintaxis de la función de transformación de distancia cv2.distanceTransform() es:

dst=cv2.distanceTransform(origen, tipodistancia, tamaño de máscara[, tipodst]])

En la fórmula:

  • src es una imagen binaria de un solo canal de 8 bits.
  • distanceType es el parámetro de tipo de distancia, y su valor y significado específicos se muestran en la Tabla 17-1.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

  • maskSize es el tamaño de la máscara, y sus posibles valores se muestran en la Tabla 17-2. Tenga en cuenta que cuando distanceType = cv2.DIST_L1 o cv2.DIST_C, maskSize debe ser 3 (porque no hay diferencia entre configurarlo en 3 y configurarlo en 5 o más).

inserte la descripción de la imagen aquí

  • dstType es el tipo de imagen de destino, el valor predeterminado es CV_32F.
  • dst representa la imagen de destino calculada, que puede ser un número de punto flotante de 8 o 32 bits, y su tamaño es el mismo que el de src.

Ejemplo: use la función de transformación de distancia cv2.distanceTransform() para calcular el primer plano de una imagen y observar el efecto.

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('water_coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
ishow=img.copy()
#对图像阈值化处理,得到二值图像,黑色背景,白色前景,前景为我们要提取的目标,背景为0,前景为1
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
#定义一个3*3的卷积核,卷积核的作用是将前景与背景分离
kernel = np.ones((3,3),np.uint8)
#对二值图像进行开运算,去除噪声,开运算是先腐蚀再膨胀的过程,它可以去除小的干扰块,平滑较大的对象边界,同时并不明显改变其面积
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
#距离变换,得到每一个前景像素点到最近的背景像素点的距离,然后对其进行阈值化处理,得到的结果就是前景
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
#对膨胀后的图像进行阈值化处理,得到前景,前景为我们要提取的目标,背景为0,前景为1,这样就得到了我们要提取的目标,但是目标并不连续
ret, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

plt.subplot(131)
plt.imshow(ishow)
plt.axis('off')
plt.subplot(132)
plt.imshow(dist_transform)
plt.axis('off')
plt.subplot(133)
plt.imshow(fore)
plt.axis('off')
plt.show()

El resultado es el siguiente:

inserte la descripción de la imagen aquí

  • La imagen de la izquierda es la imagen original.
  • La del medio es la imagen de distancia calculada por la función de transformación de distancia cv2.distanceTransform().
  • La imagen de la derecha es la imagen resultante después de establecer el umbral de la imagen de distancia.

La imagen de la derecha muestra con mayor precisión el "primer plano determinado" en la imagen de la izquierda. El primer plano determinado aquí generalmente
se refiere al centro del objeto en primer plano. La razón por la que estos puntos se consideran el primer plano es que están lo suficientemente lejos de los puntos de fondo, y todos son puntos cuya distancia es mayor que un umbral fijo suficientemente grande (0.7*dist_transform.max()).

3. Identifica regiones desconocidas

El primer plano dentro de una imagen se puede "dilatar" mediante una operación de dilatación morfológica. Cuando se amplía el primer plano de la imagen, el fondo se "comprimirá", por lo que la información de fondo obtenida en este momento debe ser más pequeña que el fondo real y no incluye el "fondo determinado" del primer plano.

De aquí en adelante, el fondo de determinación se denomina B para facilitar la descripción. La función de transformación de distancia cv2.distanceTransform()puede obtener el "centro" de la imagen para obtener el "primer plano determinado". Para facilitar la descripción, el primer plano determinado se denomina F. Con el primer plano F determinado y el fondo B determinado en la imagen, el área restante es el área desconocida UN.
Esta parte del área es exactamente el área que será definida más adelante por el algoritmo de la cuenca hidrográfica.
Para una imagen O, el área desconocida UN se puede obtener a través de la siguiente relación:

Área desconocida UN = imagen O - determinar el fondo B - determinar el primer plano F

Ordenando las expresiones anteriores, podemos obtener:

Área desconocida UN = (imagen O - determinar el fondo B) - determinar el primer plano F

La "imagen O - determinar el fondo B" en la fórmula anterior se puede obtener realizando una operación de expansión morfológica en la imagen.

Ejemplo: anotar cierto primer plano, cierto fondo y regiones desconocidas de una imagen.

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('water_coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
ishow=img.copy()
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
#对图像进行膨胀操作,得到背景
bg = cv2.dilate(opening,kernel,iterations=3)

dist = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, fore = cv2.threshold(dist,0.7*dist.max(),255,0)
fore = np.uint8(fore)
un = cv2.subtract(bg,fore)
plt.subplot(221)
plt.imshow(ishow)
plt.axis('off')
plt.subplot(222)
plt.imshow(bg)
plt.axis('off')
plt.subplot(223)
plt.imshow(fore)
plt.axis('off')
plt.subplot(224)
plt.imshow(un)
plt.axis('off')
plt.show()

resultado de la operación:

inserte la descripción de la imagen aquí

  • En la esquina superior izquierda se muestra la imagen original.
  • La esquina superior derecha es la imagen bg obtenida después de inflar la imagen isow, la imagen de fondo es el fondo definido y la imagen de primer plano es la "imagen original - fondo definido".
  • La esquina inferior izquierda es para determinar la imagen de primer plano.
  • El pequeño círculo de la imagen en la esquina inferior derecha es la imagen de la región desconocida un, que se obtiene restando la imagen bg y la imagen anterior. Es decir, la imagen de la región desconocida un se deriva del "primer plano determinado por el fondo determinado por la imagen original".

4. Función componentes conectados

Después de determinar el primer plano determinado, se puede marcar la imagen de primer plano determinada. En OpenCV, las funciones están disponibles
cv2.connectedComponents()进行标注. Esta función marcará el fondo como 0 y marcará otros objetos con números enteros positivos a partir de 1.
El formato de sintaxis de la función cv2.connectedComponents() es:

retval, etiquetas = cv2.connectedComponents(imagen)

En la fórmula:

  • image es una imagen de un solo canal de 8 bits que se va a etiquetar.
  • retval es el número de etiquetas devueltas.
  • etiquetas es la imagen de resultado etiquetada.

Ejemplo: use la función cv2.connectedComponents() para anotar una imagen y observar el efecto de la anotación.

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('water_coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
ishow=img.copy()
ret, thresh = cv2.threshold(gray,0,255,
cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
sure_bg = cv2.dilate(opening,kernel,iterations=3)
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
fore = np.uint8(fore)
ret, markers = cv2.connectedComponents(fore)
print(markers)
plt.subplot(131)
plt.imshow(ishow)
plt.axis('off')
plt.subplot(132)
plt.imshow(fore)
plt.axis('off')
plt.subplot(133)
plt.imshow(markers)
plt.axis('off')
print(ret)
plt.show()

resultado de la operación:

  • La imagen de la izquierda es la imagen original que se muestra.
  • La del medio es la imagen del punto central delante de la imagen de primer plano obtenida después de la transformación de distancia.
  • La imagen de la derecha son los marcadores de imagen resultantes después de etiquetar la imagen del punto central de la imagen de primer plano.
    Se puede ver que el punto central de la imagen de primer plano se marca de manera diferente. inserte la descripción de la imagen aquí
    Cuando la función cv2.connectedComponents() marca la imagen, marcará el fondo como 0 y
    marcará otros objetos con números enteros positivos a partir de 1. La relación específica correspondiente es:
  • Un valor de 0 representa el área de fondo.
  • Los valores a partir de 1 representan diferentes regiones de primer plano.
    En el algoritmo de cuenca hidrográfica, un valor de etiqueta de 0 representa una región desconocida. Por lo tanto, debemos ajustar los resultados marcados por la función cv2.connectedComponents(): agregue el valor 1 a los resultados marcados. Después del procesamiento anterior, en el resultado del etiquetado:
  • Un valor de 1 representa el área de fondo.
  • Los valores a partir de 2 representan diferentes regiones de primer plano.

Para poder utilizar el algoritmo de cuenca hidrográfica, también es necesario marcar el área desconocida en la imagen original y marcar el área desconocida calculada como 0.
El código clave aquí es:

ret, markers = cv2.connectedComponents(fore)
markers = markers+1
markers[未知区域] = 0

Ejemplo: use la función cv2.connectedComponents() para marcar una imagen y corregirla para que el área desconocida se marque como 0 y observe el efecto de la marca.

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('water_coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
ishow=img.copy()
ret, thresh = cv2.threshold(gray,0,255,
cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
sure_bg = cv2.dilate(opening,kernel,iterations=3)
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
fore = np.uint8(fore)
ret, markers1 = cv2.connectedComponents(fore)
foreAdv=fore.copy()
unknown = cv2.subtract(sure_bg,foreAdv)
ret, markers2 = cv2.connectedComponents(foreAdv)
markers2 = markers2+1
markers2[unknown==255] = 0
plt.subplot(121)
plt.imshow(markers1)
plt.axis('off')
plt.subplot(122)
plt.imshow(markers2)
plt.axis('off')
plt.show()

resultado de la operación:

inserte la descripción de la imagen aquí

Comparando las imágenes izquierda y derecha, se puede ver que la imagen derecha está marcada en el borde (área desconocida) de la imagen de primer plano, de modo que cada primer plano determinado tiene un borde negro, que es el área desconocida marcada.

Función de algoritmo de cuenca hidrográfica cv2.watershed()

Una vez que se completa el procesamiento anterior, la imagen del resultado del preprocesamiento se puede segmentar utilizando el algoritmo de cuenca hidrográfica. En OpenCV, la función que implementa el algoritmo watershed es cv2.watershed(), y su formato de sintaxis es:

marcadores = cv2.watershed(imagen, marcadores)

En la fórmula:

  • image es la imagen de entrada, que debe ser una imagen de tres canales de 8 bits. Antes de usar la función cv2.watershed() en la imagen , el área segmentada deseada en la imagen debe delinearse aproximadamente con un número positivo. Cada región segmentada se etiquetará como 1, 2, 3, etc. Para las áreas que no han sido determinadas, deben marcarse como 0. Podemos entender el área marcada como el área "semilla" para la segmentación del algoritmo de cuenca hidrográfica.
  • marcadores es un resultado de anotación de un solo canal de 32 bits y debe tener el mismo tamaño que la imagen. En los marcadores, cada píxel se establece en un "valor semilla" inicial o se establece en "-1" para los límites. se pueden omitir los marcadores.

Cuando se utiliza el algoritmo de cuenca hidrográfica para la segmentación de imágenes, los pasos básicos son:

  1. La imagen original O se elimina del ruido mediante una operación de apertura morfológica.
  2. Obtener "fondo determinado B" por la operación de grabado. Cabe señalar que aquí es suficiente obtener la "imagen original: determinar el fondo".
  3. Utilice la función de transformación de distancia cv2.distanceTransform() para operar en la imagen original y realice un procesamiento de umbral en ella
    para obtener un "primer plano determinado F".
  4. Calcule la región desconocida UN (UN = O –B – F).
  5. Use la función cv2.connectedComponents() para anotar la imagen original O.
  6. Corrija el resultado de la anotación de la función cv2.connectedComponents().
  7. La segmentación de la imagen se realiza mediante la función de cuenca hidrográfica.

Ejemplo de código: utilice el algoritmo de cuenca hidrográfica para segmentar una imagen y observar el efecto de segmentación.

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('water_coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
ishow=img.copy()
ret, thresh = cv2.threshold(gray,0,255,
cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
sure_bg = cv2.dilate(opening,kernel,iterations=3)
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers+1
markers[unknown==255] = 0
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]
plt.subplot(121)
plt.imshow(ishow)
plt.axis('off')
plt.subplot(122)
plt.imshow(img)
plt.axis('off')
plt.show()

resultado de ejecución:

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/hai411741962/article/details/132228072
Recomendado
Clasificación