Penguni commited on
Commit
d9dc084
·
1 Parent(s): 070d178

Upload 1519 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. app/__pycache__/app.cpython-35.pyc +0 -0
  2. app/app.py +81 -0
  3. app/index.csv +0 -0
  4. app/index.py +40 -0
  5. app/pyimagesearch/__init__.py +0 -0
  6. app/pyimagesearch/__init__.pyc +0 -0
  7. app/pyimagesearch/__pycache__/__init__.cpython-35.pyc +0 -0
  8. app/pyimagesearch/__pycache__/colordescriptor.cpython-35.pyc +0 -0
  9. app/pyimagesearch/__pycache__/searcher.cpython-35.pyc +0 -0
  10. app/pyimagesearch/colordescriptor.py +62 -0
  11. app/pyimagesearch/colordescriptor.pyc +0 -0
  12. app/pyimagesearch/searcher.py +46 -0
  13. app/pyimagesearch/searcher.pyc +0 -0
  14. app/requirements.txt +25 -0
  15. app/static/images/.DS_Store +0 -0
  16. app/static/images/Dol-Guldur-001.png +0 -0
  17. app/static/images/Dol-Guldur-002.png +0 -0
  18. app/static/images/Dol-Guldur-003.png +0 -0
  19. app/static/images/Dol-Guldur-004.png +0 -0
  20. app/static/images/Dol-Guldur-005.png +0 -0
  21. app/static/images/Goblin-001.png +0 -0
  22. app/static/images/Goblin-002.png +0 -0
  23. app/static/images/Goblin-003.png +0 -0
  24. app/static/images/Goblin-004.png +0 -0
  25. app/static/images/Golbin-005.png +0 -0
  26. app/static/images/Mordor-001.png +0 -0
  27. app/static/images/Mordor-002.png +0 -0
  28. app/static/images/Mordor-003.png +0 -0
  29. app/static/images/Mordor-004.png +0 -0
  30. app/static/images/Mordor-005.png +0 -0
  31. app/static/images/Rivendell-001.png +0 -0
  32. app/static/images/Rivendell-002.png +0 -0
  33. app/static/images/Rivendell-003.png +0 -0
  34. app/static/images/Rivendell-004.png +0 -0
  35. app/static/images/Rivendell-005.png +0 -0
  36. app/static/images/Shire-001.png +0 -0
  37. app/static/images/Shire-002.png +0 -0
  38. app/static/images/Shire-003.png +0 -0
  39. app/static/images/Shire-004.png +0 -0
  40. app/static/images/Shire-005.png +0 -0
  41. app/static/init-preview.png +0 -0
  42. app/static/main.css +180 -0
  43. app/static/main.js +113 -0
  44. app/templates/_base.html +51 -0
  45. app/templates/index.html +38 -0
  46. venv/Lib/site-packages/_distutils_hack/__init__.py +222 -0
  47. venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-311.pyc +0 -0
  48. venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-311.pyc +0 -0
  49. venv/Lib/site-packages/_distutils_hack/override.py +1 -0
  50. venv/Lib/site-packages/distutils-precedence.pth +3 -0
app/__pycache__/app.cpython-35.pyc ADDED
Binary file (2.47 kB). View file
 
