Similitud de imagen y texto | Introducción a la similitud de imágenes y texto

Contenidos

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.

897791-3292547
Fig.1 imagen hash
# 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.

índiceTexto 1image_1text_2image_2EtiquetapicadillotokenSet
0Camisa azulGdsfdfs.jpgCamisa azul.Safsfs.jpg16100
1Sombrero limpioFsdfsa.jpgPantalones limpiosYjdgfbs.jpg02571
2ratónDfsdfasd.jpgratónFgasfdg.jpg030100
. . .. . .. . .. . .. . .. . .. . .. . .

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']])
índiceTexto 1image_1text_2image_2picadillotokenSetlabelPredict
0lápizFdfgsdfhg.jpgbolígrafoAdxsea.jpg8331
1disco duroSgytueyuyt.jpgun buen disco duroErewbva.jpg201001
2borradorSadssadad.jpgestacionarioSafdfgs.jpg25250
. . .. . .. . .. . .. . .. . .. . .. . .

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.

Suscribite a nuestro Newsletter

No te enviaremos correo SPAM. Lo odiamos tanto como tú.