Introducción
Análisis y mapeo de imágenes en Earth Engine usando NDVI “, ahora es otro artículo sobre análisis de imágenes nuevamente. A diferencia del artículo anterior, este artículo analiza general análisis de imágenes, no Imagen de satélite análisis. El objetivo de esta discusión es detectar si dos productos son iguales o no. Cada uno de los dos productos tiene nombres de imagen y texto. Si el par de productos tiene imágenes o nombres de texto similares o iguales, eso significa que los dos productos son iguales. Los datos provienen de una competencia celebrada en Kaggle.
Hay 4 paquetes básicos utilizados en este script: NumPy, pandas, matplotlib y seaborn. También existen otros paquetes específicos. «Imagen» carga y muestra datos de imagen. «Imagehash» calcula la similitud de dos imágenes. «Fuzzywuzzy» detecta la similitud de dos textos. La «métrica» del paquete calcula la puntuación de precisión de la etiqueta verdadera y la etiqueta predicha.
# import packages import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from PIL import Image import imagehash from fuzzywuzzy import fuzz from sklearn.tree import DecisionTreeClassifier from sklearn import metrics
Similitud de imagen
La similitud de las dos imágenes se detecta mediante el paquete «imagehash». Si dos imágenes son idénticas o casi idénticas, la diferencia de hash de imagen será 0. Dos imágenes son más similares si la diferencia de hash de imagen está más cerca de 0.
La comparación de la similitud de dos imágenes con imagehash consta de 5 pasos. (1) Las imágenes se convierten a escala de grises. (2) Los tamaños de imagen se reducen para ser más pequeños, por ejemplo, a 8 × 8 píxeles de forma predeterminada. (3) Se calcula el valor medio de los 64 píxeles. (4) Se comprueba si los 64 píxeles son mayores que el valor medio. Ahora, cada uno de los 64 píxeles tiene un valor booleano de verdadero o falso. (5) La diferencia entre imágenes es el número de valores diferentes entre las dos imágenes. Observe la siguiente ilustración.
Image_1 (promedio: 71,96875)
48 | 20 | 34 | 40 | 40 | 32 | 30 | 32 |
34 | 210 | 38 | 50 | 42 | 41 | 230 | 40 |
47 | 230 | 33 | 44 | 34 | 50 | 245 | 50 |
43 | 230 | 46 | 50 | 36 | 34 | 250 | 30 |
30 | 200 | 190 | 38 | 41 | 240 | 39 | 39 |
38 | 7 | 200 | 210 | 220 | 240 | 50 | 48 |
48 | 8 | 45 | 43 | 47 | 37 | 37 | 47 |
10 | 8 | 6 | 5 | 6 | 6 | 5 | 5 |
FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO |
FALSO | CIERTO | FALSO | FALSO | FALSO | FALSO | CIERTO | FALSO |
FALSO | CIERTO | FALSO | FALSO | FALSO | FALSO | CIERTO | FALSO |
FALSO | CIERTO | FALSO | FALSO | FALSO | FALSO | CIERTO | FALSO |
FALSO | CIERTO | CIERTO | FALSO | FALSO | CIERTO | FALSO | FALSO |
FALSO | FALSO | CIERTO | CIERTO | CIERTO | CIERTO | FALSO | FALSO |
FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO |
FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO |
Image_2 (promedio: 78,4375)
41 | 20 | 39 | 43 | 34 | 39 | 30 | 32 |
35 | 195 | 44 | 46 | 35 | 48 | 232 | 40 |
30 | 243 | 38 | 31 | 34 | 46 | 213 | 50 |
49 | 227 | 44 | 33 | 35 | 224 | 230 | 30 |
46 | 203 | 225 | 44 | 46 | 181 | 184 | 40 |
38 | 241 | 247 | 220 | 228 | 210 | 36 | 38 |
42 | 8 | 35 | 39 | 47 | 31 | 41 | 21 |
3 | 12 | 10 | 18 | 24 | 21 | 6 | 17 |
FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO |
FALSO | CIERTO | FALSO | FALSO | FALSO | FALSO | CIERTO | FALSO |
FALSO | CIERTO | FALSO | FALSO | FALSO | FALSO | CIERTO | FALSO |
FALSO | CIERTO | FALSO | FALSO | FALSO | CIERTO | CIERTO | FALSO |
FALSO | CIERTO | CIERTO | FALSO | FALSO | CIERTO | CIERTO | FALSO |
FALSO | CIERTO | CIERTO | CIERTO | CIERTO | CIERTO | FALSO | FALSO |
FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO |
FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO | FALSO |
La diferencia de imagen hash de las dos imágenes / matrices anteriores es 3. Significa que hay 3 píxeles con diferentes valores booleanos. Las dos imágenes son relativamente similares.
Para mayor claridad, examinemos el hash de imagen aplicado a los siguientes 3 pares de imágenes. El primer par consta de dos imágenes iguales y la diferencia entre imágenes es 0. El segundo par compara dos imágenes similares. La segunda imagen (image_b) es en realidad una versión editada de la primera imagen (image_a). La diferencia entre imágenes es 6. El último par muestra la comparación de dos imágenes totalmente diferentes. La diferencia de imagen hash es 30, que es la más alejada de 0.
# First pair
hash1 = imagehash.average_hash(Image.open('D: /image_a.jpg'))
hash2 = imagehash.average_hash(Image.open('D:/ image_a.jpg'))
diff = hash1 - hash2
print(diff)
# 0
# Second pair hash1 = imagehash.average_hash(Image.open('D: /image_a.jpg')) hash2 = imagehash.average_hash(Image.open('D:/ image_b.jpg')) diff = hash1 - hash2 print(diff) # 6
# Third pair hash1 = imagehash.average_hash(Image.open('D: /image_a.jpg')) hash2 = imagehash.average_hash(Image.open('D:/ image_c.jpg')) diff = hash1 - hash2 print(diff) # 30
Así es como se ve el hash de imagen promedio
>imagehash.average_hash(Image.open('D:/image_a.jpg')) array([[ True, True, True, True, True, True, True, True], [ True, True, True, True, True, True, True, True], [ True, True, True, True, True, True, True, True], [False, True, False, False, False, False, False, False], [ True, True, False, False, False, False, False, False], [False, False, False, True, False, False, False, False], [False, False, False, True, False, False, False, False], [False, False, False, False, False, False, False, False]])
>imagehash.average_hash(Image.open('D:/image_b.jpg')) array([[ True, True, True, True, True, True, True, True], [ True, True, True, True, True, True, True, True], [False, True, True, True, True, False, False, False], [ True, True, True, False, False, False, False, False], [ True, True, False, False, False, False, False, False], [False, False, False, True, False, False, False, False], [False, False, False, True, False, False, False, False], [False, False, False, False, False, False, False, False]])
>imagehash.average_hash(Image.open('D:/image_c.png')) array([[False, False, False, False, False, False, False, False], [ True, True, True, True, True, True, True, True], [ True, True, True, True, True, True, True, True], [ True, True, True, True, True, True, True, True], [ True, True, True, True, True, True, True, True], [ True, True, True, True, True, True, True, True], [False, False, False, False, True, False, False, False], [False, False, False, False, False, False, False, False]])
Similitud de texto
La similitud de texto se puede evaluar mediante el procesamiento del lenguaje natural (PNL). Hay 4 formas de comparar la similitud de un par de textos proporcionados por el paquete «fuzzywuzzy». La función de este paquete devuelve un valor entero de 0 a 100. El valor más alto significa la similitud más alta.
1. fuzz.ratio – es la comparación más simple de los textos. El valor fuzz.ratio de «camisa azul» y «camisa azul». es 95. Significa que los dos textos son similares o casi iguales, pero el punto los hace un poco diferentes
from fuzzywuzzy import fuzz fuzz.ratio('blue shirt','blue shirt.') #95
La medición se basa en la distancia de Levenshtein (llamada así por Vladimir Levenshtein). La distancia de Levenshtein mide qué tan similares son dos textos. Mide el número mínimo de ediciones, como insertar, eliminar o sustituir un texto en otro texto. El texto «Camisa azul» requiere sólo una edición para ser «camisa azul». Solo necesita un solo punto para ser el mismo. Por tanto, la distancia de Levenshtein es «1». La relación fuzz se calcula con esta ecuación (len (a) + len (b) – lev) / ((len (a) + len (b), donde len (a) y len (b) son las longitudes de primer y segundo texto, y lev es la distancia de Levenshtein La relación es (10 + 11 – 1) / (10 + 11) = 0,95 o 95%.
2. fuzz.partial_ratio: puede detectar si un texto es parte de otro texto. Pero no puede detectar si el texto está en un orden diferente. El siguiente ejemplo muestra que «camisa azul» es parte de «camisa azul limpia», por lo que fuzz.partial_ratio es 100. fuzz.ratio devuelve el valor 74 porque solo detecta que hay mucha diferencia entre los dos textos.
print(fuzz.ratio('blue shirt','clean blue shirt.')) #74 print(fuzz.partial_ratio('blue shirt','clean blue shirt.')) #100
3. Token_Sort_Ratio: puede detectar si un texto es parte de otro texto, aunque estén en un orden diferente. Fuzz.token_sort_ratio devuelve 100 para el texto «sombrero limpio y camisa azul» y «camisa azul y sombrero limpio» porque en realidad significan lo mismo, pero están en orden inverso.
print(fuzz.ratio('clean hat and blue shirt','blue shirt and clean hat')) #42 print(fuzz.partial_ratio('clean hat and blue shirt','blue shirt and clean hat')) #42 print(fuzz.token_sort_ratio('clean hat and blue shirt','blue shirt and clean hat')) #100
4. Token_Set_Ratio: puede detectar la similitud de texto teniendo en cuenta el texto parcial, el orden del texto y diferentes longitudes de texto. Puede detectar que el texto “sombrero limpio” y “camisa azul” es parte del texto “La gente quiere usar camisa azul y sombrero limpio” en un orden diferente. En este estudio, solo usamos “Token_Set_Ratio” ya que es el más adecuado.
print(fuzz.ratio('clean hat and blue shirt','People want to wear blue shirt and clean hat')) #53 print(fuzz.partial_ratio('clean hat and blue shirt','People want to wear blue shirt and clean hat')) #62 print(fuzz.token_sort_ratio('clean hat and blue shirt','People want to wear blue shirt and clean hat')) #71 print(fuzz.token_set_ratio('clean hat and blue shirt','People want to wear blue shirt and clean hat')) #100
La siguiente celda cargará el conjunto de datos de entrenamiento y agregará características de hash, así como la proporción del conjunto de tokens.
# load training set trainingSet = pd.read_csv('D:/new_training_set.csv', index_col=0).reset_index() # Compute imagehash difference hashDiff = [] for i in trainingSet.index: hash1 = imagehash.average_hash(Image.open(path_img + trainingSet.iloc[i,2])) hash2 = imagehash.average_hash(Image.open(path_img + trainingSet.iloc[i,4])) diff = hash1 - hash2 hashDiff.append(diff) trainingSet = trainingSet.iloc[:-1,:] trainingSet['hash'] = hashDiff # Compute token_set_ratio Token_tes = [] for i in trainingSet.index: TokenSet = fuzz.token_set_ratio(trainingSet.iloc[i,1], trainingSet.iloc[i,3]) TokenSet = (i, TokenSet) Token_tes.append(TokenSet) dfToken = pd.DataFrame(Token_tes) trainingSet['Token'] = dfToken
A continuación se muestra la ilustración del conjunto de datos de entrenamiento. En realidad, no es el conjunto de datos original porque el conjunto de datos original no está en el idioma inglés. Creo otro dato en inglés para entenderlo. Cada fila tiene dos productos. Las columnas «texto_1» e «imagen_1» pertenecen al primer producto. Las columnas «texto_2» e «imagen_2» pertenecen al segundo producto. “Etiqueta” define si los productos de emparejamiento son iguales (1) o no (0). Observe que hay otras dos columnas: «hash» y «tokenSet». Estas dos columnas se generan, no a partir del conjunto de datos original, sino a partir del código anterior.
índice | Texto 1 | image_1 | text_2 | image_2 | Etiqueta | picadillo | tokenSet |
0 | Camisa azul | Gdsfdfs.jpg | Camisa azul. | Safsfs.jpg | 1 | 6 | 100 |
1 | Sombrero limpio | Fsdfsa.jpg | Pantalones limpios | Yjdgfbs.jpg | 0 | 25 | 71 |
2 | ratón | Dfsdfasd.jpg | ratón | Fgasfdg.jpg | 0 | 30 | 100 |
. . . | . . . | . . . | . . . | . . . | . . . | . . . | . . . |
Aplicar el aprendizaje automático
Ahora, sabemos que una diferencia de Imagehash más baja y una Token_Set_Ratio más alta indican que es más probable que un par de productos sean iguales. El valor más bajo de imagehash es 0 y el valor más alto de Token_Set_Ratio es 100. Pero, la pregunta es cuánto son los umbrales. Para establecer los umbrales, podemos usar el clasificador de árbol de decisión.
Se crea un modelo de aprendizaje automático del árbol de decisiones utilizando el conjunto de datos de entrenamiento. El algoritmo de aprendizaje automático encontrará el patrón de diferencia de hash de imagen y la proporción de conjunto de tokens de productos idénticos y diferentes. El árbol de decisiones se visualiza para la imagen de portada de este artículo. El siguiente código crea un modelo de árbol de decisión con Python. (Pero, la visualización de la imagen de portada es el árbol de decisiones generado con R porque, en mi opinión, R visualiza el árbol de decisiones de manera más agradable). Luego, volverá a predecir el conjunto de datos de entrenamiento. Finalmente, podemos obtener la precisión.
# Create decision tree classifier: hash and token set Dtc = DecisionTreeClassifier(max_depth=4) Dtc = Dtc.fit(trainingSet.loc[:,['hash', 'tokenSet']], trainingSet.loc[:,'Label']) Prediction2 = Dtc.predict(trainingSet.loc[:,['hash', 'tokenSet']]) metrics.accuracy_score(trainingSet.loc[:,'Label'], Prediction2)
El árbol de decisiones se usa para predecir la clasificación del conjunto de datos de entrenamiento nuevamente. La precisión es 0,728. En otras palabras, el 72,8% del conjunto de datos de entrenamiento se predice correctamente.
Del árbol de decisiones, podemos extraer la información de que si la diferencia de Imagehash es menor que 12, el par de productos se clasifica como idéntico. Si la diferencia de Imagehash es mayor o igual a 12, debemos verificar el valor Token_Set_Ratio. El Token_Set_Ratio inferior a 97 confirma que el par de productos es diferente. En caso contrario, compruebe nuevamente si el valor de diferencia de Imagehash. Si la diferencia de imagen hash es mayor o igual a 22, entonces los productos son idénticos. De lo contrario, los productos son diferentes.
Aplicar para probar el conjunto de datos
Ahora, cargaremos el conjunto de datos de prueba, generaremos la diferencia Imagehash y Token_Set_Ratio, y finalmente predeciremos si cada par de productos coincide.
# path to image path_img = 'D:/test_img/' # load test set test = pd.read_csv('D:/new_test_set.csv', index_col=0).reset_index() # hashDiff list hashDiff = [] # Compute image difference for i in test.index[:100]: hash1 = imagehash.average_hash(Image.open(path_img + test.iloc[i,2])) hash2 = imagehash.average_hash(Image.open(path_img + test.iloc[i,4])) diff = hash1 - hash2 hashDiff.append(diff) test['hash'] = hashDiff # Token_set list Token_set = [] # Compute text difference using token set for i in test.index: TokenSet = fuzz.token_set_ratio(test.iloc[i,1], test.iloc[i,3]) Token_set.append(TokenSet) test['token'] = Token_set
Después de calcular la diferencia de Imagehash y Token_Set_ratio, lo siguiente que debe hacer es aplicar el árbol de decisiones para la detección de coincidencias de productos.
# Detecting product match test['labelPredict'] = np.where(test['hash']<12, 1, np.where(test['token']<97, 0, np.where(test['hash']>=22, 0, 1))) # or test['labelPredict'] = Dtc.predict(test[['hash','token']])
índice | Texto 1 | image_1 | text_2 | image_2 | picadillo | tokenSet | labelPredict |
0 | lápiz | Fdfgsdfhg.jpg | bolígrafo | Adxsea.jpg | 8 | 33 | 1 |
1 | disco duro | Sgytueyuyt.jpg | un buen disco duro | Erewbva.jpg | 20 | 100 | 1 |
2 | borrador | Sadssadad.jpg | estacionario | Safdfgs.jpg | 25 | 25 | 0 |
. . . | . . . | . . . | . . . | . . . | . . . | . . . | . . . |
La tabla de arriba es la ilustración del resultado final. El objetivo de este artículo es demostrar cómo predecir si dos imágenes y dos textos son similares o iguales. Puede descubrir que el modelo de aprendizaje automático utilizado es bastante simple y no hay ajuste de hiperparámetros ni división de datos de entrenamiento y prueba. La aplicación de otro aprendizaje automático, como los métodos de conjuntos basados en árboles, puede aumentar la precisión. Pero no es nuestro foco de discusión aquí. Si está interesado en aprender otro aprendizaje automático basado en árboles más preciso que el árbol de decisiones, busque un artículo aquí.
sobre el autor
Conéctate conmigo aquí https://www.linkedin.com/in/rendy-kurnia/
Los medios que se muestran en este artículo no son propiedad de DataPeaker y se utilizan a discreción del autor.