sakkyoi commited on
Commit
b8558b3
1 Parent(s): 55fd0ca
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. app.py +117 -0
  2. features.h5 +3 -0
  3. kmeans.pkl +3 -0
  4. model.py +34 -0
  5. requirements.txt +5 -0
  6. tiny-imagenet-200/train/n01443537/images/n01443537_0.JPEG +0 -0
  7. tiny-imagenet-200/train/n01443537/images/n01443537_1.JPEG +0 -0
  8. tiny-imagenet-200/train/n01443537/images/n01443537_10.JPEG +0 -0
  9. tiny-imagenet-200/train/n01443537/images/n01443537_100.JPEG +0 -0
  10. tiny-imagenet-200/train/n01443537/images/n01443537_101.JPEG +0 -0
  11. tiny-imagenet-200/train/n01443537/images/n01443537_102.JPEG +0 -0
  12. tiny-imagenet-200/train/n01443537/images/n01443537_103.JPEG +0 -0
  13. tiny-imagenet-200/train/n01443537/images/n01443537_104.JPEG +0 -0
  14. tiny-imagenet-200/train/n01443537/images/n01443537_105.JPEG +0 -0
  15. tiny-imagenet-200/train/n01443537/images/n01443537_106.JPEG +0 -0
  16. tiny-imagenet-200/train/n01443537/images/n01443537_107.JPEG +0 -0
  17. tiny-imagenet-200/train/n01443537/images/n01443537_108.JPEG +0 -0
  18. tiny-imagenet-200/train/n01443537/images/n01443537_109.JPEG +0 -0
  19. tiny-imagenet-200/train/n01443537/images/n01443537_11.JPEG +0 -0
  20. tiny-imagenet-200/train/n01443537/images/n01443537_110.JPEG +0 -0
  21. tiny-imagenet-200/train/n01443537/images/n01443537_111.JPEG +0 -0
  22. tiny-imagenet-200/train/n01443537/images/n01443537_112.JPEG +0 -0
  23. tiny-imagenet-200/train/n01443537/images/n01443537_113.JPEG +0 -0
  24. tiny-imagenet-200/train/n01443537/images/n01443537_114.JPEG +0 -0
  25. tiny-imagenet-200/train/n01443537/images/n01443537_115.JPEG +0 -0
  26. tiny-imagenet-200/train/n01443537/images/n01443537_116.JPEG +0 -0
  27. tiny-imagenet-200/train/n01443537/images/n01443537_117.JPEG +0 -0
  28. tiny-imagenet-200/train/n01443537/images/n01443537_118.JPEG +0 -0
  29. tiny-imagenet-200/train/n01443537/images/n01443537_119.JPEG +0 -0
  30. tiny-imagenet-200/train/n01443537/images/n01443537_12.JPEG +0 -0
  31. tiny-imagenet-200/train/n01443537/images/n01443537_120.JPEG +0 -0
  32. tiny-imagenet-200/train/n01443537/images/n01443537_121.JPEG +0 -0
  33. tiny-imagenet-200/train/n01443537/images/n01443537_122.JPEG +0 -0
  34. tiny-imagenet-200/train/n01443537/images/n01443537_123.JPEG +0 -0
  35. tiny-imagenet-200/train/n01443537/images/n01443537_124.JPEG +0 -0
  36. tiny-imagenet-200/train/n01443537/images/n01443537_125.JPEG +0 -0
  37. tiny-imagenet-200/train/n01443537/images/n01443537_126.JPEG +0 -0
  38. tiny-imagenet-200/train/n01443537/images/n01443537_127.JPEG +0 -0
  39. tiny-imagenet-200/train/n01443537/images/n01443537_128.JPEG +0 -0
  40. tiny-imagenet-200/train/n01443537/images/n01443537_129.JPEG +0 -0
  41. tiny-imagenet-200/train/n01443537/images/n01443537_13.JPEG +0 -0
  42. tiny-imagenet-200/train/n01443537/images/n01443537_130.JPEG +0 -0
  43. tiny-imagenet-200/train/n01443537/images/n01443537_131.JPEG +0 -0
  44. tiny-imagenet-200/train/n01443537/images/n01443537_132.JPEG +0 -0
  45. tiny-imagenet-200/train/n01443537/images/n01443537_133.JPEG +0 -0
  46. tiny-imagenet-200/train/n01443537/images/n01443537_134.JPEG +0 -0
  47. tiny-imagenet-200/train/n01443537/images/n01443537_135.JPEG +0 -0
  48. tiny-imagenet-200/train/n01443537/images/n01443537_136.JPEG +0 -0
  49. tiny-imagenet-200/train/n01443537/images/n01443537_137.JPEG +0 -0
  50. tiny-imagenet-200/train/n01443537/images/n01443537_138.JPEG +0 -0
