├── .gitignore ├── README.md ├── app ├── app.py ├── index.csv ├── pyimagesearch │ ├── __init__.py │ ├── __init__.pyc │ ├── colordescriptor.py │ ├── colordescriptor.pyc │ ├── searcher.py │ └── searcher.pyc ├── static │ ├── main.css │ ├── main.js │ └── queries │ │ ├── .DS_Store │ │ ├── 103100.png │ │ ├── 103300.png │ │ ├── 108100.png │ │ ├── 115100.png │ │ ├── 123600.png │ │ └── 127502.png └── templates │ ├── _base.html │ └── index.html ├── config ├── app.ini ├── nginx.conf └── supervisor.conf └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | app/pyimagesearch/*.pyc 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flask_image_search 2 | 3 | 这是一个练习项目。 4 | 5 | 代码参考 6 | 7 | Adding a web interface to our image search engine with Flask 8 | http://www.pyimagesearch.com/2014/12/08/adding-web-interface-image-search-engine-flask/ 9 | 10 | The complete guide to building an image search engine with Python and OpenCV 11 | http://www.pyimagesearch.com/2014/12/01/complete-guide-building-image-search-engine-python-opencv/ 12 | 13 | # 使用方法 14 | 15 | ``` 16 | cd flask_image_search 17 | python app/app.py 18 | ``` 19 | -------------------------------------------------------------------------------- /app/app.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import os 3 | import sys 4 | 5 | from flask import Flask, render_template, request, jsonify 6 | 7 | from pyimagesearch.colordescriptor import ColorDescriptor 8 | from pyimagesearch.searcher import Searcher 9 | 10 | # create flask instance 11 | app = Flask(__name__) 12 | 13 | INDEX = os.path.join(os.path.dirname(__file__), 'index.csv') 14 | 15 | 16 | # main route 17 | @app.route('/') 18 | def index(): 19 | return render_template('index.html') 20 | 21 | # search route 22 | @app.route('/search', methods=['POST']) 23 | def search(): 24 | 25 | if request.method == "POST": 26 | 27 | RESULTS_ARRAY = [] 28 | 29 | # get url 30 | image_url = request.form.get('img') 31 | 32 | 33 | try: 34 | 35 | # initialize the image descriptor 36 | cd = ColorDescriptor((8, 12, 3)) 37 | 38 | # load the query image and describe it 39 | from skimage import io 40 | import cv2 41 | # query = io.imread(image_url) 42 | # query = (query * 255).astype("uint8") 43 | # (r, g, b) = cv2.split(query) 44 | # query = cv2.merge([b, g, r]) 45 | 46 | image_url = "app/" + image_url[1:] 47 | # print "图像url路径:", image_url 48 | # print os.getcwd() 49 | # print sys.path[0] 50 | query = cv2.imread(image_url) 51 | # print "读取成功!" 52 | features = cd.describe(query) 53 | # print "描述子生成成功" 54 | 55 | # perform the search 56 | searcher = Searcher(INDEX) 57 | results = searcher.search(features) 58 | 59 | # loop over the results, displaying the score and image name 60 | for (score, resultID) in results: 61 | RESULTS_ARRAY.append( 62 | {"image": str(resultID), "score": str(score)}) 63 | 64 | # return success 65 | return jsonify(results=(RESULTS_ARRAY[:5])) 66 | 67 | except: 68 | 69 | # return error 70 | jsonify({"sorry": "Sorry, no results! Please try again."}), 500 71 | 72 | 73 | # run! 74 | if __name__ == '__main__': 75 | app.run('127.0.0.1', debug=True) 76 | -------------------------------------------------------------------------------- /app/pyimagesearch/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BLKStone/flask_image_search/daa2c8b3005dc3e70753585fb1f9f3e9fff5d0b6/app/pyimagesearch/__init__.py -------------------------------------------------------------------------------- /app/pyimagesearch/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BLKStone/flask_image_search/daa2c8b3005dc3e70753585fb1f9f3e9fff5d0b6/app/pyimagesearch/__init__.pyc -------------------------------------------------------------------------------- /app/pyimagesearch/colordescriptor.py: -------------------------------------------------------------------------------- 1 | # import the necessary packages 2 | import numpy as np 3 | import cv2 4 | 5 | 6 | class ColorDescriptor: 7 | def __init__(self, bins): 8 | # store the number of bins for the 3D histogram 9 | self.bins = bins 10 | 11 | def describe(self, image): 12 | # convert the image to the HSV color space and initialize 13 | # the features used to quantify the image 14 | image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) 15 | features = [] 16 | 17 | # grab the dimensions and compute the center of the image 18 | (h, w) = image.shape[:2] 19 | (cX, cY) = (int(w * 0.5), int(h * 0.5)) 20 | 21 | # divide the image into four rectangles/segments (top-left, 22 | # top-right, bottom-right, bottom-left) 23 | segments = [(0, cX, 0, cY), (cX, w, 0, cY), 24 | (cX, w, cY, h), (0, cX, cY, h)] 25 | 26 | # construct an elliptical mask representing the center of the 27 | # image 28 | (axesX, axesY) = (int(w * 0.75) / 2, int(h * 0.75) / 2) 29 | ellipMask = np.zeros(image.shape[:2], dtype="uint8") 30 | cv2.ellipse(ellipMask, (cX, cY), (axesX, axesY), 0, 0, 360, 255, -1) 31 | 32 | # loop over the segments 33 | for (startX, endX, startY, endY) in segments: 34 | # construct a mask for each corner of the image, subtracting 35 | # the elliptical center from it 36 | cornerMask = np.zeros(image.shape[:2], dtype="uint8") 37 | cv2.rectangle(cornerMask, (startX, startY), (endX, endY), 255, -1) 38 | cornerMask = cv2.subtract(cornerMask, ellipMask) 39 | 40 | # extract a color histogram from the image, then update the 41 | # feature vector 42 | hist = self.histogram(image, cornerMask) 43 | features.extend(hist) 44 | 45 | # extract a color histogram from the elliptical region and 46 | # update the feature vector 47 | hist = self.histogram(image, ellipMask) 48 | features.extend(hist) 49 | 50 | # return the feature vector 51 | return features 52 | 53 | def histogram(self, image, mask): 54 | # extract a 3D color histogram from the masked region of the 55 | # image, using the supplied number of bins per channel; then 56 | # normalize the histogram 57 | hist = cv2.calcHist([image], [0, 1, 2], mask, self.bins, 58 | [0, 180, 0, 256, 0, 256]) 59 | 60 | cv2.normalize(hist,hist) 61 | hist = hist.flatten() # flatten the matrix 62 | 63 | # return the histogram 64 | return hist 65 | -------------------------------------------------------------------------------- /app/pyimagesearch/colordescriptor.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BLKStone/flask_image_search/daa2c8b3005dc3e70753585fb1f9f3e9fff5d0b6/app/pyimagesearch/colordescriptor.pyc -------------------------------------------------------------------------------- /app/pyimagesearch/searcher.py: -------------------------------------------------------------------------------- 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 = 10): 11 | # initialize our dictionary of results 12 | results = {} 13 | 14 | # open the index file for reading 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 distance between 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 | # now that we have the distance between the two feature 28 | # vectors, we can udpate the results dictionary -- the 29 | # key is the current image ID in the index and the 30 | # value is the distance we just computed, representing 31 | # how 'similar' the image in the index is to our query 32 | results[row[0]] = d 33 | 34 | # close the reader 35 | f.close() 36 | 37 | # sort our results, so that the smaller distances (i.e. the 38 | # more relevant images are at the front of the list) 39 | results = sorted([(v, k) for (k, v) in results.items()]) 40 | 41 | # return our (limited) results 42 | return results[:limit] 43 | 44 | def chi2_distance(self, histA, histB, eps = 1e-10): 45 | # compute the chi-squared distance 46 | d = 0.5 * np.sum([((a - b) ** 2) / (a + b + eps) 47 | for (a, b) in zip(histA, histB)]) 48 | 49 | # return the chi-squared distance 50 | return d -------------------------------------------------------------------------------- /app/pyimagesearch/searcher.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BLKStone/flask_image_search/daa2c8b3005dc3e70753585fb1f9f3e9fff5d0b6/app/pyimagesearch/searcher.pyc -------------------------------------------------------------------------------- /app/static/main.css: -------------------------------------------------------------------------------- 1 | /* custom styles */ 2 | 3 | .center-container { 4 | text-align: center; 5 | padding-top: 20px; 6 | padding-bottom: 20px; 7 | } 8 | 9 | .active { 10 | border: 5px solid red; 11 | } 12 | 13 | 14 | .result-img { 15 | max-width: 100px; 16 | max-height: 100px; 17 | } -------------------------------------------------------------------------------- /app/static/main.js: -------------------------------------------------------------------------------- 1 | // ----- custom js ----- // 2 | 3 | // hide initial 4 | $("#searching").hide(); 5 | $("#results-table").hide(); 6 | $("#error").hide(); 7 | 8 | // global 9 | var url = 'http://static.pyimagesearch.com.s3-us-west-2.amazonaws.com/vacation-photos/dataset/'; 10 | var data = []; 11 | 12 | $(function() { 13 | 14 | // sanity check 15 | console.log( "ready!" ); 16 | 17 | // image click 18 | $(".img").click(function() { 19 | 20 | // empty/hide results 21 | $("#results").empty(); 22 | $("#results-table").hide(); 23 | $("#error").hide(); 24 | 25 | // add active class to clicked picture 26 | $(this).addClass("active") 27 | 28 | // grab image url 29 | var image = $(this).attr("src") 30 | console.log(image) 31 | 32 | // show searching text 33 | $("#searching").show(); 34 | console.log("searching...") 35 | 36 | // ajax request 37 | $.ajax({ 38 | type: "POST", 39 | url: "/search", 40 | data : { img : image }, 41 | // handle success 42 | success: function(result) { 43 | console.log(result.results); 44 | var data = result.results 45 | 46 | // loop through results, append to dom 47 | for (i = 0; i < data.length; i++) { 48 | $("#results").append('
Error: {{ error }}
41 | {% endif %} 42 | 43 | 44 |Searching...
27 |Oh no! No results! Check your internet connection.
28 |Image | 32 |Score | 33 |
---|