/_mix?type=data
100 |
101 | .. code::
102 |
103 | {
104 | name : file_img|file
105 | body :data
106 | }
107 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | tornado==4.4.1
2 | lxml==3.4.4
3 | numpy==1.9.2
4 | pillow==2.9.0
5 | tinydb==2.3.2
6 | pyyaml==3.12
7 | redis==2.10.5
8 | opencv-python==3.3.0.9
9 |
--------------------------------------------------------------------------------
/runtests.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | import importlib
4 |
5 | if __name__ == "__main__":
6 | from server import config_yaml
7 | config_yaml()
8 |
9 | for testcase in [
10 | 'tests.test_base'
11 | ]:
12 | __instance = importlib.import_module(testcase)
13 | __instance.main()
14 |
--------------------------------------------------------------------------------
/server.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import os
3 | import yaml
4 | import redis
5 | import tornado
6 | import tornado.web
7 | import tornado.template
8 | import tornado.web
9 | import tornado.ioloop
10 | import tornado.httpserver
11 | from tornado.options import define, options
12 | from tornado.ioloop import IOLoop
13 |
14 | from src import routes
15 |
16 | def config_yaml():
17 | '''
18 | config the App value
19 | :return:
20 | '''
21 | yaml_config = yaml.load(open("./config.yaml"))
22 | # 全局可用变量
23 | # config = yaml_config
24 | if not 'redis' in yaml_config.keys():
25 | raise Exception('config error not redis config')
26 | if not 'port' in yaml_config.keys():
27 | raise Exception('config error not port key')
28 | if not 'binding_host' in yaml_config.keys():
29 | raise Exception('config error not binding_host key')
30 | if not 'result_size' in yaml_config.keys():
31 | raise Exception('config error not result_size key')
32 | # 做检查
33 | return yaml_config
34 |
35 | config = config_yaml()
36 |
37 | class Application(tornado.web.Application):
38 | def __init__(self):
39 | ''' the setting '''
40 | settings = dict(
41 | template_path = os.path.join(os.path.dirname(__file__), "src/template"),
42 | static_path = os.path.join(os.path.dirname(__file__), "src/static"),
43 | autoreload=False,
44 | debug=False,
45 | # autoreload = True,
46 | # debug = True
47 | )
48 |
49 | self.config = config
50 | route = routes.getRoutes(config)
51 |
52 | _host = self.config['redis']['host']
53 | _port = self.config['redis']['port']
54 | _db = self.config['redis']['db']
55 | # 需要认真阅读这里的文章
56 | # https://mirrors.segmentfault.com/itt2zh/ch4.html
57 | self.r = redis.Redis(
58 | host = _host,
59 | port = _port,
60 | db = _db
61 | )
62 |
63 | # 初始化 redis
64 | # 服务器初始化
65 | tornado.web.Application.__init__(self, handlers=route, **settings)
66 |
67 | # start run
68 | def main():
69 | print 'Running...'
70 | # 服务启动的进程
71 | num_processes = 1
72 | app_port = config['port']
73 | address = config['binding_host']
74 | tornado.options.parse_command_line()
75 | http_server = tornado.httpserver.HTTPServer(Application())
76 |
77 | # listen 可以显式创建创建 http
78 | # http_server.listen(app_port)
79 | http_server.bind(app_port)
80 | http_server.start(num_processes)
81 | # IOLoop.current().start()
82 | IOLoop.instance().start()
83 |
84 | # main run
85 | if __name__ == "__main__":
86 | main()
87 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/src/__init__.py
--------------------------------------------------------------------------------
/src/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/src/core/__init__.py
--------------------------------------------------------------------------------
/src/core/app.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import json, time, os, uuid
3 | import hashlib
4 |
5 | from tornado import gen
6 | import tornado
7 | import tornado.ioloop
8 | import tornado.web
9 | import tornado.gen
10 | import tornado.template
11 |
12 | from src.lib.data import Data
13 | from src.service.manage import Manage
14 | from src.service.match import Match # 对比管理程序
15 |
16 | class App(tornado.web.RequestHandler):
17 | SUPPORTED_METHODS = ("CONNECT", "GET", "HEAD", "POST", "DELETE", "PATCH", "PUT", "OPTIONS")
18 | # def __init__(self, application, request, **kwargs):
19 | # super(tornado.web.RequestHandler, self).__init__(*request,**kwargs)
20 | def __init__(self, *request, **kwargs):
21 | super(App, self).__init__(request[0], request[1])
22 |
23 | self.set_header('Access-Control-Allow-Origin', '*')
24 | self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
25 |
26 | self.data = Data()
27 | self.config = self.application.config
28 | self.manage = Manage(
29 | self.application.r
30 | )
31 |
32 | # 定义 匹配接口
33 | self.match = Match(
34 | self.manage,
35 | self.config['result_size']
36 | )
37 | # 数据结果
38 | def result(self, resultDict = []):
39 | # print compareDict
40 | self.write(self.data
41 | .set('status', 'OK')
42 | .set('data', resultDict)
43 | .get())
44 |
45 | def add_json(self):
46 | self.set_header('Content-Type', 'application/json')
47 |
48 | def write_error(self, status_code, **kwargs):
49 | '''
50 | : 处理失败问题
51 | '''
52 | self.set_status(200)
53 | self.set_header('Content-Type', 'application/json')
54 | self.write(
55 | self.data
56 | .set('status', 'fail')
57 | .set('message', 'Not any result be found')
58 | .set('data', [])
59 | .get()
60 | )
61 |
--------------------------------------------------------------------------------
/src/detector.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | import io
4 |
5 | # define a base detector Image paser for module
6 | class Detector:
7 | _weight = 1
8 | # 储存 原 对比数据, 避免又一次计算
9 | _base_image = None
10 | _base_image_for_opencv = None
11 | # 注册名称
12 | def get_name(self):
13 | return self.__class__.__name__
14 |
15 | def __init__(self):
16 | pass
17 |
18 | def match(self, source, target):
19 | source_path = source.get_path()
20 | target_path = target.get_path()
21 |
22 | def do_screening(self):
23 | raise Exception('You must rewrite the do screening function!!')
24 |
25 | def get_score(self):
26 | return self.do_screening()
27 |
28 | # def reg(self):
29 | # # 注册该方法到 feature
30 | # raise Exception('You must rewrite the do screening function!!')
31 |
32 | def calculate(self, origin = None, local = None):
33 | # 开始计算
34 | raise Exception('You must rewrite the calculate function!!')
35 |
36 | def is_io(self, io_image = None):
37 | if io is None:
38 | raise Exception('io is error')
39 | if not isinstance(io_image, io.BytesIO):
40 | return False
41 | return True
42 |
--------------------------------------------------------------------------------
/src/detectors/Base.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import math
3 | import operator
4 | from PIL import Image as im
5 | from src.detector import Detector
6 |
7 | # histogram 算法
8 | class Base(Detector):
9 |
10 | def calculate(self, origin = None, local = None):
11 | return self._base(origin, local)
12 |
13 | # ----------------------------------------------------------
14 | # base
15 | # 算法 -> 直方图比较
16 | # ----------------------------------------------------------
17 | def _base(self, origin = None, local = None):
18 | # origin 需要 静态化
19 | if self._base_image is None:
20 | print 'histogram calculate'
21 | image1 = im.open(origin)
22 | self._base_image = image1.convert('RGB').histogram()
23 |
24 | # if not image1.size is image2.size:
25 | # image2 = image2.resize(image1.size)
26 | # pass
27 |
28 | image2 = im.open(local)
29 | h2 = image2.convert('RGB').histogram()
30 |
31 | rms = math.sqrt(
32 | reduce(
33 | operator.add,
34 | list(
35 | map(
36 | lambda a, b: (a - b) ** 2, self._base_image, h2
37 | )
38 | )
39 | )
40 | /
41 | len(self._base_image)
42 | )
43 | print rms
44 | # 如果这个 histigram 波浪太大就过滤掉
45 | # wave = reduce(lambda o,n: abs(0-n),image2.convert('RGB').histogram())
46 | # return wave
47 |
48 | return rms
49 |
--------------------------------------------------------------------------------
/src/detectors/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/src/detectors/__init__.py
--------------------------------------------------------------------------------
/src/detectors/color.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | from PIL import Image as im
4 | from src.detector import Detector
5 |
6 | class Color(Detector):
7 |
8 | def calculate(self, origin = None, local = None):
9 | # 注册 执行 perceptual hash
10 | return self._color(origin, local)
11 |
12 | # ----------------------------------------------------------
13 | # color compare
14 | #
15 | # ----------------------------------------------------------
16 | def _color(self, origin=None, local=None):
17 | '''
18 | 计算两个三维向量距离
19 | (R1-R2)^2 + (G1-G2)^2 + (B1-B2)^2 的值的平方根,即颜色空间的距离
20 | 距离越大,差距就越大。
21 | :return:
22 | '''
23 | def getRgb(io):
24 | r, g, b = im.open(io).convert('RGB').resize((1, 1)).getcolors()[0][1]
25 | return [r, g, b]
26 | RGB_A = None
27 | if self._base_image is None:
28 | RGB_A = getRgb(origin)
29 |
30 | RGB_B = getRgb(local)
31 |
32 | # if len(RGB_A) == 3 and len(RGB_B) == 3:
33 | score = (RGB_A[0] - RGB_B[0]) ** 2 + (RGB_A[1] - RGB_B[1]) ** 2 + (RGB_A[2] - RGB_B[2]) ** 2
34 | return abs(score)
35 |
36 |
--------------------------------------------------------------------------------
/src/detectors/correlate.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | from PIL import Image as im
4 | from src.detector import Detector
5 |
6 | class Phash(Detector):
7 |
8 | def calculate(self, origin = None, local = None):
9 | # 注册 执行 perceptual hash
10 | return self._mse(origin, local)
11 |
12 | # ----------------------------------------------------------
13 | # correlate2d
14 | # very slow
15 | # return int
16 | # return the MSE, the lower the error, the more "similar"
17 | # NOTE: the two images must have the same dimension
18 | # ----------------------------------------------------------
19 | def correlate2d(self):
20 | """
21 | : So fucking slow
22 | : return: float
23 | """
24 | import scipy as sp
25 | from scipy.misc import imread
26 | from scipy.signal.signaltools import correlate2d
27 |
28 | def get(path):
29 | data = imread(path)
30 | data = sp.inner(data, [299, 587, 114]) / 1000.0
31 | return (data - data.mean()) / data.std()
32 |
33 | value = correlate2d(get(self.image_a_path),
34 | get(self.image_b_path)).max()
35 | return value
36 |
--------------------------------------------------------------------------------
/src/detectors/mse.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | from PIL import Image as im
4 | from src.detector import Detector
5 | import numpy as np
6 | import cv2
7 | # from StringIO import StringIO
8 |
9 | class Mse(Detector):
10 |
11 | def calculate(self, origin = None, local = None):
12 | # 注册 执行 perceptual hash
13 | return self._mse(origin, local)
14 |
15 | # ----------------------------------------------------------
16 | # mse 均方误差
17 | # MSE可以评价数据的变化程度,
18 | # MSE的值越小,
19 | # 说明预测模型描述实验数据具有更好的精确度。与此相对应的,
20 | # 还有均方根误差RMSE、平均绝对百分误差等等。
21 | # ----------------------------------------------------------
22 | def _mse(self, origin = None, local = None):
23 | """
24 | :return: float
25 | """
26 | # 使用 io byte 读取数据
27 | # import numpy as np
28 | # a1=io.BytesIO(rr.get('base_image_name'))
29 | # nparr = np.fromstring(a1.read(), np.uint8)
30 | # img_np = cv2.imdecode(nparr, cv2.CV_LOAD_IMAGE_COLOR)
31 | # cv2.imshow('image',img_np)
32 | # cv2.namedWindow('image', cv2.WINDOW_NORMAL)
33 | # cv2.imshow('image',img)
34 | # cv2.waitKey(0)
35 | # cv2.destroyAllWindows()
36 |
37 | def io_to_cv2data(io = None):
38 | nparr = np.fromstring(io.read(), np.uint8)
39 | return cv2.imdecode(nparr, cv2.CV_LOAD_IMAGE_COLOR)
40 |
41 | if self._base_image_for_opencv is None:
42 | self._base_image_for_opencv = io_to_cv2data(origin)
43 |
44 | # use opencv color bgr to gray
45 | imageA = cv2.cvtColor(self._base_image_for_opencv, cv2.COLOR_BGR2GRAY)
46 | imageB = cv2.cvtColor(io_to_cv2data(local), cv2.COLOR_BGR2GRAY)
47 |
48 | err = np.sum((imageA.astype("float") - imageB.astype("float")) ** 2)
49 | err /= float(imageA.shape[0] * imageA.shape[1])
50 |
51 | return err
52 |
53 |
--------------------------------------------------------------------------------
/src/detectors/phash.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | from PIL import Image as im
4 | from src.detector import Detector
5 |
6 | class Phash(Detector):
7 |
8 | def calculate(self, origin = None, local = None):
9 | # 注册 执行 perceptual hash
10 | return self._phash(origin, local)
11 |
12 | # ----------------------------------------------------------
13 | # perceptual Hash
14 | # very quick 8 x 8
15 | # 感知 hash 算法 , 通过指纹匹配
16 | # ----------------------------------------------------------
17 | def _phash(self, origin = None, local = None):
18 | def avhash(io, im):
19 | # print im
20 | # print im
21 | # if not isinstance(im, Image.Image):
22 | the_image = im.open(io)
23 | the_image = the_image.resize((8, 8), im.ANTIALIAS).convert('L')
24 | avg = reduce(lambda x, y: x + y, the_image.getdata()) / 64.
25 | return reduce(
26 | lambda x, (y, z): x | (z << y),
27 | enumerate(map(lambda i: 0 if i < avg else 1, the_image.getdata())),
28 | 0
29 | )
30 |
31 | # hamming 距离
32 | def hamming(h1, h2):
33 | h, d = 0, h1 ^ h2
34 | while d:
35 | h += 1
36 | d &= d - 1
37 | return h
38 |
39 | # a = avhash(self.byte_base, im)
40 | # b = avhash(self.byte_storage, im)
41 |
42 | # a 需要 静态化
43 | if self._base_image is None:
44 | print 'phash calculate again'
45 | self._base_image = avhash(origin, im)
46 |
47 | b = avhash(local, im)
48 | value = hamming(self._base_image, b)
49 | # self.value_of_perceptualHash = value
50 |
51 | return value
52 |
--------------------------------------------------------------------------------
/src/handler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/src/handler/__init__.py
--------------------------------------------------------------------------------
/src/handler/bindex.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import hashlib
3 | import json, time, os, uuid
4 | import tornado
5 | import tornado.ioloop
6 | import tornado.web
7 | import tornado.gen
8 | import tornado.template
9 | from src.lib.data import Data
10 |
11 | # from tornado import queues
12 | from tornado import gen
13 |
14 | from tinydb import TinyDB, where
15 | from src.service.manage import Manage
16 |
17 | class BuildIndexHandler(tornado.web.RequestHandler):
18 | """
19 | RESTFUL api style
20 | """
21 | def get(self, type=None):
22 | self.write("please use post method")
23 |
24 | @tornado.gen.coroutine
25 | def post(self, type=None):
26 | self.set_header('Content-Type', 'application/json')
27 | jsonM = Data()
28 |
29 | getJson = self.request.body
30 | jsondata = json.loads(getJson)
31 |
32 | __is_base64 = False
33 | __image = None
34 | if 'url' in jsondata['query'].keys():
35 | __image = jsondata['query']['url']
36 | else:
37 | __image = jsondata['query']['base64']
38 | __is_base64 = True
39 |
40 | if __image is None:
41 | raise Exception('image data is empty!')
42 |
43 | __name = jsondata['query']['name']
44 | __id = jsondata['query']['id']
45 | __data = jsondata['query']['data']
46 | # 需要参与搜索的字段
47 | __search = jsondata['query']['search']
48 |
49 | __data['id'] = __id
50 | # 直接使用 application 的 redis 初始化
51 | Manage(
52 | self.application.r
53 | ).index_image(
54 | __id,
55 | __search,
56 | __data,
57 | __image,
58 | __name,
59 | __is_base64
60 | )
61 | return self.write(jsonM.setStatus('status', 'OK')
62 | .set('msg', str('index success!'))
63 | .get())
64 |
65 | from src.core.app import App
66 |
67 | class AddHandler(App):
68 | def get(self):
69 | return self.write('[]')
70 |
71 | class CleaerIndexHandler(tornado.web.RequestHandler):
72 | def delete(self, type=None):
73 | try:
74 | # os.remove(os.environ[config.STORAGE_INDEX_DB])
75 | Manage(
76 | self.application.r
77 | ).clear_db()
78 | except:
79 | pass
80 | self.set_header('Content-Type', 'application/json')
81 | jsonM = Data()
82 | self.write(jsonM.setStatus('status', 'OK')
83 | .set('msg', str('delete index Success!'))
84 | .get())
85 | def get(self, type=None):
86 | self.write("error method")
87 |
--------------------------------------------------------------------------------
/src/handler/compare.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import json
3 | from src.core.app import App
4 |
5 | class pcHandler(App):
6 | def post(self, type):
7 | self.set_header('Content-Type', 'application/json')
8 | # way = self.get_argument("type")
9 |
10 | # if way != 'json':
11 | # raise Exception('method incorrect!')
12 |
13 | getJson = self.request.body
14 | jsondata = json.loads(getJson)
15 |
16 | # 储存对比图片到 redis
17 | if 'base64' in jsondata['query'].keys():
18 | self.manage.store_base_image_by_base64(jsondata['query']['base64'])
19 | else:
20 | self.manage.store_base_image(jsondata['query']['url'])
21 |
22 | try:
23 | terms = jsondata['terms']
24 | except:
25 | terms = None
26 |
27 | # 返回数据限定
28 | try:
29 | page_size = jsondata['size']
30 | except:
31 | page_size = None
32 |
33 | # 开始比对
34 | resultDict = self.match.get_match_result(terms, page_size)
35 |
36 | self.result(resultDict)
37 |
--------------------------------------------------------------------------------
/src/handler/demo.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import os
3 | import glob
4 | import StringIO
5 | import tornado
6 | import tornado.ioloop
7 | import tornado.web
8 | import tornado.template
9 | from PIL import Image as im
10 |
11 | from src.core.app import App
12 | from src.lib.image import Image
13 | from src.service.feature import Feature as Compare
14 | from src.service.manage import Manage as Manage
15 | from src.service.match import Match
16 |
17 |
18 |
19 | class TestHandler(App):
20 | def get(self, *args, **kwargs):
21 | self.write(
22 | tornado.template.Loader(os.environ[config.TEMPLATE]).load("search_test_upload.html").generate(
23 | name='search by index',
24 | action='search_test'
25 | )
26 | )
27 |
28 | def post(self, *args, **kwargs):
29 | '''
30 | search color test demo
31 | '''
32 | os.chdir(os.environ[config.PROJECT_DIR] + "tests/tmp/")
33 |
34 | imagetool = im
35 | compare = Compare()
36 | imgfiles = self.request.files['file_img']
37 | if len(imgfiles) > 1:
38 | return self.write("error")
39 | imgfile = imgfiles[0]
40 | filename = imgfile['filename'].strip()
41 | import uuid
42 | filename = str(uuid.uuid4()) + '.' + filename.split('.')[-1]
43 | tmp = os.environ[config.PROJECT_DIR] + "tests/tmp/"
44 |
45 | tmp_image = tmp + filename
46 | print tmp_image
47 | im.open(StringIO.StringIO(imgfile['body'])).save(tmp_image)
48 |
49 | # path = os.environ[config.PROJECT_DIR] + "tests/img/"
50 | self.m.store_base_image_file(tmp_image)
51 |
52 |
53 | # 开始比对
54 | resultDict = Match(
55 | self.m
56 | ).get_match_result()
57 |
58 | print resultDict
59 | self.write(
60 | tornado.template.Loader(os.environ[config.TEMPLATE]).load("search_test.html").generate(
61 | origin_img = '/tests/tmp/' + filename,
62 | results = resultDict
63 | )
64 | )
65 |
--------------------------------------------------------------------------------
/src/handler/home.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import os
3 | import tornado
4 | import tornado.ioloop
5 | import tornado.web
6 | import tornado.template
7 | from src.core.app import App
8 | from src.lib.data import Data
9 |
10 | class HomeHandler(App):
11 | # @tornado.web.asynchronous
12 | def get(self, param):
13 | self.set_header('Content-Type', 'application/json')
14 | the_list = self.manage.search([])
15 | result = self.data \
16 | .set('status', 'ok') \
17 | .set('count_data', str(len(the_list))) \
18 | .set('config', self.config) \
19 | .get()
20 | self.write(
21 | result
22 | )
23 |
--------------------------------------------------------------------------------
/src/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/src/lib/__init__.py
--------------------------------------------------------------------------------
/src/lib/data.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import json
3 | from StringIO import StringIO
4 |
5 | class Data:
6 | '''
7 | this is pc json standard
8 | The json must be have status and data
9 | status is a str
10 | data was dict
11 | '''
12 | def __init__(self, data = []):
13 | self.origin = data
14 | self.data = {}
15 |
16 | def __str__(self):
17 | '''
18 | :return:
19 | '''
20 | return "json_module"
21 |
22 | def setData(self, key, param):
23 | '''
24 | :param key:
25 | :param param:
26 | :return:
27 | '''
28 | if type(param) in (str, list, dict):
29 | if key is 'data':
30 | self.data[key] = param
31 | return self
32 |
33 | def setStatus(self, key, param):
34 | '''
35 | :param key:
36 | :param param:
37 | :return:
38 | '''
39 | if type(param) in (str, list, dict):
40 | if key is 'status':
41 | self.data[key] = param
42 | return self
43 |
44 | def set(self, key, param):
45 | '''
46 | :param key:
47 | :param param:
48 | :return:
49 | '''
50 | if type(param) in (str, list, dict):
51 | self.data[key] = param
52 | return self
53 |
54 | def add(self, key, param):
55 | '''
56 | :param key:
57 | :param param:
58 | :return:
59 | '''
60 | self.data[key].append(param)
61 |
62 | def get(self):
63 | '''
64 | :return:
65 | '''
66 | return json.dumps(self.data)
67 |
68 | def loads(self, raw_data = ''):
69 | return json.loads(raw_data)
70 |
71 | def to_string(self):
72 | return json.dumps(self.origin)
73 |
--------------------------------------------------------------------------------
/src/lib/image.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from PIL import Image as im
3 |
4 | class Image:
5 | '''
6 | tranlate value for color
7 | '''
8 |
9 | def __init__(self):
10 | pass
11 |
12 | # ----------------------------------------------------------
13 | # get picture color rgba
14 | # @:return
15 | # ----------------------------------------------------------
16 | def get_rgba(self, io):
17 | '''
18 | :param path:
19 | :return:
20 | '''
21 | r, g, b, a = im.open(io).convert('RGBA').resize((1, 1)).getcolors()[0][1]
22 | return (r, g, b, a)
23 |
24 |
25 | # ----------------------------------------------------------
26 | # get picture color rgb
27 | # @:return
28 | # ----------------------------------------------------------
29 | def get_rgb(self, io):
30 | '''
31 | :param path:
32 | :return:
33 | '''
34 | r, g, b = im.open(io).convert('RGB').resize((1, 1)).getcolors()[0][1]
35 | return (r, g, b)
36 |
37 | def get_hsi(self, io):
38 | '''
39 | Unfortunately I think that this transformation can not be done
40 | with Image.convert: you can only do transformations between equivalent
41 | color spaces (i.e. reach the destination colorspace by doing a
42 | multiplication with a matrix with the source colorspace).
43 |
44 | The HSI colorspace, instead, is not an equivalent colorspace of RGB.
45 | To get the HSI equivalent of a RGB pixel one must do these
46 | transformations:
47 |
48 | :return:
49 | '''
50 | import math
51 |
52 | R, G, B = im.open(io).convert('RGB').resize((1, 1)).getcolors()[0][1]
53 |
54 | I = 1/3 * (R+G+B)
55 |
56 | S = 1 - (3/(R+G+B))*(min(R,G,B))
57 |
58 | H = math.cos^-1( (((R-G)+(R-B))/2)/ (math.sqrt((R-G)^2 + (R-B)*(G-B) )))
59 |
60 | return (H,S,I)
61 |
62 | rgb_list = [
63 | {"almon": (250, 128, 114)},
64 | {"darksalmon": (233, 150, 122)},
65 | {"lightcoral": (240, 128, 128)},
66 | {"indianred": (205, 92, 92)},
67 | {"crimson": (220, 20, 60)},
68 | {"firebrick": (178, 34, 34)},
69 | {"red": (255, 0, 0)},
70 | {"darkred": (139, 0, 0)},
71 | {"coral": (255, 127, 80)},
72 | {"tomato": (255, 99, 71)},
73 | {"orangered": (255, 69, 0)},
74 | {"gold": (255, 215, 0)},
75 | {"orange": (255, 165, 0)},
76 | {"darkorange": (255, 140, 0)},
77 | {"lightyellow": (255, 255, 224)},
78 | {"lemonchiffon": (255, 250, 205)},
79 | {"lightgoldenrodyellow": (250, 250, 210)},
80 | {"papayawhip": (255, 239, 213)},
81 | {"moccasin": (255, 228, 181)},
82 | {"peachpuff": (255, 218, 185)},
83 | {"palegoldenrod": (238, 232, 170)},
84 | {"khaki": (240, 230, 140)},
85 | {"darkkhaki": (189, 183, 107)},
86 | {"yellow": (255, 255, 0)},
87 | {"lawngreen": (124, 252, 0)},
88 | {"chartreuse": (127, 255, 0)},
89 | {"limegreen": (50, 205, 50)},
90 | {"lime": (0, 255, 0)},
91 | {"forestgreen": (34, 139, 34)},
92 | {"green": (0, 128, 0)},
93 | {"darkgreen": (0, 100, 0)},
94 | {"greenyellow": (173, 255, 47)},
95 | {"yellowgreen": (154, 205, 50)},
96 | {"springgreen": (0, 255, 127)},
97 | {"mediumspringgreen": (0, 250, 154)},
98 | {"lightgreen": (144, 238, 144)},
99 | {"palegreen": (152, 251, 152)},
100 | {"darkseagreen": (143, 188, 143)},
101 | {"mediumseagreen": (60, 179, 113)},
102 | {"seagreen": (46, 139, 87)},
103 | {"olive": (128, 128, 0)},
104 | {"darkolivegreen": (85, 107, 47)},
105 | {"olivedrab": (107, 142, 35)},
106 | {"lightcyan": (224, 255, 255)},
107 | {"cyan": (0, 255, 255)},
108 | {"aqua": (0, 255, 255)},
109 | {"aquamarine": (127, 255, 212)},
110 | {"mediumaquamarine": (102, 205, 170)},
111 | {"paleturquoise": (175, 238, 238)},
112 | {"turquoise": (64, 224, 208)},
113 | {"mediumturquoise": (72, 209, 204)},
114 | {"darkturquoise": (0, 206, 209)},
115 | {"lightseagreen": (32, 178, 170)},
116 | {"cadetblue": (95, 158, 160)},
117 | {"darkcyan": (0, 139, 139)},
118 | {"teal": (0, 128, 128)},
119 | {"powderblue": (176, 224, 230)},
120 | {"lightblue": (173, 216, 230)},
121 | {"lightskyblue": (135, 206, 250)},
122 | {"skyblue": (135, 206, 235)},
123 | {"deepskyblue": (0, 191, 255)},
124 | {"lightsteelblue": (176, 196, 222)},
125 | {"dodgerblue": (30, 144, 255)},
126 | {"cornflowerblue": (100, 149, 237)},
127 | {"steelblue": (70, 130, 180)},
128 | {"royalblue": (65, 105, 225)},
129 | {"blue": (0, 0, 255)},
130 | {"mediumblue": (0, 0, 205)},
131 | {"darkblue": (0, 0, 139)},
132 | {"navy": (0, 0, 128)},
133 | {"midnightblue": (25, 25, 112)},
134 | {"mediumslateblue": (123, 104, 238)},
135 | {"slateblue": (106, 90, 205)},
136 | {"darkslateblue": (72, 61, 139)},
137 | {"lavender": (230, 230, 250)},
138 | {"thistle": (216, 191, 216)},
139 | {"plum": (221, 160, 221)},
140 | {"violet": (238, 130, 238)},
141 | {"orchid": (218, 112, 214)},
142 | {"fuchsia": (255, 0, 255)},
143 | {"magenta": (255, 0, 255)},
144 | {"mediumorchid": (186, 85, 211)},
145 | {"mediumpurple": (147, 112, 219)},
146 | {"blueviolet": (138, 43, 226)},
147 | {"darkviolet": (148, 0, 211)},
148 | {"darkorchid": (153, 50, 204)},
149 | {"darkmagenta": (139, 0, 139)},
150 | {"purple": (128, 0, 128)},
151 | {"indigo": (75, 0, 130)},
152 | {"pink": (255, 192, 203)},
153 | {"lightpink": (255, 182, 193)},
154 | {"hotpink": (255, 105, 180)},
155 | {"deeppink": (255, 20, 147)},
156 | {"palevioletred": (219, 112, 147)},
157 | {"mediumvioletred": (199, 21, 133)},
158 | {"white": (255, 255, 255)},
159 | {"snow": (255, 250, 250)},
160 | {"honeydew": (240, 255, 240)},
161 | {"mintcream": (245, 255, 250)},
162 | {"azure": (240, 255, 255)},
163 | {"aliceblue": (240, 248, 255)},
164 | {"ghostwhite": (248, 248, 255)},
165 | {"whitesmoke": (245, 245, 245)},
166 | {"seashell": (255, 245, 238)},
167 | {"beige": (245, 245, 220)},
168 | {"oldlace": (253, 245, 230)},
169 | {"floralwhite": (255, 250, 240)},
170 | {"ivory": (255, 255, 240)},
171 | {"antiquewhite": (250, 235, 215)},
172 | {"linen": (250, 240, 230)},
173 | {"lavenderblush": (255, 240, 245)},
174 | {"mistyrose": (255, 228, 225)},
175 | {"gainsboro": (220, 220, 220)},
176 | {"lightgray": (211, 211, 211)},
177 | {"silver": (192, 192, 192)},
178 | {"darkgray": (169, 169, 169)},
179 | {"gray": (128, 128, 128)},
180 | {"dimgray": (105, 105, 105)},
181 | {"lightslategray": (119, 136, 153)},
182 | {"slategray": (112, 128, 144)},
183 | {"darkslategray": (47, 79, 79)},
184 | {"black": (0, 0, 0)},
185 | {"cornsilk": (255, 248, 220)},
186 | {"blanchedalmond": (255, 235, 205)},
187 | {"bisque": (255, 228, 196)},
188 | {"navajowhite": (255, 222, 173)},
189 | {"wheat": (245, 222, 179)},
190 | {"burlywood": (222, 184, 135)},
191 | {"tan": (210, 180, 140)},
192 | {"rosybrown": (188, 143, 143)},
193 | {"sandybrown": (244, 164, 96)},
194 | {"goldenrod": (218, 165, 32)},
195 | {"peru": (205, 133, 63)},
196 | {"chocolate": (210, 105, 30)},
197 | {"saddlebrown": (139, 69, 19)},
198 | {"sienna": (160, 82, 45)},
199 | {"brown": (165, 42, 42)},
200 | {"maroon": (128, 0, 0)}
201 | ]
202 |
203 | rgb_list_chinese = {
204 | "红色": (255, 0, 0),
205 | "橙红": (255, 51, 0),
206 | "橙色": (255, 102, 0),
207 | "橙黄": (255, 153, 0),
208 | "黄色": (255, 255, 0),
209 | "黄绿": (153, 255, 0),
210 | "绿色": (0, 255, 0),
211 | "蓝绿": (0, 255, 255),
212 | "蓝色": (0, 0, 255),
213 | "蓝紫": (102, 0, 255),
214 | "紫色": (255, 0, 255),
215 | "紫红": (255, 0, 102)
216 | }
217 |
--------------------------------------------------------------------------------
/src/routes.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import tornado
3 | import tornado.ioloop
4 | import tornado.web
5 | import tornado.template
6 | from src.handler import (demo,compare,bindex,home)
7 | import os
8 |
9 | def getRoutes(config):
10 | Routes = [
11 | # ---------------------------------------------
12 | # demo url
13 | # ---------------------------------------------
14 | (r"/search_test", demo.TestHandler),
15 |
16 | # ---------------------------------------------
17 | # static url
18 | # ---------------------------------------------
19 | # (r'/img/(.*)', tornado.web.StaticFileHandler, {'path': os.environ[config.STATIC_DIR]}),
20 | # (r'/tests/(.*)', tornado.web.StaticFileHandler, {'path': os.environ[config.PROJECT_DIR]+"/tests/"}),
21 |
22 | # ---------------------------------------------
23 | # index
24 | # ---------------------------------------------
25 | (r'/_index(.*)',bindex.BuildIndexHandler),
26 | (r'/_delete(.*)', bindex.CleaerIndexHandler),
27 |
28 | # picture compare api
29 | (r'/_pc(.*)',compare.pcHandler),
30 |
31 | # ---------------------------------------------
32 | # other tool url
33 | # ---------------------------------------------
34 | # (r'/crossdomain.xml',urltool.urltoolHandler),
35 |
36 | # ---------------------------------------------
37 | # home dashboard url
38 | # ---------------------------------------------
39 | (r"/(.*)", home.HomeHandler),
40 | ]
41 |
42 | return Routes
43 |
--------------------------------------------------------------------------------
/src/service/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/src/service/__init__.py
--------------------------------------------------------------------------------
/src/service/feature.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | from PIL import Image as im
4 | from src.detectors.phash import Phash
5 | from src.detectors.base import Base
6 | from src.detectors.color import Color
7 | from src.detectors.mse import Mse
8 |
9 | # 方向 base 的数据其实只需要提取一次啊, 囧~~
10 | class Feature:
11 | '''
12 | Compare Image differ I find some useful function
13 | Maybe Some function would suit for you Project
14 | '''
15 | detector = {}
16 |
17 | # 预注册特征
18 | __default_feature = [
19 | # 'Phash',
20 | 'Base',
21 | # 'Color',
22 | # 'Mse',
23 | ]
24 |
25 | # 使用比特码对比
26 | byte_base = None
27 | byte_storage = None
28 |
29 | # 算法特征
30 | # 将原对比图片 预先出错 , 避免 重复计算
31 | base_image_trait_for_image = None
32 | base_image_trait_for_cv = None
33 |
34 | def __init__(self):
35 | # 注册所有的特征
36 | self.__reg(Phash())
37 | self.__reg(Base())
38 | self.__reg(Color())
39 | self.__reg(Mse())
40 |
41 | def __reg(self, instance_name = None):
42 | self.detector[
43 | instance_name.get_name()
44 | ] = instance_name
45 |
46 | def process(self, detector_list = []):
47 | '''
48 | : 每个进程都会使用这个 Process, 出现了一些问题??
49 | '''
50 | if (detector_list is None) or (not len(detector_list) > 0):
51 | detector_list = self.__default_feature
52 |
53 | result = {}
54 | for single_feature in self.detector:
55 | if single_feature in detector_list:
56 | result[single_feature] = self.detector[single_feature].calculate(
57 | self.byte_base,
58 | self.byte_storage
59 | )
60 | return result
61 |
62 | def set_byte_base_image(self, byte):
63 | self.byte_base = byte
64 |
65 | def set_byte_storage_image(self, byte):
66 | self.byte_storage = byte
67 |
--------------------------------------------------------------------------------
/src/service/manage.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import os
3 | import io
4 | import base64
5 | import urllib2
6 | import StringIO
7 | import cStringIO
8 | from tinydb import TinyDB,where
9 |
10 | from PIL import Image as im
11 | from src.lib.data import Data
12 |
13 |
14 | class Manage:
15 | image_size = (20,20)
16 |
17 | divided = '--@@--'
18 |
19 | r = None
20 |
21 | def __init__(self, redis = None):
22 | # 如今已经不需要 redis 的初始化了 叼
23 | self.r = redis
24 |
25 | # 生成短名称 短名称 在前面
26 | def __genrate_sort_name(self, names = []):
27 | '''
28 | :生成 redis 的 key
29 | :param keys:
30 | :return:
31 | '''
32 | __sort_dict, __result = {}, {}
33 | # 根据穷举法, 找到最短的 key
34 | for s in names:
35 | for lenght in range(0, len(s)):
36 | __check_name = s[:(lenght + 1)]
37 | if not __check_name in __sort_dict.values():
38 | # sort name 没有被定义 可以使用
39 | __sort_dict[s] = __check_name
40 | # 同时进入下一个关键词判断
41 | break
42 | # 首先对names 进行一次排序 保证 每次的结果都一样
43 | names = sorted(__sort_dict)
44 | # 重新排序
45 | for i in names:
46 | __result[i] = __sort_dict[i]
47 | return __result
48 |
49 | # ----------------------------------------------------------
50 | # 生成 redis key 名称
51 | # ---------------------------------------------------------
52 | def __generate_key(self, search = [] ,source_data = {}):
53 | # 生成短名称
54 | __sort_dict = self.__genrate_sort_name(search)
55 | if not type(source_data) is dict:
56 | raise Exception('Keys incorrectness!')
57 |
58 | k_name = ''
59 |
60 | for i in __sort_dict:
61 | if i in source_data:
62 | k_name += str(__sort_dict[i]) + '=' + str(source_data[i])
63 | # 不是最后一个 那么加上 - 连接符号
64 | # if __sort_dict.keys()[-1] is not i:
65 | k_name += '-'
66 |
67 | return k_name
68 |
69 | # ----------------------------------------------------------
70 | # 向 redis 创建索引
71 | # ---------------------------------------------------------
72 | def index_image(self, id = 0, search = [], data = [], image = '', name = '', is_base64 = False):
73 | # TOOD 需要一个算法 , 将每次 的 search 字段数据 转化为相同的,数据
74 | # 根据 client 的条件字段创建 的 key
75 | source_data = {}
76 | for index_name in search:
77 | source_data[index_name] = data[index_name]
78 |
79 | # 每个对象必须要有一个名字
80 | data['name'] = name
81 |
82 | key_name = self.__generate_key(
83 | search,
84 | source_data
85 | )
86 |
87 | # 在尾部加上id
88 | key_name += '#' + str(id)
89 | # 0 -> data
90 | # 1 -> image - binary
91 | if image:
92 | if is_base64:
93 | # 对于 base64 的处理办法
94 | if 'base64,' in image:
95 | image = image.split(',')[1]
96 | image_str = cStringIO.StringIO(base64.b64decode(image))
97 | im_instance = im.open(image_str).resize(self.image_size)
98 | else:
99 | # 对于 url 文件的处理办法
100 | res = urllib2.urlopen(image)
101 | if res.code == 200:
102 | # save data into Bytes
103 | imimage = io.BytesIO(res.read())
104 | # 压缩图片以及,格式化为 JPEG
105 | im_instance = im.open(imimage).resize(self.image_size)
106 |
107 | # 不管使用哪种参数方法 最终的结果都是保存 redis
108 | output = StringIO.StringIO()
109 | im_instance \
110 | .convert('RGB') \
111 | .save(output, 'JPEG')
112 |
113 | string = Data(data).to_string()
114 |
115 | value = string + \
116 | self.divided + \
117 | output.getvalue()
118 |
119 | self.r.set(key_name, value)
120 | return True
121 | return False
122 |
123 | base_image_name = 'base_image_name'
124 |
125 | def store_base_image(self, image = ''):
126 | res = urllib2.urlopen(image)
127 | if res.code == 200:
128 | imimage = io.BytesIO(res.read())
129 | im_instance = im.open(imimage).resize(self.image_size)
130 | output = StringIO.StringIO()
131 | im_instance \
132 | .convert('RGB') \
133 | .save(output, 'JPEG')
134 |
135 | return self.r.set(self.base_image_name, output.getvalue())
136 | raise Exception('Image request fail!')
137 |
138 | def store_base_image_file(self, image = ''):
139 | im_instance = im.open(image).resize(self.image_size)
140 | output = StringIO.StringIO()
141 | im_instance \
142 | .convert('RGB') \
143 | .save(output, 'JPEG')
144 |
145 | self.r.set(self.base_image_name, output.getvalue())
146 |
147 | def store_base_image_by_base64(self, image = ''):
148 | '''
149 | : 通过 base64 储存文件
150 | '''
151 | if 'base64,' in image:
152 | image = image.split(',')[1]
153 | image_str = cStringIO.StringIO(base64.b64decode(image))
154 | im_instance = im.open(image_str).resize(self.image_size)
155 | output = StringIO.StringIO()
156 | im_instance \
157 | .convert('RGB') \
158 | .save(output, 'JPEG')
159 |
160 | self.r.set(self.base_image_name, output.getvalue())
161 |
162 | def remove_base_image_file(self):
163 | ''' 删除缓存数据 '''
164 | self.r.delete(self.base_image_name)
165 |
166 |
167 | def get_base_image(self):
168 | result = self.r.get(self.base_image_name)
169 | return io.BytesIO(result)
170 |
171 | def clear_db(self):
172 | '''
173 | : 清除当前数据库
174 | '''
175 | print 'clear db ...'
176 | self.r.flushdb()
177 |
178 | # 单个获取图片
179 | def get_image(self, key_name = None):
180 | return io.BytesIO(
181 | self.r.get(key_name)
182 | )
183 |
184 | # 单个获取图片
185 | def get_image_with_data(self, key_name = None):
186 | data, result = self.r.get(key_name).split(self.divided)
187 | return data, io.BytesIO(result)
188 |
189 | # ----------------------------------------------------------
190 | # 根据条件生成数据
191 | # ---------------------------------------------------------
192 | def search(self, terms = None):
193 | # 生成短名称
194 | if terms:
195 | key_name = self.__generate_key(
196 | terms.keys(),
197 | terms
198 | )
199 | return self.r.keys('*' + key_name + '*')
200 | else:
201 | return self.r.keys('*')
202 |
203 | def get_multi(self, keys = []):
204 | if len(keys) > 0:
205 | return self.r.mget(keys)
206 | raise Exception('keys is empty!')
207 |
--------------------------------------------------------------------------------
/src/service/match.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | import io
4 | import json
5 | from src.lib.data import Data
6 | from src.service.feature import Feature
7 | from src.service.manage import Manage
8 | import multiprocessing as mp
9 | from multiprocessing import Pool
10 | from functools import partial
11 |
12 | def mix_hash(score_list = {}):
13 | '''
14 | : merge image score
15 | '''
16 | mse = 0
17 | phash = 0
18 | base = 0
19 | color = 0
20 | for detector in score_list:
21 | if detector is 'Phash':
22 | phash = score_list[detector] * 0.5
23 | if detector is 'Base':
24 | base = score_list[detector] * 9
25 | if detector is 'Mse':
26 | mse = score_list[detector] * 0.8
27 | if detector is 'Color':
28 | color = score_list[detector] * 1.1
29 |
30 | return (mse + phash + base + color)
31 | # print '---'
32 | # print phash
33 | # print base
34 | # return (base + phash)
35 |
36 |
37 | def process_match(origin_io=None, lists=None):
38 | '''
39 | : match image by different process
40 | '''
41 | feature = Feature()
42 | data = Data()
43 |
44 | # print lists
45 | results = []
46 |
47 | # 直接返回 redis row data
48 | for container in lists:
49 | # 找到比对数据
50 | feature.set_byte_base_image(origin_io)
51 |
52 | # 风格数据
53 | data, image_str = container.split(Manage.divided)
54 |
55 | byte = io.BytesIO(image_str)
56 | feature.set_byte_storage_image(byte)
57 |
58 | bean = json.loads(data)
59 | result = {}
60 | # 使用算法到的
61 | # 大色块比对方案
62 | result = feature.process(None)
63 |
64 | # merge calculate score
65 | score = mix_hash(result)
66 | # 准备返回数据
67 | processed = {}
68 |
69 | for i in bean:
70 | processed[i] = bean[i]
71 | processed['score'] = score
72 |
73 | results.append(processed)
74 | return results
75 |
76 | class Match:
77 | '''
78 | Compare Image differ I find some useful function
79 | Maybe Some function would suit for you Project
80 | '''
81 |
82 | # 原对比文件 的 byte 属性
83 | origin_io_image = None
84 |
85 | def __init__(self, Manage = None, result_size = 10):
86 | """
87 | 设置 管理器
88 | """
89 | self.manage = Manage
90 | self.feature = Feature()
91 | self.data = Data()
92 | self.result_size = result_size
93 |
94 |
95 | def set_origin_image(self, image_url = ''):
96 | # 设置原图片索引
97 | if image_url is '':
98 | raise Exception('Origin image is empty')
99 | self.manage.store_base_image(image_url)
100 |
101 | def get_match_result(self, terms = None, page_size = None):
102 | '''
103 | :param data:
104 | :return: list | None
105 | '''
106 | # 设置原图数据
107 | self.origin_io_image = self.manage.get_base_image()
108 |
109 | limit = page_size
110 | if page_size is None:
111 | limit = self.result_size
112 |
113 | the_list = self.manage.search(terms)
114 | # 删除缓存数据
115 | if Manage.base_image_name in the_list:
116 | the_list.remove(Manage.base_image_name)
117 |
118 | for_multiprocess_list = []
119 | for_multiprocess_list = self.manage.get_multi(the_list)
120 |
121 | print 'count result:', str(len(the_list))
122 |
123 | results = []
124 | core_number = mp.cpu_count()
125 |
126 | # 计算每个 cpu 需要的数量 (分化数据到每个 cpu )
127 | n = int(round(len(for_multiprocess_list) / float(core_number)))
128 | divid_list = [for_multiprocess_list[i:i + n] for i in xrange(0, len(for_multiprocess_list), n)]
129 |
130 |
131 | # Pool的默认大小是CPU
132 | pool = Pool()
133 | func = partial(process_match, self.origin_io_image)
134 |
135 | # 并得到合并的结果集
136 | rl = pool.map(func, divid_list)
137 | pool.close()
138 | pool.join()
139 |
140 | # set two dimension to one dimension
141 | results = [item for i in rl for item in i]
142 |
143 | sortedList = sorted(results, key=lambda k: k['score'])
144 | sortedList = sortedList[:limit]
145 | item_id = 0
146 |
147 | # 处理 image 在内存里面的数据
148 | self.manage.remove_base_image_file()
149 | return sortedList
150 |
--------------------------------------------------------------------------------
/src/template/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | just show test image
4 |
5 |
6 | {% include nav.html %}
7 |
8 |
9 | rms = math.sqrt(
10 | reduce(operator.add, list(map(lambda a, b: (a - b) ** 2, h1, h2)))
11 | /
12 | len(h1)
13 | )
14 |
15 | {% for package in package_image %}
16 |
17 | {% for i in package %}
18 |
19 |
20 |  |
21 |  |
22 | ![]() |
23 | base:{{ i['code'] }} |
24 | mes:{{ i['code2'] }} |
25 | perceptualHash:{{ i['code3'] }} |
26 | color:{{ i['code4'] }} |
27 |
28 |
29 | {% end %}
30 |
31 |
32 | {% end %}
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/template/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | just show test image
4 |
5 |
6 | {% include nav.html %}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/template/nav.html:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/template/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | search file
4 |
5 |
6 |
10 | {{ name }}
11 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/template/search_color_result.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | search file
4 |
5 |
6 |
9 |
10 | code2
11 |
12 | {% for result in results %}
13 | -
14 |
15 |
16 |
17 | {{ origin_img_rgb }} //
18 | {{result['rgb']}} //
19 | {{result['score']}} //
20 | {{result['keyname']}} //
21 |
22 | {% end %}
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/template/search_result.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | just show test image
4 |
5 |
6 |
10 |
11 | code1
12 |
13 | {% for result in results_code1 %}
14 | -
15 |
16 |
17 |
18 | {{result['code1']}} //
19 |
20 | {% end %}
21 |
22 |
23 | code2
24 |
25 | {% for result in results_code2 %}
26 | -
27 |
28 |
29 |
30 | {{result['code2']}} //
31 |
32 | {% end %}
33 |
34 |
35 | code3
36 |
37 | {% for result in results_code3 %}
38 | -
39 |
40 |
41 |
42 | {{result['code3']}} //
43 |
44 | {% end %}
45 |
46 |
47 |
48 | color Compare
49 |
50 | {% for result in results_code4 %}
51 | -
52 |
53 |
54 |
55 | {{result['code4']}} //
56 | {{result['color_package']['keyname']}} //
57 |
58 | {% end %}
59 |
60 |
61 |
62 | code_mix
63 |
64 | {% for result in results_mix %}
65 | -
66 |
67 |
68 |
69 | {{result['code_mix']}} //
70 |
71 | {% end %}
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/template/search_test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | just show test image
4 |
5 |
6 |
7 |
8 |
16 |
19 |
20 | {% for result in results %}
21 |
22 |
23 |
24 |
25 | {{ result['name'] }} //
26 |
27 | {% end %}
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/template/search_test_upload.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | search file
4 |
5 |
6 |
10 | {{ name }}
11 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/__init__.py
--------------------------------------------------------------------------------
/tests/brick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/brick.png
--------------------------------------------------------------------------------
/tests/find.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/find.png
--------------------------------------------------------------------------------
/tests/finds_the_coin.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 |
3 |
4 | import cv2
5 | import numpy as np
6 | from matplotlib import pyplot as plt
7 | def test_2():
8 | # http://docs.opencv.org/3.1.0/d4/dc6/tutorial_py_template_matching.html
9 | # find 找图例子
10 | img_rgb = cv2.imread('origin_material.jpg')
11 | img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
12 | template = cv2.imread('find.png',0)
13 | w, h = template.shape[::-1]
14 |
15 | res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
16 | threshold = 0.8
17 | loc = np.where( res >= threshold)
18 | for pt in zip(*loc[::-1]):
19 | cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
20 | cv2.imwrite('res.png',img_rgb)
21 |
22 |
23 |
24 | def test_one():
25 | img = cv2.imread('orgin_brick.jpg',0)
26 | img2 = img.copy()
27 | img2 = img.copy()
28 | template = cv2.imread('brick.png',0)
29 | w, h = template.shape[::-1]
30 |
31 | # All the 6 methods for comparison in a list
32 | methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
33 | 'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
34 | for meth in methods:
35 | img = img2.copy()
36 | method = eval(meth)
37 |
38 | # Apply template Matching
39 | res = cv2.matchTemplate(img,template,method)
40 | min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
41 |
42 | # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
43 | if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
44 | top_left = min_loc
45 | else:
46 | top_left = max_loc
47 | bottom_right = (top_left[0] + w, top_left[1] + h)
48 |
49 | cv2.rectangle(img,top_left, bottom_right, 255, 2)
50 | plt.subplot(121),plt.imshow(res,cmap = 'gray')
51 | plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
52 | plt.subplot(122),plt.imshow(img,cmap = 'gray')
53 | plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
54 | plt.suptitle(meth)
55 | plt.show()
56 |
57 | def test_3():
58 | import urllib2
59 | import io
60 |
61 | url = "http://i.gzdmc.net/images/bd2888edd41a951de1ab8cbfb33c82e2.jpg@1e_400w_400h_1c_0i_1o_90Q_1x.png";
62 | res = urllib2.urlopen(url)
63 | # save data into Bytes
64 | imimage = io.BytesIO(res.read())
65 |
66 | nparr = np.fromstring(imimage.read(), np.uint8)
67 | img = cv2.imdecode(nparr, cv2.CV_LOAD_IMAGE_COLOR)
68 | print dir(img)
69 | height, width, channels = img.shape
70 | print height
71 | print width
72 | print channels
73 | # img = cv2.imread()
74 | mask = np.zeros(img.shape[:2],np.uint8)
75 |
76 | bgdModel = np.zeros((1,65),np.float64)
77 | fgdModel = np.zeros((1,65),np.float64)
78 |
79 | rect = (0, 0, height - 1 ,width - 1)
80 | cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
81 | mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
82 | img = img*mask2[:,:,np.newaxis]
83 |
84 | plt.imshow(img),plt.colorbar(),plt.show()
85 |
86 | # # newmask is the mask image I manually labelled
87 | # newmask = cv2.imread('orgin_brick.jpg',0)
88 | # # whereever it is marked white (sure foreground), change mask=1
89 | # # whereever it is marked black (sure background), change mask=0
90 | # mask[newmask == 0] = 0
91 | # mask[newmask == 255] = 1
92 | # mask, bgdModel, fgdModel = cv2.grabCut(img,mask,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK)
93 | # mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')
94 | # img = img*mask[:,:,np.newaxis]
95 | # plt.imshow(img),plt.colorbar(),plt.show()
96 | def test_find_cycle():
97 | cap = cv2.VideoCapture(0)
98 |
99 | while(1):
100 |
101 | # Take each frame
102 | _, frame = cap.read()
103 |
104 | # Convert BGR to HSV
105 | hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
106 |
107 | # define range of blue color in HSV
108 | lower_blue = np.array([110,50,50])
109 | upper_blue = np.array([130,255,255])
110 |
111 | # Threshold the HSV image to get only blue colors
112 | mask = cv2.inRange(hsv, lower_blue, upper_blue)
113 |
114 | # Bitwise-AND mask and original image
115 | res = cv2.bitwise_and(frame,frame, mask= mask)
116 |
117 | cv2.imshow('frame',frame)
118 | cv2.imshow('mask',mask)
119 | cv2.imshow('res',res)
120 | k = cv2.waitKey(5) & 0xFF
121 | if k == 27:
122 | break
123 | cv2.destroyAllWindows()
124 | test_3()
125 |
--------------------------------------------------------------------------------
/tests/img/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/1.jpg
--------------------------------------------------------------------------------
/tests/img/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/10.jpg
--------------------------------------------------------------------------------
/tests/img/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/11.jpg
--------------------------------------------------------------------------------
/tests/img/14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/14.jpg
--------------------------------------------------------------------------------
/tests/img/15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/15.jpg
--------------------------------------------------------------------------------
/tests/img/16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/16.jpg
--------------------------------------------------------------------------------
/tests/img/17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/17.jpg
--------------------------------------------------------------------------------
/tests/img/18.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/18.jpg
--------------------------------------------------------------------------------
/tests/img/19.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/19.jpg
--------------------------------------------------------------------------------
/tests/img/21.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/21.jpg
--------------------------------------------------------------------------------
/tests/img/22.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/22.jpg
--------------------------------------------------------------------------------
/tests/img/23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/23.jpg
--------------------------------------------------------------------------------
/tests/img/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/3.jpg
--------------------------------------------------------------------------------
/tests/img/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/4.jpg
--------------------------------------------------------------------------------
/tests/img/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/5.jpg
--------------------------------------------------------------------------------
/tests/img/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/6.jpg
--------------------------------------------------------------------------------
/tests/img/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/7.jpg
--------------------------------------------------------------------------------
/tests/img/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/8.jpg
--------------------------------------------------------------------------------
/tests/img/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/img/9.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/10.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/11.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/12.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/2.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/3.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/4.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/5.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/6.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/7.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/8.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/9.jpg
--------------------------------------------------------------------------------
/tests/imgs/img1/bd_logo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img1/bd_logo1.png
--------------------------------------------------------------------------------
/tests/imgs/img2/jp_gates_contrast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/jp_gates_contrast.png
--------------------------------------------------------------------------------
/tests/imgs/img2/jp_gates_original.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/jp_gates_original.png
--------------------------------------------------------------------------------
/tests/imgs/img2/jp_gates_photoshopped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/jp_gates_photoshopped.png
--------------------------------------------------------------------------------
/tests/imgs/img2/u=1154773526,535753407&fm=21&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=1154773526,535753407&fm=21&gp=0.jpg
--------------------------------------------------------------------------------
/tests/imgs/img2/u=2382192293,4052630182&fm=21&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=2382192293,4052630182&fm=21&gp=0.jpg
--------------------------------------------------------------------------------
/tests/imgs/img2/u=2473462771,2519378688&fm=21&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=2473462771,2519378688&fm=21&gp=0.jpg
--------------------------------------------------------------------------------
/tests/imgs/img2/u=2476847967,542236518&fm=21&gp=0-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=2476847967,542236518&fm=21&gp=0-2.jpg
--------------------------------------------------------------------------------
/tests/imgs/img2/u=2476847967,542236518&fm=21&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=2476847967,542236518&fm=21&gp=0.jpg
--------------------------------------------------------------------------------
/tests/imgs/img2/u=2741110226,162889272&fm=21&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=2741110226,162889272&fm=21&gp=0.jpg
--------------------------------------------------------------------------------
/tests/imgs/img2/u=2755629579,2099783568&fm=21&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=2755629579,2099783568&fm=21&gp=0.jpg
--------------------------------------------------------------------------------
/tests/imgs/img2/u=3598758,4045583727&fm=21&gp=0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img2/u=3598758,4045583727&fm=21&gp=0.jpg
--------------------------------------------------------------------------------
/tests/imgs/img3/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img3/1.jpg
--------------------------------------------------------------------------------
/tests/imgs/img3/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img3/2.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/1.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/10.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/2.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/3.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/4.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/562c11dfa9ec8a13836f2676f103918fa0ecc02b.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/562c11dfa9ec8a13836f2676f103918fa0ecc02b.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/738b4710b912c8fc1aae2af7fb039245d68821af-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/738b4710b912c8fc1aae2af7fb039245d68821af-2.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/738b4710b912c8fc1aae2af7fb039245d68821af.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/738b4710b912c8fc1aae2af7fb039245d68821af.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/9b46f21fbe096b630a632fc60a338744ebf8ac2a.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/9b46f21fbe096b630a632fc60a338744ebf8ac2a.jpg
--------------------------------------------------------------------------------
/tests/imgs/img4/a8014c086e061d953a36eb027cf40ad162d9ca9c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/img4/a8014c086e061d953a36eb027cf40ad162d9ca9c.jpg
--------------------------------------------------------------------------------
/tests/imgs/imgdb/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/imgdb/.gitkeep
--------------------------------------------------------------------------------
/tests/imgs/storage/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/.gitkeep
--------------------------------------------------------------------------------
/tests/imgs/storage/0079d7d650f8833d4d152381aa397a49.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/0079d7d650f8833d4d152381aa397a49.png
--------------------------------------------------------------------------------
/tests/imgs/storage/023808d2c8d421e59b44adf9d0975513.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/023808d2c8d421e59b44adf9d0975513.png
--------------------------------------------------------------------------------
/tests/imgs/storage/160a31eb7ccb105f0ab9d5b7aede085b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/160a31eb7ccb105f0ab9d5b7aede085b.png
--------------------------------------------------------------------------------
/tests/imgs/storage/1d7f93bf15288d660ea283ad3ad2cf36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/1d7f93bf15288d660ea283ad3ad2cf36.png
--------------------------------------------------------------------------------
/tests/imgs/storage/2cb2bca1f460957b0de2e5fdd600437a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/2cb2bca1f460957b0de2e5fdd600437a.png
--------------------------------------------------------------------------------
/tests/imgs/storage/3203a0be00ed57feb72a592dddf76c3e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/3203a0be00ed57feb72a592dddf76c3e.png
--------------------------------------------------------------------------------
/tests/imgs/storage/3ac2c13d9a48c75a703689b3c3780e61.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/3ac2c13d9a48c75a703689b3c3780e61.png
--------------------------------------------------------------------------------
/tests/imgs/storage/3cf2c674b35839f1a7801ab5b11448c5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/3cf2c674b35839f1a7801ab5b11448c5.png
--------------------------------------------------------------------------------
/tests/imgs/storage/3e44218e97dd14e2efeac90d012ca00c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/3e44218e97dd14e2efeac90d012ca00c.png
--------------------------------------------------------------------------------
/tests/imgs/storage/4991385c86dadab8cf075e35949b6719.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/4991385c86dadab8cf075e35949b6719.png
--------------------------------------------------------------------------------
/tests/imgs/storage/4a71dae033504b97bc7bbe06f0fa447f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/4a71dae033504b97bc7bbe06f0fa447f.png
--------------------------------------------------------------------------------
/tests/imgs/storage/4de571fcf072849f23ef19ef4f6b9738.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/4de571fcf072849f23ef19ef4f6b9738.png
--------------------------------------------------------------------------------
/tests/imgs/storage/51ffa23048d553e5f633f177aef3c990.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/51ffa23048d553e5f633f177aef3c990.png
--------------------------------------------------------------------------------
/tests/imgs/storage/5f9659b5ee80cde874970ed6aa10d109.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/5f9659b5ee80cde874970ed6aa10d109.png
--------------------------------------------------------------------------------
/tests/imgs/storage/711be1f660213bdc5eceff97ec1f3d21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/711be1f660213bdc5eceff97ec1f3d21.png
--------------------------------------------------------------------------------
/tests/imgs/storage/7d5627485e8f4ee30d8fdf8d659282c6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/7d5627485e8f4ee30d8fdf8d659282c6.png
--------------------------------------------------------------------------------
/tests/imgs/storage/a27a1c9c847a7534ebc590de56e037a8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/a27a1c9c847a7534ebc590de56e037a8.png
--------------------------------------------------------------------------------
/tests/imgs/storage/af3727c3075c61f1bfa434b33f01a0ed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/af3727c3075c61f1bfa434b33f01a0ed.png
--------------------------------------------------------------------------------
/tests/imgs/storage/b714e06d15c85867bc785d36a8fe83d9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/b714e06d15c85867bc785d36a8fe83d9.png
--------------------------------------------------------------------------------
/tests/imgs/storage/c1635f9e09bb7dcf76a6b04a51bae240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/c1635f9e09bb7dcf76a6b04a51bae240.png
--------------------------------------------------------------------------------
/tests/imgs/storage/d266e6072469ca6103c5ace4bf77b6d7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/d266e6072469ca6103c5ace4bf77b6d7.png
--------------------------------------------------------------------------------
/tests/imgs/storage/eb30bf991b24eb14e6083390c29bb1da.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/eb30bf991b24eb14e6083390c29bb1da.png
--------------------------------------------------------------------------------
/tests/imgs/storage/ec86dff70f3634aff8a93f167f594a36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/ec86dff70f3634aff8a93f167f594a36.png
--------------------------------------------------------------------------------
/tests/imgs/storage/ecc73686b4340c8a4fa5152221053705.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storage/ecc73686b4340c8a4fa5152221053705.png
--------------------------------------------------------------------------------
/tests/imgs/storagetemp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storagetemp.jpg
--------------------------------------------------------------------------------
/tests/imgs/storagetemp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgs/storagetemp.png
--------------------------------------------------------------------------------
/tests/imgtemp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/imgtemp.jpg
--------------------------------------------------------------------------------
/tests/opencv.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from matplotlib import pyplot as plt
3 | import cv2
4 |
5 | img = cv2.imread('/Users/liyang/Downloads/mQxZL0pz69ZbmfR8pSw70c7lmQgt4SI-3-fhhnxP9hUVLmIJSHmFsGWE_sifAkQv.jpg@1o.png',0)
6 | edges = cv2.Canny(img,100,200)
7 |
8 | plt.subplot(121),plt.imshow(img,cmap = 'gray')
9 | plt.title('Original Image'), plt.xticks([]), plt.yticks([])
10 | plt.subplot(122),plt.imshow(edges,cmap = 'gray')
11 | plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
12 |
13 | plt.show()
14 |
--------------------------------------------------------------------------------
/tests/orgin_brick.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/orgin_brick.jpg
--------------------------------------------------------------------------------
/tests/origin_material.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/origin_material.jpg
--------------------------------------------------------------------------------
/tests/res.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/res.png
--------------------------------------------------------------------------------
/tests/stone_ streamline.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Callwoola/picture-compare/5a7748bce557ddbee350476dd5cf29f696c88324/tests/stone_ streamline.jpg
--------------------------------------------------------------------------------
/tests/testOne.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 |
3 | #from skimage.measure import structural_similarity as ssim
4 | from skimage.measure import structural_similarity as ssim
5 | import matplotlib.pyplot as plt
6 | import numpy as np
7 | import cv2
8 |
9 |
10 | def demo1():
11 | from PIL import Image
12 | import ImageChops
13 |
14 | path = "D:/code/image/image/"
15 | im1 = Image.open(path + "1.jpg")
16 | im2 = Image.open(path + "2.jpg")
17 |
18 | diff = ImageChops.difference(im2, im1)
19 | print diff
20 |
21 | im1.show()
22 | im2.show()
23 | diff.show()
24 |
25 |
26 | def mse(imageA, imageB):
27 | # the 'Mean Squared Error' between the two images is the
28 | # sum of the squared difference between the two images;
29 | # NOTE: the two images must have the same dimension
30 | err = np.sum((imageA.astype("float") - imageB.astype("float")) ** 2)
31 | err /= float(imageA.shape[0] * imageA.shape[1])
32 |
33 | # return the MSE, the lower the error, the more "similar"
34 | # the two images are
35 | return err
36 |
37 |
38 | def compare_images(imageA, imageB, title):
39 | # compute the mean squared error and structural similarity
40 | # index for the images
41 | m = mse(imageA, imageB)
42 | print title
43 | print m
44 | print "-----"
45 | s = ssim(imageA, imageB)
46 |
47 | # setup the figure
48 | fig = plt.figure(title)
49 | plt.suptitle("MSE: %.2f, SSIM: %.2f" % (m, s))
50 | #plt.suptitle("MSE: %.2f, SSIM: ??" % (m))
51 | # show first image
52 | ax = fig.add_subplot(1, 2, 1)
53 | plt.imshow(imageA, cmap=plt.cm.gray)
54 | plt.axis("off")
55 |
56 | # show the second image
57 | ax = fig.add_subplot(1, 2, 2)
58 | plt.imshow(imageB, cmap=plt.cm.gray)
59 | plt.axis("off")
60 |
61 | # show the images
62 | plt.show()
63 |
64 | # load the images -- the original, the original + contrast,
65 | # and the original + photoshop
66 |
67 |
68 |
69 | original = cv2.imread("img/img2/jp_gates_contrast.png")
70 | contrast = cv2.imread("img/img2/jp_gates_original.png")
71 | shopped = cv2.imread("img/img2/jp_gates_photoshopped.png")
72 |
73 | # convert the images to grayscale
74 | original = cv2.cvtColor(original, cv2.COLOR_BGR2GRAY)
75 | contrast = cv2.cvtColor(contrast, cv2.COLOR_BGR2GRAY)
76 | shopped = cv2.cvtColor(shopped, cv2.COLOR_BGR2GRAY)
77 |
78 | # initialize the figure
79 | fig = plt.figure("Images")
80 | images = ("Original", original), ("Contrast", contrast), ("Photoshopped", shopped)
81 | #images = ("Original", original), ("Contrast", contrast)
82 | # loop over the images
83 | for (i, (name, image)) in enumerate(images):
84 | # show the image
85 | ax = fig.add_subplot(1, 3, i + 1)
86 | ax.set_title(name)
87 | plt.imshow(image, cmap=plt.cm.gray)
88 | plt.axis("off")
89 |
90 | # show the figure
91 | plt.show()
92 |
93 | # compare the images
94 | compare_images(original, original, "Original vs. Original")
95 | compare_images(original, contrast, "Original vs. Contrast")
96 | compare_images(original, shopped, "Original vs. Photoshopped")
97 |
--------------------------------------------------------------------------------
/tests/testThree.py:
--------------------------------------------------------------------------------
1 | def first():
2 | import PIL
3 | from PIL import Image
4 | from matplotlib import pyplot as plt
5 |
6 | im = Image.open('../img/img1/1.jpg')
7 | w, h = im.size
8 | colors = im.getcolors(w * h)
9 |
10 | def hexencode(rgb):
11 | r = rgb[0]
12 | g = rgb[1]
13 | b = rgb[2]
14 | return '#%02x%02x%02x' % (r, g, b)
15 |
16 | def getColor(im):
17 | im.size
18 |
19 | for idx, c in enumerate(colors):
20 | plt.bar(idx, c[0], color=hexencode(c[1]))
21 | for idx, c in enumerate(colors):
22 | plt.bar(idx, c[0], color=hexencode(c[1]), edgecolor=hexencode(c[1]))
23 |
24 | plt.show()
25 |
26 |
27 | def main():
28 | import cv2
29 | import matplotlib.pyplot as plt
30 |
31 | def show_histogram(im):
32 | """ Function to display image histogram.
33 | Supports single and three channel images. """
34 |
35 | if im.ndim == 2:
36 | # Input image is single channel
37 | plt.hist(im.flatten(), 256, range=(0, 250), fc='k')
38 | plt.show()
39 |
40 | elif im.ndim == 3:
41 | # Input image is three channels
42 | fig = plt.figure()
43 | fig.add_subplot(311)
44 | plt.hist(im[..., 0].flatten(), 256, range=(0, 250), fc='b')
45 | fig.add_subplot(312)
46 | plt.hist(im[..., 1].flatten(), 256, range=(0, 250), fc='g')
47 | fig.add_subplot(313)
48 | plt.hist(im[..., 2].flatten(), 256, range=(0, 250), fc='r')
49 | plt.show()
50 |
51 | if __name__ == '__main__':
52 | im = cv2.imread('../img/img1/1.jpg')
53 | if not (im is None):
54 | show_histogram(im)
55 |
56 |
57 | def two():
58 | import cv2
59 | import matplotlib.pyplot as plt
60 |
61 | im = cv2.imread('../img/img1/1.jpg')
62 | plt.hist(im.flatten(), 256, range=(0, 255))
63 | plt.hist(im[..., 0].flatten(), 256, range=(0, 250), fc='b')
64 | plt.show()
65 |
66 |
67 | def test():
68 | from PIL import Image
69 | import cv2
70 |
71 | path = '../img/img1/1.jpg'
72 | im = Image.open(path)
73 | im2 = cv2.imread(path)[..., 0].flatten()
74 | print len(im2)
75 | array = im.convert("RGB").histogram()
76 | print len(array)
77 |
78 |
79 | def major():
80 | from PIL import Image
81 |
82 | im = Image.open("../img/img1/1.jpg")
83 | return max(im.getcolors(im.size[0] * im.size[1]))
84 |
85 |
86 | def getRgba(path):
87 | from PIL import Image
88 | r, g, b, a = Image.open(path).convert('RGBA').resize((1, 1)).getcolors()[0][1]
89 | return "rgba(%d, %d, %d, %d)" % (r, g, b, a)
90 |
91 |
92 | if __name__ == '__main__':
93 | # two()
94 | # test()
95 | print getRgba("../img/img4/1.jpg")
96 |
--------------------------------------------------------------------------------
/tests/testTwo.py:
--------------------------------------------------------------------------------
1 | import scipy as sp
2 | from scipy.misc import imread
3 | from scipy.signal.signaltools import correlate2d as c2d
4 |
5 |
6 | def get(i):
7 | # get JPG image as Scipy array, RGB (3 layer)
8 | print i
9 | data = imread(i)
10 | # convert to grey-scale using W3C luminance calc
11 | data = sp.inner(data, [299, 587, 114]) / 1000.0
12 | # normalize per http://en.wikipedia.org/wiki/Cross-correlation
13 | return (data - data.mean()) / data.std()
14 |
15 |
16 | im1 = get("./img/1.jpg")
17 | im2 = get("./img/3.jpg")
18 | im3 = get("./img/4.jpg")
19 |
20 | c11 = c2d(im1, im1, mode='same') # baseline
21 | print 'starting...'
22 | print c11.max()
23 |
24 | exit()
25 | c12 = c2d(im1, im2, mode='same')
26 | c13 = c2d(im1, im3, mode='same')
27 | c23 = c2d(im2, im3, mode='same')
28 | print c11.max(), c12.max(), c13.max(), c23.max()
29 |
--------------------------------------------------------------------------------
/tests/test_base.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import json
3 | import StringIO
4 | # from src.module import json_module
5 | # from src import config
6 | # from src.adapter import db
7 | import hashlib, time, os
8 |
9 | import unittest
10 |
11 | from subprocess import call
12 |
13 |
14 | class TestBaseSearch(unittest.TestCase):
15 | # def nottest_first(self):
16 | # ''' there is processing img and return img list '''
17 | # file_path = '/Users/liyang/Code/picture-compare/img/img1/1.jpg'
18 | # tmp_name = file_path
19 | # terms = []
20 | # from src.service.compare import Compare
21 | # compareDict = Compare().setCompareImage(tmp_name, terms)
22 | # for item in compareDict:
23 | # # print call(['imgo '+item['url']])
24 | # print call(['id -un'])
25 | # self.assertTrue(len(compareDict) > 0)
26 | def test_base(self):
27 | self.assertEqual(True, True)
28 |
29 |
30 | def test_module(self):
31 | print '\n\nstart'
32 | from src.service.compare import Compare
33 | file_path = '/Users/liyang/Code/picture-compare/img/img1/1.jpg'
34 | compareDict = Compare().start(file_path)
35 | self.assertEqual(True, True)
36 |
37 | def main():
38 | suite = unittest.TestLoader().loadTestsFromTestCase(TestBaseSearch)
39 | unittest.TextTestRunner(verbosity=2).run(suite)
40 |
--------------------------------------------------------------------------------
/tests/test_camera.py:
--------------------------------------------------------------------------------
1 | # o
2 |
3 | import cv2
4 | import sys
5 |
6 | cascPath = sys.argv[1]
7 | faceCascade = cv2.CascadeClassifier(cascPath)
8 |
9 | video_capture = cv2.VideoCapture(0)
10 |
11 | # 捕捉人脸
12 | while True:
13 | # Capture frame-by-frame
14 | ret, frame = video_capture.read()
15 |
16 | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
17 |
18 | faces = faceCascade.detectMultiScale(
19 | gray,
20 | scaleFactor=1.1,
21 | minNeighbors=5,
22 | minSize=(30, 30),
23 | flags=cv2.cv.CV_HAAR_SCALE_IMAGE
24 | )
25 |
26 | # Draw a rectangle around the faces
27 | for (x, y, w, h) in faces:
28 | cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
29 |
30 | # Display the resulting frame
31 | cv2.imshow('Video', frame)
32 |
33 | if cv2.waitKey(1) & 0xFF == ord('q'):
34 | break
35 |
36 | # When everything is done, release the capture
37 | video_capture.release()
38 | cv2.destroyAllWindows()
39 |
--------------------------------------------------------------------------------
/tests/test_index.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | import os
3 | import json
4 | import requests
5 |
6 | class Index:
7 | target_url = "http://120.25.56.146:1565/_index"
8 | def index(self.id, name, image_url):
9 | post = {
10 | 'query' : {
11 | 'id' : id,
12 | 'name' : name,
13 | 'url' : image_url,
14 | 'search' : {
15 | },
16 | 'data': {
17 | 'origin_url' image_url:,
18 | },
19 | }
20 | }
21 | payload = payload % (id, name, image_url, image_url)
22 | headers = {
23 | 'content-type': "application/json",
24 | }
25 | response = requests.request(
26 | "POST",
27 | self.target_url,
28 | data=payload,
29 | headers=headers
30 | )
31 | print(response.text)
32 |
33 | if __name__ == '__main__':
34 | # 请把本地图片上传到在线服务器
35 | # 并把对应内容填写到下面的变量
36 | # python main.py
37 | online_image_repo = 'http://online.app/images/'
38 | local_image_repo = '/Users/n/image_repo'
39 | img_list = os.listdir(path)
40 | capsule = Index()
41 | for i in img_list:
42 | capsule.index(img_list.index(i), i, online_repo_url + i)
43 |
--------------------------------------------------------------------------------
/tests/test_interceptors.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import logging
3 | import logging.config
4 | import tornado.httpserver
5 | import tornado.ioloop
6 | import tornado.web
7 |
8 | log = logging.getLogger("root")
9 |
10 |
11 | def interceptor(func):
12 | """
13 | This is a class decorator which is helpful in configuring
14 | one or more interceptors which are able to intercept, inspect,
15 | process and approve or reject further processing of the request
16 | """
17 |
18 | def classwrapper(cls):
19 | def wrapper(old):
20 | def inner(self, transforms, *args, **kwargs):
21 | print self.request
22 | print old
23 | return old(self, transforms, *args, **kwargs)
24 | return inner
25 | cls._execute = wrapper(cls._execute)
26 | return cls
27 | return classwrapper
28 |
29 |
30 | @interceptor("func-")
31 | class MainHandler(tornado.web.RequestHandler):
32 | def get(self):
33 | self.write("Hello, interceptor")
34 |
35 |
36 | application = tornado.web.Application([
37 | (r"/", MainHandler),
38 | ])
39 |
40 | if __name__ == "__main__":
41 | http_server = tornado.httpserver.HTTPServer(application)
42 | http_server.listen(3232)
43 | tornado.ioloop.IOLoop.instance().start()
44 |
45 |
--------------------------------------------------------------------------------
/tests/test_queue.py:
--------------------------------------------------------------------------------
1 | import HTMLParser
2 | import time
3 | import urlparse
4 | from datetime import timedelta
5 |
6 | from tornado import httpclient, gen, ioloop, queues
7 |
8 | base_url = 'http://www.tornadoweb.org/en/stable/'
9 | concurrency = 10
10 |
11 |
12 | @gen.coroutine
13 | def get_links_from_url(url):
14 | """Download the page at `url` and parse it for links.
15 |
16 | Returned links have had the fragment after `#` removed, and have been made
17 | absolute so, e.g. the URL 'gen.html#tornado.gen.coroutine' becomes
18 | 'http://www.tornadoweb.org/en/stable/gen.html'.
19 | """
20 | try:
21 | response = yield httpclient.AsyncHTTPClient().fetch(url)
22 | print('fetched %s' % url)
23 | urls = [urlparse.urljoin(url, remove_fragment(new_url))
24 | for new_url in get_links(response.body)]
25 | except Exception as e:
26 | print('Exception: %s %s' % (e, url))
27 | raise gen.Return([])
28 |
29 | raise gen.Return(urls)
30 |
31 |
32 | def remove_fragment(url):
33 | scheme, netloc, url, params, query, fragment = urlparse.urlparse(url)
34 | return urlparse.urlunparse((scheme, netloc, url, params, query, ''))
35 |
36 |
37 | def get_links(html):
38 | class URLSeeker(HTMLParser.HTMLParser):
39 | def __init__(self):
40 | HTMLParser.HTMLParser.__init__(self)
41 | self.urls = []
42 |
43 | def handle_starttag(self, tag, attrs):
44 | href = dict(attrs).get('href')
45 | if href and tag == 'a':
46 | self.urls.append(href)
47 |
48 | url_seeker = URLSeeker()
49 | url_seeker.feed(html)
50 | return url_seeker.urls
51 |
52 |
53 | @gen.coroutine
54 | def main():
55 | q = queues.Queue()
56 | start = time.time()
57 | fetching, fetched = set(), set()
58 |
59 | @gen.coroutine
60 | def fetch_url():
61 | current_url = yield q.get()
62 | try:
63 | if current_url in fetching:
64 | return
65 |
66 | print('fetching %s' % current_url)
67 | fetching.add(current_url)
68 | urls = yield get_links_from_url(current_url)
69 | fetched.add(current_url)
70 |
71 | for new_url in urls:
72 | # Only follow links beneath the base URL
73 | if new_url.startswith(base_url):
74 | yield q.put(new_url)
75 |
76 | finally:
77 | q.task_done()
78 |
79 | @gen.coroutine
80 | def worker():
81 | while True:
82 | yield fetch_url()
83 |
84 | q.put(base_url)
85 |
86 | # Start workers, then wait for the work queue to be empty.
87 | for _ in range(concurrency):
88 | worker()
89 | yield q.join(timeout=timedelta(seconds=300))
90 | assert fetching == fetched
91 | print('Done in %d seconds, fetched %s URLs.' % (
92 | time.time() - start, len(fetched)))
93 |
94 |
95 | if __name__ == '__main__':
96 | import logging
97 | logging.basicConfig()
98 | io_loop = ioloop.IOLoop.current()
99 | io_loop.run_sync(main)
--------------------------------------------------------------------------------
/tests/test_time.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | class Testsample1():
3 | """This is a dummy test file used for testing testimony"""
4 |
5 | def test_picture_compare(self):
6 | # Code to perform the test
7 | pass
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------