Spaces:
Runtime error
Runtime error
sakkyoi
commited on
Commit
•
b8558b3
1
Parent(s):
55fd0ca
init
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- app.py +117 -0
- features.h5 +3 -0
- kmeans.pkl +3 -0
- model.py +34 -0
- requirements.txt +5 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_0.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_1.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_10.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_100.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_101.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_102.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_103.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_104.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_105.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_106.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_107.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_108.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_109.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_11.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_110.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_111.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_112.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_113.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_114.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_115.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_116.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_117.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_118.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_119.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_12.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_120.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_121.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_122.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_123.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_124.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_125.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_126.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_127.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_128.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_129.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_13.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_130.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_131.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_132.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_133.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_134.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_135.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_136.JPEG +0 -0
- tiny-imagenet-200/train/n01443537/images/n01443537_137.JPEG +0 -0
- 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
|