app/app.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ import numpy as np
4
+
5
+
6
+ from flask import Flask, render_template, request, jsonify, redirect, url_for
7
+ from werkzeug.utils import secure_filename
8
+
9
+
10
+ from pyimagesearch.colordescriptor import ColorDescriptor
11
+ from pyimagesearch.searcher import Searcher
12
+
13
+
14
+ # create flask instance
15
+ app = Flask(__name__)
16
+
17
+ INDEX = os.path.join(os.path.dirname(__file__), 'index.csv')
18
+
19
+ # main route
20
+ @app.route('/')
21
+ def index():
22
+ return render_template('index.html', preview="static/init-preview.png")
23
+
24
+ # image database url list route
25
+ @app.route('/list', methods=['POST'])
26
+ def image_list():
27
+
28
+ if request.method == "POST":
29
+
30
+ try:
31
+
32
+ imgList = [img for img in list(os.listdir(os.path.join(os.path.dirname(__file__), 'static/images/'))) if img[-4:] in ('.png', '.jpg', '.gif')]
33
+
34
+ return jsonify(imgList=imgList)
35
+
36
+ except Exception as e:
37
+ return jsonify({"sorry": "Sorry, no results! Please try again."}), 500
38
+
39
+
40
+ # search route
41
+ @app.route('/search', methods=['POST'])
42
+ def search():
43
+
44
+ if request.method == "POST":
45
+
46
+ RESULTS_ARRAY = []
47
+
48
+ # get url
49
+ image_url = request.form.get('img')
50
+
51
+ try:
52
+
53
+ # initialize the image descriptor
54
+ cd = ColorDescriptor((8, 12, 3))
55
+
56
+ # load the query image and describe it
57
+ from skimage import io
58
+ import cv2
59
+
60
+ query = cv2.imread(os.path.join(os.path.dirname(__file__), 'static/images/'+image_url))
61
+ features = cd.describe(query)
62
+
63
+ # perform the search
64
+ searcher = Searcher(INDEX)
65
+ results = searcher.search(features)
66
+
67
+ # loop over the results, displaying the score and image name
68
+ for (score, resultID) in results:
69
+ RESULTS_ARRAY.append(
70
+ {"image": str(resultID), "score": str(score)})
71
+ # return success
72
+ return jsonify(results=(RESULTS_ARRAY[:101]), preview="images/"+image_url)
73
+
74
+ except Exception as e:
75
+ print(str(e))
76
+ # return error
77
+ return jsonify({"sorry": "Sorry, no results! Please try again."}), 500
78
+
79
+ # run!
80
+ if __name__ == '__main__':
81
+ app.run('0.0.0.0', debug=True)
app/index.csv ADDED
The diff for this file is too large to render. See raw diff
 
app/index.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #import the necessary packages
2
+ from pyimagesearch.colordescriptor import ColorDescriptor
3
+ import argparse
4
+ import glob
5
+ import cv2
6
+
7
+ #construct the argument parser and parse the arguments
8
+ ap = argparse.ArgumentParser()
9
+ ap.add_argument("-d", "--dataset", required=True,
10
+ help = "path to the directory that contains the images to be indexed")
11
+ ap.add_argument("-i", "--index", required=True,
12
+ help = "path to where the index should be stored")
13
+ args = vars(ap.parse_args())
14
+
15
+ #initialize the color descriptor
16
+ cd = ColorDescriptor((8, 12, 3))
17
+
18
+ #open the output index file for writing
19
+ output = open(args["index"], "w")
20
+ types = ('/*.jpg', '/*.png', '/*.gif') # the tuple of file types
21
+ files_grabbed = []
22
+ for files in types:
23
+ files_grabbed.extend(glob.glob(args["dataset"]+files))
24
+
25
+ #use glob to grab the image paths and loop over them
26
+ for imagePath in files_grabbed:
27
+ #extract the imageID from the image
28
+ #path and load the image itself
29
+ imageID = imagePath[imagePath.rfind("/")+1:]
30
+ image = cv2.imread(imagePath)
31
+
32
+ #describe the image
33
+ features = cd.describe(image)
34
+
35
+ #write the features to file
36
+ features = [str(f) for f in features]
37
+ output.write("%s,%s\n" % (imageID, ",".join(features)))
38
+
39
+ # close the index file
40
+ output.close()
app/pyimagesearch/__init__.py ADDED
File without changes
app/pyimagesearch/__init__.pyc ADDED
Binary file (168 Bytes). View file
 
app/pyimagesearch/__pycache__/__init__.cpython-35.pyc ADDED
Binary file (164 Bytes). View file
 
app/pyimagesearch/__pycache__/colordescriptor.cpython-35.pyc ADDED
Binary file (1.71 kB). View file
 
app/pyimagesearch/__pycache__/searcher.cpython-35.pyc ADDED
Binary file (1.62 kB). View file
 