app.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ import numpy as np
4
+ import h5py
5
+ import pandas as pd
6
+ import pickle
7
+
8
+ from skimage.util import random_noise
9
+ import time
10
+
11
+ import tensorflow as tf
12
+
13
+ from model import VGGNet
14
+
15
+ def query_normal(query_img: np.ndarray):
16
+ query_feature = model.extract_feature(query_img, verbose=0)
17
+ scores = np.dot(query_feature, features.T)
18
+ rank_ID = np.argsort(scores)[::-1]
19
+ rank_score = scores[rank_ID]
20
+
21
+ imlist = [image_ids.astype(str)[index] for i, index in enumerate(rank_ID[0:10])]
22
+
23
+ return imlist, rank_score[0:10].tolist(), len(scores)
24
+
25
+ def query_kmeans(query_img: np.ndarray):
26
+ query_feature = model.extract_feature(query_img, verbose=0)
27
+
28
+ cluster = kmeans.predict(query_feature.reshape(1, -1))
29
+ cluster = cluster[0]
30
+
31
+ df = pd.DataFrame({'image_id': image_ids.astype(str), 'cluster_id': kmeans.labels_})
32
+ df = df[df['cluster_id'] == cluster]
33
+
34
+ query = df[df['cluster_id'] == cluster].index
35
+
36
+ query_feature = model.extract_feature(query_img)
37
+ scores = np.dot(query_feature, features[query].T)
38
+ rank_ID = np.argsort(scores)[::-1]
39
+ rank_score = scores[rank_ID]
40
+
41
+ imlist = [image_ids.astype(str)[index] for i, index in enumerate(query[rank_ID[0:10]])]
42
+
43
+ return imlist, rank_score[0:10].tolist(), len(scores), cluster
44
+
45
+ def query(image, mode, noise, noise_seed, mean, var, amount, salt_vs_pepper):
46
+ if image == None or noise_seed == None:
47
+ return None, None, None, None, None
48
+
49
+ query_img = tf.keras.utils.load_img(image, target_size=(model.input_shape[0], model.input_shape[1]))
50
+ query_img = tf.keras.utils.img_to_array(query_img).astype(int)
51
+
52
+ if noise == 'none':
53
+ pass
54
+ elif noise == 'gaussian' or noise =='speckle':
55
+ query_img = random_noise(query_img / 255, mode=noise, rng=int(noise_seed), mean=mean, var=var, clip=True)
56
+ query_img = np.array(query_img * 255, dtype=np.uint8)
57
+ elif noise == 'localvar':
58
+ query_img = random_noise(query_img / 255, mode=noise, rng=int(noise_seed), clip=True)
59
+ query_img = np.array(query_img * 255, dtype=np.uint8)
60
+ elif noise == 'poisson':
61
+ query_img = random_noise(query_img / 255, mode=noise, rng=int(noise_seed), clip=True)
62
+ query_img = np.array(query_img * 255, dtype=np.uint8)
63
+ elif noise == 'salt' or noise == 'pepper':
64
+ query_img = random_noise(query_img / 255, mode=noise, rng=int(noise_seed), amount=amount, clip=True)
65
+ query_img = np.array(query_img * 255, dtype=np.uint8)
66
+ elif noise == 's&p':
67
+ query_img = random_noise(query_img / 255, mode=noise, rng=int(noise_seed), amount=amount, salt_vs_pepper=salt_vs_pepper, clip=True)
68
+ query_img = np.array(query_img * 255, dtype=np.uint8)
69
+
70
+ start = time.time()
71
+ if mode == 'normal':
72
+ results, scores, length = query_normal(query_img)
73
+ elif mode == 'kmeans':
74
+ results, scores, length, cluster = query_kmeans(query_img)
75
+ end = time.time()
76
+ query_time = end - start
77
+ query_time = round(query_time * 1000, 2)
78
+
79
+ return query_img, f'Query time: {query_time} ms', [(result, f'Score: {score}, file: {result}') for result, score in zip(results, scores)], length, f'{cluster}' if mode == 'kmeans' else 'None'
80
+
81
+ if __name__ == '__main__':
82
+ model = VGGNet()
83
+
84
+ # Load dataset
85
+ datasets = h5py.File('features.h5', 'r')
86
+ features = datasets['features'][:]
87
+ image_ids = datasets['image_ids'][:]
88
+ datasets.close()
89
+
90
+ # Load kmeans model
91
+ with open('kmeans.pkl', 'rb') as f:
92
+ kmeans = pickle.load(f)
93
+
94
+ # Run web app
95
+ iface = gr.Interface(
96
+ title='An image search engine based on VGG16',
97
+ description='dataset: https://www.kaggle.com/datasets/hcfighting/tinyimagenet200. Error may occur when result showing because i\'d deleted some images in the dataset, please try another image to search.',
98
+ fn=query,
99
+ inputs=[
100
+ gr.Image(type='filepath'),
101
+ gr.Radio(['normal', 'kmeans'], value='normal', info='normal: search all images, kmeans: search images in the same cluster'),
102
+ gr.Radio(['none', 'gaussian', 'localvar', 'poisson', 'salt', 'pepper', 's&p', 'speckle'], value='none', info='noise type (default: none)'),
103
+ gr.Number(label='random_seed', value=0, info='random seed for noise (default: 0)'),
104
+ gr.Slider(label='mean', maximum=1, minimum=0, value=0, info='mean of the noise, works with gaussian and localvar (default: 0)'),
105
+ gr.Slider(label='var', maximum=1, minimum=0, value=0.01, info='variance of the noise, works with gaussian and localvar (default: 0.01)'),
106
+ gr.Slider(label='amount', maximum=1, minimum=0, value=0.05, info='proportion of image pixels to replace with noise, works with salt, pepper, and s&p (default: 0.05)'),
107
+ gr.Slider(label='salt_vs_pepper', maximum=1, minimum=0, value=0.5, info='proportion of s&p noise (default: 0.5)'),
108
+ ],
109
+ outputs=[
110
+ gr.Image(label='query image', type='numpy'),
111
+ gr.Label(label='query time'),
112
+ gr.Gallery(label='Top 10 similar images').style(columns=[5], rows=[2]),
113
+ gr.Label(label='count of images for searching'),
114
+ gr.Label(label='cluster id')
115
+ ],
116
+ )
117
+ iface.launch()
features.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:213bc8f61b17123b4f6977843eeef32d479c176b03c65fb6f9d404e8a704ac4a
3
+ size 210702048
kmeans.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4634447f64ae7d12f0b0a04bf49a806a4bb2f3b13d308747deaa9942f136b153
3
+ size 421136
model.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow as tf
2
+
3
+ import numpy as np
4
+ from numpy import linalg as LA
5
+
6
+ from keras.applications.vgg16 import VGG16
7
+ from keras.applications.vgg16 import preprocess_input
8
+
9
+ class VGGNet:
10
+ def __init__(self):
11
+ self.input_shape = (224, 224, 3)
12
+ self.weight = 'imagenet'
13
+ self.pooling = 'max'
14
+ self.model = VGG16(weights=self.weight, input_shape=(self.input_shape[0], self.input_shape[1], self.input_shape[2]), pooling=self.pooling, include_top=False)
15
+ self.model.predict(np.zeros((1, 224, 224, 3)))
16
+
17
+ def extract_feature(self, img_path: any, verbose='auto'):
18
+ if type(img_path) == str or type(img_path) == np.str_:
19
+ img = tf.keras.utils.load_img(img_path, target_size=(self.input_shape[0], self.input_shape[1]))
20
+ img = tf.keras.utils.img_to_array(img)
21
+ img = np.expand_dims(img, axis=0)
22
+ img = preprocess_input(img)
23
+ feature = self.model.predict(img, verbose=verbose)
24
+ feature_normalized = feature[0] / LA.norm(feature[0])
25
+ elif type(img_path) == np.ndarray:
26
+ img = img_path
27
+ img = np.expand_dims(img, axis=0)
28
+ img = preprocess_input(img)
29
+ feature = self.model.predict(img, verbose=verbose)
30
+ feature_normalized = feature[0] / LA.norm(feature[0])
31
+ else:
32
+ raise TypeError('img_path must be str or np.ndarray')
33
+
34
+ return feature_normalized
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio
2
+ h5py
3
+ scikit_learn
4
+ scikit-image
5
+ tensorflow
tiny-imagenet-200/train/n01443537/images/n01443537_0.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_1.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_10.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_100.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_101.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_102.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_103.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_104.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_105.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_106.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_107.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_108.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_109.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_11.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_110.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_111.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_112.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_113.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_114.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_115.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_116.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_117.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_118.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_119.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_12.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_120.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_121.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_122.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_123.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_124.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_125.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_126.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_127.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_128.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_129.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_13.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_130.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_131.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_132.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_133.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_134.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_135.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_136.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_137.JPEG ADDED
tiny-imagenet-200/train/n01443537/images/n01443537_138.JPEG ADDED