app/pyimagesearch/colordescriptor.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # import the necessary packages
2
+ import numpy as np
3
+ import cv2
4
+
5
+ class ColorDescriptor:
6
+ def __init__(self, bins):
7
+ # store the number of bins for the 3D histogram
8
+ self.bins = bins
9
+
10
+ def describe(self, image):
11
+ # convert the image to the HSV color space and initialize
12
+ # the features used to quantify the image
13
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
14
+ features = []
15
+
16
+ # grab the dimensions and compute the center of the image
17
+ (h, w) = image.shape[:2]
18
+ (cX, cY) = (int(w * 0.5), int(h * 0.5))
19
+
20
+ # divide the image into four rectangles/segments (top-left,
21
+ # top-right, bottom-right, bottom-left)
22
+ segments = [(0, cX, 0, cY), (cX, w, 0, cY), (cX, w, cY, h),
23
+ (0, cX, cY, h)]
24
+
25
+ # construct an elliptical mask representing the center of the
26
+ # image
27
+ (axesX, axesY) = (int(w * 0.75) // 2, int(h * 0.75) // 2)
28
+ ellipMask = np.zeros(image.shape[:2], dtype = "uint8")
29
+ cv2.ellipse(ellipMask, (cX, cY), (axesX, axesY), 0, 0, 360, 255, -1)
30
+
31
+ # loop over the segments
32
+ for (startX, endX, startY, endY) in segments:
33
+ # construct a mask for each corner of the image, subtracting
34
+ # the elliptical center from it
35
+ cornerMask = np.zeros(image.shape[:2], dtype = "uint8")
36
+ cv2.rectangle(cornerMask, (startX, startY), (endX, endY), 255, -1)
37
+ cornerMask = cv2.subtract(cornerMask, ellipMask)
38
+
39
+ # extract a color histogram from the image, then update the
40
+ # feature vector
41
+ hist = self.histogram(image, cornerMask)
42
+ features.extend(hist)
43
+
44
+ # extract a color histogram from the elliptical region and
45
+ # update the feature vector
46
+ hist = self.histogram(image, ellipMask)
47
+ features.extend(hist)
48
+
49
+ # return the feature vector
50
+ return features
51
+
52
+ def histogram(self, image, mask):
53
+ # extract a 3D color histogram from the masked region of the
54
+ # image, using the supplied number of bins per channel; then
55
+ # normalize the histogram
56
+ hist = cv2.calcHist([image], [0, 1, 2], mask, self.bins,
57
+ [0, 180, 0, 256, 0, 256])
58
+ cv2.normalize(hist,hist)
59
+ hist = hist.flatten()
60
+
61
+ # return the histogram
62
+ return hist
app/pyimagesearch/colordescriptor.pyc ADDED
Binary file (2.07 kB). View file
 
app/pyimagesearch/searcher.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # import the necessary packages
2
+ import numpy as np
3
+ import csv
4
+
5
+ class Searcher:
6
+ def __init__(self, indexPath):
7
+ #store our index path
8
+ self.indexPath = indexPath
9
+
10
+ def search(self, queryFeatures, limit=101):
11
+ #initialize dictionary of results
12
+ results = {}
13
+
14
+ #open the index file
15
+ with open(self.indexPath) as f:
16
+ #initialize the CSV reader
17
+ reader = csv.reader(f)
18
+
19
+ #loop over the rows in the index
20
+ for row in reader:
21
+ #parse out the image ID and features, then compute the
22
+ #chi-squared dist. b/w the features in our index
23
+ #and our query features
24
+ features = [float(x) for x in row[1:]]
25
+ d = self.chi2_distance(features, queryFeatures)
26
+
27
+ #Update dictionsary
28
+ #key is image id, value is similarity
29
+ results[row[0]] = d
30
+
31
+ #close reader
32
+ f.close()
33
+
34
+ #sort in order of relevance
35
+ results = sorted([(v,k) for (k,v) in results.items()])
36
+
37
+ #return our (limited) results
38
+ return results[:limit]
39
+
40
+ def chi2_distance(self, histA, histB, eps=1e-10):
41
+ #compute chi-squared distance
42
+ d = 0.5 * np.sum([((a-b)**2)/(a+b+eps)
43
+ for (a,b) in zip(histA, histB)])
44
+
45
+ # return the chi-squared distance
46
+ return d
app/pyimagesearch/searcher.pyc ADDED
Binary file (1.59 kB). View file
 
app/requirements.txt ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ appdirs==1.4.0
2
+ certifi==2018.8.24
3
+ click==6.7
4
+ cycler==0.10.0
5
+ dask==0.14.0
6
+ decorator==4.0.11
7
+ Flask==1.0.2
8
+ gunicorn==19.7.0
9
+ itsdangerous==0.24
10
+ Jinja2==2.10.1
11
+ MarkupSafe==1.0
12
+ matplotlib==2.0.0
13
+ networkx==1.11
14
+ numpy==1.12.0
15
+ olefile==0.44
16
+ opencv-python==4.0.0.21
17
+ packaging==16.8
18
+ Pillow==6.2.1
19
+ pyparsing==2.1.10
20
+ python-dateutil==2.6.0
21
+ pytz==2016.10
22
+ scipy==0.19.0
23
+ six==1.10.0
24
+ toolz==0.8.2
25
+ Werkzeug==0.15.3
app/static/images/.DS_Store ADDED
Binary file (12.3 kB). View file
 
app/static/images/Dol-Guldur-001.png ADDED
app/static/images/Dol-Guldur-002.png ADDED
app/static/images/Dol-Guldur-003.png ADDED
app/static/images/Dol-Guldur-004.png ADDED
app/static/images/Dol-Guldur-005.png ADDED
app/static/images/Goblin-001.png ADDED
app/static/images/Goblin-002.png ADDED
app/static/images/Goblin-003.png ADDED
app/static/images/Goblin-004.png ADDED
app/static/images/Golbin-005.png ADDED
app/static/images/Mordor-001.png ADDED
app/static/images/Mordor-002.png ADDED
app/static/images/Mordor-003.png ADDED
app/static/images/Mordor-004.png ADDED
app/static/images/Mordor-005.png ADDED
app/static/images/Rivendell-001.png ADDED
app/static/images/Rivendell-002.png ADDED
app/static/images/Rivendell-003.png ADDED
app/static/images/Rivendell-004.png ADDED
app/static/images/Rivendell-005.png ADDED
app/static/images/Shire-001.png ADDED
app/static/images/Shire-002.png ADDED
app/static/images/Shire-003.png ADDED
app/static/images/Shire-004.png ADDED
app/static/images/Shire-005.png ADDED
app/static/init-preview.png ADDED
app/static/main.css ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css?family=Lato&display=swap');
2
+
3
+ * {
4
+ box-sizing: border-box;
5
+ padding: 0;
6
+ margin: 0;
7
+ font-family: 'Lato', sans-serif;
8
+ }
9
+
10
+ body {
11
+ background-color: white;
12
+ }
13
+
14
+ .container {
15
+ width: 100%;
16
+ }
17
+
18
+ .header {
19
+ text-align: center;
20
+ font-weight: bold;
21
+ padding: 10px;
22
+ color: #0D19A3;
23
+ border-bottom: 5px solid #15DB95;
24
+ }
25
+
26
+
27
+ .display {
28
+ display: grid;
29
+ grid-template-columns: 1fr 3fr;
30
+ grid-column-gap: 20px;
31
+ margin-top: 10px;
32
+ }
33
+
34
+ .left-pane {
35
+ display: flex;
36
+ flex-direction: column;
37
+ align-items: center;
38
+ justify-content: flex-start;
39
+ color: #F4E4C1;
40
+ border-bottom: 3px solid #080F5B;
41
+ margin-left: 2px;
42
+ }
43
+
44
+ .img-preview {
45
+ width: 95%;
46
+ margin: 10px;
47
+ border: 4px solid #15DB95;
48
+ }
49
+
50
+ #preview-name {
51
+ color: #080F5B;
52
+ font-weight: bold;
53
+ font-size: 1.25em;
54
+ text-align: center;
55
+ }
56
+
57
+ #select {
58
+ padding: 10px;
59
+ background-color: #15DB95;
60
+ color: white;
61
+ font-weight: bold;
62
+ font-size: 1.5em;
63
+ cursor: pointer;
64
+ border-radius: 10px;
65
+ margin: 10px;
66
+ text-align: center;
67
+ transition: .3s;
68
+ }
69
+
70
+ #select:hover {
71
+ transform: scale(.95);
72
+ -webkit-box-shadow: 0px 0px 4px 3px rgba(8,15,91,1);
73
+ -moz-box-shadow: 0px 0px 4px 3px rgba(8,15,91,1);
74
+ box-shadow: 0px 0px 4px 3px rgba(8,15,91,1);
75
+ }
76
+
77
+ #results {
78
+ display: grid;
79
+ grid-template-columns: 1fr 1fr 1fr;
80
+ grid-column-gap: 15px;
81
+ grid-row-gap: 15px;
82
+ padding: 10px;
83
+ }
84
+
85
+ #searching {
86
+ font-weight: bold;
87
+ font-size: 1.75em;
88
+ color: #080F5B;
89
+ }
90
+
91
+ .img-result {
92
+ background-color: #080F5B;
93
+ color: white;
94
+ border: 2px solid #F4E4C1;
95
+ -webkit-box-shadow: 0px 0px 4px 3px rgba(8,15,91,1);
96
+ -moz-box-shadow: 0px 0px 4px 3px rgba(8,15,91,1);
97
+ box-shadow: 0px 0px 4px 3px rgba(8,15,91,1);
98
+ }
99
+
100
+ .img-info {
101
+ display: grid;
102
+ grid-template-columns: 1fr;
103
+ align-content: center;
104
+ justify-items: center;
105
+ border: 1px solid white;
106
+ }
107
+
108
+ .responsive {
109
+ width: 100%;
110
+ max-width: 100%;
111
+ height: 250px;
112
+ }
113
+
114
+ /* The Modal (background) */
115
+ .modal-display {
116
+ display: none; /* Hidden by default */
117
+ position: fixed; /* Stay in place */
118
+ z-index: 1; /* Sit on top */
119
+ padding-top: 100px; /* Location of the box */
120
+ left: 0;
121
+ top: 0;
122
+ width: 100%; /* Full width */
123
+ height: 100%; /* Full height */
124
+ overflow: auto; /* Enable scroll if needed */
125
+ background-color: rgb(0,0,0); /* Fallback color */
126
+ background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
127
+ }
128
+
129
+ /* Modal Content */
130
+ .modal-content {
131
+ background-color: white;
132
+ margin: auto;
133
+ padding: 20px;
134
+ border: 2px solid black;
135
+ width: 90%;
136
+ }
137
+
138
+ .modal-images-list {
139
+ display: flex;
140
+ flex-wrap: wrap;
141
+ justify-content: space-between;
142
+ }
143
+
144
+ .modal-image {
145
+ margin-bottom: 10px;
146
+ width: 30%;
147
+ cursor: pointer;
148
+ }
149
+
150
+ .modal-image:hover {
151
+ border: 5px solid #0D19A3;
152
+ }
153
+
154
+ /* The Close Button */
155
+ .close {
156
+ color: #aaaaaa;
157
+ float: right;
158
+ font-size: 28px;
159
+ font-weight: bold;
160
+ transform: translate(12px, -13px)
161
+ }
162
+
163
+ .close:hover,
164
+ .close:focus {
165
+ color: #000;
166
+ text-decoration: none;
167
+ cursor: pointer;
168
+ }
169
+
170
+ @media (max-width: 500px){
171
+ .display {
172
+ grid-template-columns: 1fr;
173
+ grid-row-gap: 20px;
174
+ }
175
+
176
+ #results {
177
+ grid-template-columns: 1fr;
178
+ grid-row-gap: 20px;
179
+ }
180
+ }
app/static/main.js ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // ----- custom js ----- //
2
+ var imagePath = 'static/images/';
3
+
4
+ $(document).ready(function() {
5
+
6
+ console.log("ready");
7
+ modalControl();
8
+ getAllImages();
9
+
10
+ });
11
+
12
+ // request for all images in database to display in modal
13
+ var getAllImages = function(){
14
+
15
+ $.ajax({
16
+ url: "/list",
17
+ cache: false,
18
+ contentType: false,
19
+ processData: false,
20
+ type: 'POST',
21
+ success: function(data){
22
+ displayModalImages(data.imgList);
23
+ },
24
+ error: function(error){
25
+ console.log(error.toString());
26
+ }
27
+ });
28
+ }
29
+
30
+ // displays images in modal
31
+ var displayModalImages = function(imgList){
32
+
33
+ for(var i = 0; i < imgList.length; i++){
34
+ $(".modal-images-list").append("<img src="+imagePath+imgList[i]+" class=modal-image onclick=imageSelectSearch(this) />");
35
+
36
+ }
37
+
38
+ }
39
+
40
+ // handles click of modal image
41
+ var imageSelectSearch = function(_this) {
42
+ var src = $(_this).attr("src");
43
+
44
+ $("#modal").css("display", "none");
45
+ $(".img-preview").attr("src", src);
46
+ $("#results").html("");
47
+ $("#results").append("<div id=searching>Searching For Results...</div>");
48
+
49
+ var image = src.split('/')[2];
50
+ var imageName = image.split('.')[0];
51
+
52
+ $("#preview-name").text('QUERY: '+imageName);
53
+
54
+ $.ajax({
55
+ url: "/search",
56
+ data: {img: image},
57
+ cache: false,
58
+ type: 'POST',
59
+ success: function(data){
60
+ displayResults(data.results);
61
+ },
62
+ error: function(error){
63
+ console.log(error.toString());
64
+ }
65
+ });
66
+
67
+ }
68
+
69
+ //display results
70
+ var displayResults = function(data){
71
+
72
+ $("#results").html("");
73
+
74
+ for(var i = 0; i < data.length; i++){
75
+ var image = data[i].image;
76
+ var score = data[i].score;
77
+ var element = "<div class=img-result><img class=responsive src="+imagePath+image+"/>\
78
+ <div class=img-info>"+"<span class=image-name>IMAGE: "+image.split('.')[0]+"</span>\
79
+ <span class=img-score>SCORE: "+score+"</span></div></div>"
80
+ $("#results").append(element);
81
+ }
82
+ }
83
+
84
+ //Controls the opening and closing of the modal
85
+ var modalControl = function(){
86
+
87
+ // Get the modal
88
+ var modal = document.getElementById("modal");
89
+
90
+ // Get the button that opens the modal
91
+ var btn = document.getElementById("select");
92
+ console.log(modal);
93
+
94
+ // Get the <span> element that closes the modal
95
+ var span = document.getElementsByClassName("close")[0];
96
+
97
+ // When the user clicks the button, open the modal
98
+ btn.onclick = function() {
99
+ modal.style.display = "block";
100
+ }
101
+
102
+ // When the user clicks on <span> (x), close the modal
103
+ span.onclick = function() {
104
+ modal.style.display = "none";
105
+ }
106
+
107
+ // When the user clicks anywhere outside of the modal, close it
108
+ window.onclick = function(event) {
109
+ if (event.target == modal) {
110
+ modal.style.display = "none";
111
+ }
112
+ }
113
+ }
app/templates/_base.html ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+
6
+ <meta charset="utf-8">
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
+ <meta name="viewport" content="width=device-width, initial-scale=1">
9
+ <meta name="description" content="content based image retrieval system">
10
+ <meta name="author" content="Kene Udeh">
11
+
12
+ <title>Image Search</title>
13
+
14
+ <!-- stylesheets -->
15
+ <link href="{{ url_for('static', filename='main.css') }}" rel="stylesheet">
16
+
17
+ <!-- Scripts -->
18
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js" type="text/javascript"></script>
19
+ <script src="{{ url_for('static', filename='main.js') }}" type="text/javascript"></script>
20
+
21
+ </head>
22
+
23
+ <body>
24
+
25
+ <!-- Page Content -->
26
+ <div class="container">
27
+
28
+ <!-- messages -->
29
+ {% for message in get_flashed_messages() %}
30
+ <div class="alert alert-success alert-dismissible" role="alert">
31
+ <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
32
+ {{ message }}
33
+ </div>
34
+ {% endfor %}
35
+
36
+ <!-- child template -->
37
+ {% block content %}{% endblock %}
38
+ {% block modal %}{% endblock %}
39
+
40
+ <!-- errors -->
41
+ {% if error %}
42
+ <p class="error"><strong>Error:</strong> {{ error }}</p>
43
+ {% endif %}
44
+
45
+
46
+ </div>
47
+ <!-- /.container -->
48
+
49
+ </body>
50
+
51
+ </html>
app/templates/index.html ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "_base.html" %}
2
+
3
+ {% block content %}
4
+
5
+ <div class="header">
6
+ <h1 class="title">SEARCH BY IMAGE</h1>
7
+ </div>
8
+ <hr/>
9
+
10
+ <div class="display">
11
+ <div class="left-pane">
12
+ <img src="static/init-preview.png" alt="preview image" class="img-preview">
13
+ <div id="preview-name">Preview</div>
14
+ <div id="select" class="image-select">
15
+ Select & Search
16
+ </div>
17
+ </div>
18
+ <div class="right-pane">
19
+ <div id="results" class="search-results">
20
+
21
+ </div>
22
+ </div>
23
+ </div>
24
+ <!-- The Modal -->
25
+ <div id="modal" class="modal-display">
26
+
27
+ <!-- Modal content -->
28
+ <div class="modal-content">
29
+ <span class="close">&times;</span>
30
+ <div class="modal-images-list">
31
+
32
+ </div>
33
+ </div>
34
+
35
+ </div>
36
+
37
+ {% endblock %}
38
+
venv/Lib/site-packages/_distutils_hack/__init__.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # don't import any costly modules
2
+ import sys
3
+ import os
4
+
5
+
6
+ is_pypy = '__pypy__' in sys.builtin_module_names
7
+
8
+
9
+ def warn_distutils_present():
10
+ if 'distutils' not in sys.modules:
11
+ return
12
+ if is_pypy and sys.version_info < (3, 7):
13
+ # PyPy for 3.6 unconditionally imports distutils, so bypass the warning
14
+ # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
15
+ return
16
+ import warnings
17
+
18
+ warnings.warn(
19
+ "Distutils was imported before Setuptools, but importing Setuptools "
20
+ "also replaces the `distutils` module in `sys.modules`. This may lead "
21
+ "to undesirable behaviors or errors. To avoid these issues, avoid "
22
+ "using distutils directly, ensure that setuptools is installed in the "
23
+ "traditional way (e.g. not an editable install), and/or make sure "
24
+ "that setuptools is always imported before distutils."
25
+ )
26
+
27
+
28
+ def clear_distutils():
29
+ if 'distutils' not in sys.modules:
30
+ return
31
+ import warnings
32
+
33
+ warnings.warn("Setuptools is replacing distutils.")
34
+ mods = [
35
+ name
36
+ for name in sys.modules
37
+ if name == "distutils" or name.startswith("distutils.")
38
+ ]
39
+ for name in mods:
40
+ del sys.modules[name]
41
+
42
+
43
+ def enabled():
44
+ """
45
+ Allow selection of distutils by environment variable.
46
+ """
47
+ which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local')
48
+ return which == 'local'
49
+
50
+
51
+ def ensure_local_distutils():
52
+ import importlib
53
+
54
+ clear_distutils()
55
+
56
+ # With the DistutilsMetaFinder in place,
57
+ # perform an import to cause distutils to be
58
+ # loaded from setuptools._distutils. Ref #2906.
59
+ with shim():
60
+ importlib.import_module('distutils')
61
+
62
+ # check that submodules load as expected
63
+ core = importlib.import_module('distutils.core')
64
+ assert '_distutils' in core.__file__, core.__file__
65
+ assert 'setuptools._distutils.log' not in sys.modules
66
+
67
+
68
+ def do_override():
69
+ """
70
+ Ensure that the local copy of distutils is preferred over stdlib.
71
+
72
+ See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
73
+ for more motivation.
74
+ """
75
+ if enabled():
76
+ warn_distutils_present()
77
+ ensure_local_distutils()
78
+
79
+
80
+ class _TrivialRe:
81
+ def __init__(self, *patterns):
82
+ self._patterns = patterns
83
+
84
+ def match(self, string):
85
+ return all(pat in string for pat in self._patterns)
86
+
87
+
88
+ class DistutilsMetaFinder:
89
+ def find_spec(self, fullname, path, target=None):
90
+ # optimization: only consider top level modules and those
91
+ # found in the CPython test suite.
92
+ if path is not None and not fullname.startswith('test.'):
93
+ return
94
+
95
+ method_name = 'spec_for_{fullname}'.format(**locals())
96
+ method = getattr(self, method_name, lambda: None)
97
+ return method()
98
+
99
+ def spec_for_distutils(self):
100
+ if self.is_cpython():
101
+ return
102
+
103
+ import importlib
104
+ import importlib.abc
105
+ import importlib.util
106
+
107
+ try:
108
+ mod = importlib.import_module('setuptools._distutils')
109
+ except Exception:
110
+ # There are a couple of cases where setuptools._distutils
111
+ # may not be present:
112
+ # - An older Setuptools without a local distutils is
113
+ # taking precedence. Ref #2957.
114
+ # - Path manipulation during sitecustomize removes
115
+ # setuptools from the path but only after the hook
116
+ # has been loaded. Ref #2980.
117
+ # In either case, fall back to stdlib behavior.
118
+ return
119
+
120
+ class DistutilsLoader(importlib.abc.Loader):
121
+ def create_module(self, spec):
122
+ mod.__name__ = 'distutils'
123
+ return mod
124
+
125
+ def exec_module(self, module):
126
+ pass
127
+
128
+ return importlib.util.spec_from_loader(
129
+ 'distutils', DistutilsLoader(), origin=mod.__file__
130
+ )
131
+
132
+ @staticmethod
133
+ def is_cpython():
134
+ """
135
+ Suppress supplying distutils for CPython (build and tests).
136
+ Ref #2965 and #3007.
137
+ """
138
+ return os.path.isfile('pybuilddir.txt')
139
+
140
+ def spec_for_pip(self):
141
+ """
142
+ Ensure stdlib distutils when running under pip.
143
+ See pypa/pip#8761 for rationale.
144
+ """
145
+ if self.pip_imported_during_build():
146
+ return
147
+ clear_distutils()
148
+ self.spec_for_distutils = lambda: None
149
+
150
+ @classmethod
151
+ def pip_imported_during_build(cls):
152
+ """
153
+ Detect if pip is being imported in a build script. Ref #2355.
154
+ """
155
+ import traceback
156
+
157
+ return any(
158
+ cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None)
159
+ )
160
+
161
+ @staticmethod
162
+ def frame_file_is_setup(frame):
163
+ """
164
+ Return True if the indicated frame suggests a setup.py file.
165
+ """
166
+ # some frames may not have __file__ (#2940)
167
+ return frame.f_globals.get('__file__', '').endswith('setup.py')
168
+
169
+ def spec_for_sensitive_tests(self):
170
+ """
171
+ Ensure stdlib distutils when running select tests under CPython.
172
+
173
+ python/cpython#91169
174
+ """
175
+ clear_distutils()
176
+ self.spec_for_distutils = lambda: None
177
+
178
+ sensitive_tests = (
179
+ [
180
+ 'test.test_distutils',
181
+ 'test.test_peg_generator',
182
+ 'test.test_importlib',
183
+ ]
184
+ if sys.version_info < (3, 10)
185
+ else [
186
+ 'test.test_distutils',
187
+ ]
188
+ )
189
+
190
+
191
+ for name in DistutilsMetaFinder.sensitive_tests:
192
+ setattr(
193
+ DistutilsMetaFinder,
194
+ f'spec_for_{name}',
195
+ DistutilsMetaFinder.spec_for_sensitive_tests,
196
+ )
197
+
198
+
199
+ DISTUTILS_FINDER = DistutilsMetaFinder()
200
+
201
+
202
+ def add_shim():
203
+ DISTUTILS_FINDER in sys.meta_path or insert_shim()
204
+
205
+
206
+ class shim:
207
+ def __enter__(self):
208
+ insert_shim()
209
+
210
+ def __exit__(self, exc, value, tb):
211
+ remove_shim()
212
+
213
+
214
+ def insert_shim():
215
+ sys.meta_path.insert(0, DISTUTILS_FINDER)
216
+
217
+
218
+ def remove_shim():
219
+ try:
220
+ sys.meta_path.remove(DISTUTILS_FINDER)
221
+ except ValueError:
222
+ pass
venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (11.2 kB). View file
 
venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-311.pyc ADDED
Binary file (349 Bytes). View file
 
venv/Lib/site-packages/_distutils_hack/override.py ADDED
@@ -0,0 +1 @@
 
 
1
+ __import__('_distutils_hack').do_override()
venv/Lib/site-packages/distutils-precedence.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2638ce9e2500e572a5e0de7faed6661eb569d1b696fcba07b0dd223da5f5d224
3
+ size 151