commit e76128b095684816c0422bae4ab2f7da63189af9 Author: paolo.bolettieri Date: Tue Mar 14 12:09:08 2023 +0100 Image Recognition code of Extension Project diff --git a/BEBLIDBulkExtractionFromFileList.py b/BEBLIDBulkExtractionFromFileList.py new file mode 100755 index 0000000..44f7062 --- /dev/null +++ b/BEBLIDBulkExtractionFromFileList.py @@ -0,0 +1,33 @@ +from pathlib import Path +import tqdm + +import LFUtilities +import BEBLIDExtractor as lf +import argparse +import os + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='BEBLID bulk extraction') + parser.add_argument('src', type=str, help='text file containing a list of img paths') + parser.add_argument('dest', type=str, help='BEBLID dest file') + + args = parser.parse_args() + src = args.src + dest = args.dest + + with open(src, 'r') as src_file: + dataset = [] + + print('Extracting lf...') + for line in src_file: + try: + kp, des = lf.extract(line.strip()) + dataset.append((kp, des)) + except: + print("cannot process '%s'" % line) + pass + + LFUtilities.save(dataset, dest) + + print('lf extracted.') diff --git a/BEBLIDExtractor.py b/BEBLIDExtractor.py new file mode 100755 index 0000000..a48d128 --- /dev/null +++ b/BEBLIDExtractor.py @@ -0,0 +1,19 @@ +import cv2 +from pathlib import Path +import tqdm +import pickle +import os +import LFUtilities + +import BEBLIDParameters as params + +detector = cv2.ORB_create(params.KEYPOINTS) +descriptor = cv2.xfeatures2d.BEBLID_create(0.75) + + +def extract(img_path): + img = LFUtilities.resize(params.IMG_SIZE, cv2.imread(img_path)) + kp = detector.detect(img, None) + kp, des = descriptor.compute(img, kp) + return (kp, des) + diff --git a/BEBLIDParameters.py b/BEBLIDParameters.py new file mode 100755 index 0000000..0fe480d --- /dev/null +++ b/BEBLIDParameters.py @@ -0,0 +1,5 @@ +NN_MATCH_RATIO = 0.8 +MIN_GOOD_MATCHES = 20 +MIN_INLIERS = 16 +KEYPOINTS = 1000 +IMG_SIZE = 1000 \ No newline at end of file diff --git a/BEBLIDRescorer.py b/BEBLIDRescorer.py new file mode 100755 index 0000000..9c4e947 --- /dev/null +++ b/BEBLIDRescorer.py @@ -0,0 +1,68 @@ +import cv2 +import numpy as np + +import LFUtilities +import BEBLIDParameters +import WebAppSettings as settings + + +class BEBLIDRescorer: + + def __init__(self): + self.lf = LFUtilities.load(settings.DATASET_BEBLID) + self.ids = np.loadtxt(settings.DATASET_IDS, dtype=str).tolist() + #self.bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) + self.bf = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE_HAMMING) + + def rescore_by_id(self, query_id, resultset): + query_idx = self.ids.index(query_id) + return self.rescore_by_img(self.lf[query_idx], resultset) + + def rescore_by_img(self, query, resultset): + max_inliers = -1 + res = [] + + for data_id, _ in resultset: + data_idx = self.ids.index(data_id) + try: + data_el = self.lf[data_idx] + + nn_matches = self.bf.knnMatch(query[1], data_el[1], 2) + good = [m for m, n in nn_matches if m.distance < BEBLIDParameters.NN_MATCH_RATIO * n.distance] + + if len(good) > BEBLIDParameters.MIN_GOOD_MATCHES: + src_pts = np.float32([query[0][m.queryIdx].pt for m in good]).reshape(-1, 1, 2) + dst_pts = np.float32([data_el[0][m.trainIdx].pt for m in good]).reshape(-1, 1, 2) + + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 1.0) + matches_mask = mask.ravel().tolist() + # print(len(good)) + inliers = np.count_nonzero(matches_mask) + # print(inliers) + if (inliers >= BEBLIDParameters.MIN_INLIERS and inliers > max_inliers): + max_inliers = inliers + res.append((data_id, round(inliers/len(good), 3))) + except: + print('rescore error evaluating ' + data_id) + pass + + if res: + res.sort(key=lambda result: result[1], reverse=True) + return res + + def add(self, lf): + self.lf.append(lf) + + def remove(self, idx): + self.descs = np.delete(self.descs, idx, axis=0) + + def save(self, is_backup=False): + lf_save_file = settings.DATASET_LF + ids_file = settings.DATASET_IDS_LF + if lf_save_file != "None": + if is_backup: + lf_save_file += '.bak' + ids_file += '.bak' + + LFUtilities.save(lf_save_file, self.lf) + np.savetxt(ids_file, self.ids, fmt='%s') diff --git a/BEBLIDSearcher.py b/BEBLIDSearcher.py new file mode 100755 index 0000000..0bbfa19 --- /dev/null +++ b/BEBLIDSearcher.py @@ -0,0 +1,69 @@ +import cv2 +import numpy as np + +import LFUtilities +import BEBLIDParameters +import WebAppSettings as settings + + +class BEBLIDSearcher: + + def __init__(self): + self.lf = LFUtilities.load(settings.DATASET_BEBLID) + self.ids = np.loadtxt(settings.DATASET_IDS, dtype=str).tolist() + #self.bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) + self.bf = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE_HAMMING) + + def get_id(self, idx): + return self.ids[idx] + + def search_by_id(self, query_id): + query_idx = self.ids.index(query_id) + return self.search_by_img(self.lf[query_idx]) + + def search_by_img(self, query): + max_inliers = -1 + res = [] + + for img_id, features in zip(self.ids, self.lf): + try: + nn_matches = self.bf.knnMatch(query[1], features[1], 2) + good = [m for m, n in nn_matches if m.distance < BEBLIDParameters.NN_MATCH_RATIO * n.distance] + + if len(good) > BEBLIDParameters.MIN_GOOD_MATCHES: + src_pts = np.float32([query[0][m.queryIdx].pt for m in good]).reshape(-1, 1, 2) + dst_pts = np.float32([features[0][m.trainIdx].pt for m in good]).reshape(-1, 1, 2) + + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 1.0) + matches_mask = mask.ravel().tolist() + # print(len(good)) + inliers = np.count_nonzero(matches_mask) + # print(inliers) + if (inliers >= BEBLIDParameters.MIN_INLIERS and inliers > max_inliers): + max_inliers = inliers + class_name = img_id.split('/')[0] + res.append((class_name, round(inliers/len(good), 3))) + except: + print('search error evaluating ' + img_id) + pass + + if res: + res.sort(key=lambda result: result[1], reverse=True) + return res + + def add(self, lf): + self.lf.append(lf) + + def remove(self, idx): + self.descs = np.delete(self.descs, idx, axis=0) + + def save(self, is_backup=False): + lf_save_file = settings.DATASET_LF + ids_file = settings.DATASET_IDS_LF + if lf_save_file != "None": + if is_backup: + lf_save_file += '.bak' + ids_file += '.bak' + + LFUtilities.save(lf_save_file, self.lf) + np.savetxt(ids_file, self.ids, fmt='%s') diff --git a/BeniCulturaliOut.py b/BeniCulturaliOut.py new file mode 100755 index 0000000..769077d --- /dev/null +++ b/BeniCulturaliOut.py @@ -0,0 +1,91 @@ +import h5py +import numpy as np + +rmac_out_file = '/media/Data/data/beni_culturali/out/rmac_out.txt' +orb_out_file = '/media/Data/data/beni_culturali/out/orb_out.txt' + +ground_truth_file = '/media/Data/data/beni_culturali/groundtruth.txt' + +ground_truth = {} +rmac_out = {} +orb_out = {} + +query_folder = '/media/Data/data/beni_culturali/ImmaginiComparazioni/' +img_folder = '/media/Data/data/beni_culturali/thumbs/' + +with open(ground_truth_file, 'r') as f: + for line in f: + values = line.strip().split(',') + ground_truth[values[0]] = values[1:] + +with open(orb_out_file, 'r') as f: + for line in f: + values = line.strip().split(',') + orb_out[values[0]] = values[1] + +with open(rmac_out_file, 'r') as f: + for line in f: + values = line.strip().split(',') + rmac_out[values[0]] = values[1:] + +counter = 0 +found = 0 + +html = '' +html += '

Image Analysis Report

' +html += '

Numero totale query: 64 (una query è ripetuta due volte)

' +html += '

Immagini Recuperate (evidenziate dal bordo verde):

' +html += '' + +html += '

Elenco delle query e delle immagini recuperate:

' +html += '

[query, immagine ritrovata, posizione (ranking)]


' + +counter = 1 + +for key, value in ground_truth.items(): + orb_res = orb_out[key] + rmac_res = rmac_out[key] + #print(key) + #print(value) + # print(orb_res + '\n') + html += '
' + str(counter) + '. ' + key + '' + tmp = '' + found_id = '' + found = False + k = 0 + if orb_res in value: + found = True + found_id = orb_res + ground_truth[key] = 'already_found' + tmp += '' + + else: + for k in range(60): + if rmac_res[k] in value: + tmp += '' + found = True + found_id = rmac_res[k] + ground_truth[key] = 'already_found' + break + if k < 2: + tmp += '' + else: + tmp += '.' + + if found: + html += ', ' + found_id + '' + ', (ranking: ' + str(k + 1) + ')' + else: + html += ', NONE' + + html += '

' + if found: + html += tmp + else: + html += '' + + html += '

' + counter += 1 +html += '' +print(html) diff --git a/ExtensionBot.py b/ExtensionBot.py new file mode 100755 index 0000000..3e9ed22 --- /dev/null +++ b/ExtensionBot.py @@ -0,0 +1,77 @@ +from telegram import ReplyKeyboardMarkup, KeyboardButton +from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ContextTypes +import requests +import json +import telegram +import re + +endpoint = "http://bilioso.isti.cnr.it:8190/bcir/searchByURL" +endpoint_rescorer = "http://bilioso.isti.cnr.it:8190/bcir/setRescorer" + + + +def start(update, context): + chat_id = update.effective_chat.id + # custom_keyboard = [['top-left', 'top-right'], ['bottom-left', 'bottom-right']] + # reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) + # context.bot.send_message(chat_id=chat_id, text = "Custom Keyboard Test", reply_markup = reply_markup) + # context.bot.send_message(chat_id=chat_id, text = "Custom Keyboard Test") + photo_id = update.message.photo[-1].file_id + if (photo_id is None): + print(update.message) + query = context.bot.getFile(photo_id) + print(query.file_path) + # r = requests.get(endpoint, params=params) + # json_res = json.loads(r.text) + response = "Sorry, I can't recognize it :-(" + # if json_res is not None: + # title = re.sub("\\d", "", json_res['title']) + # response = "*" + json_res['author'] + "*, _" + title + "_\n\n" + # response += json_res['artworkPage'] + # update.message.reply_text(response) + text = endpoint + '?tohtml=true&url=' + query.file_path + + + print(text) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + params = {'url': query.file_path, 'securityID': 'FA6mMmeWZ8JjWKz5'} + print(query.file_path) + r = requests.get(endpoint, params=params) + text = json.loads(r.text) + print(text) + + #context.bot.send_message(chat_id=chat_id, text='GEM', parse_mode=telegram.ParseMode.HTML) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + +''' +def commands(update, context): + text = update.message.text + if text.lower() == 'commands': + chat_id = update.effective_chat.id + markup = ReplyKeyboardMarkup(keyboard=[['GEM', KeyboardButton(text='BEBLID')],["GEM_TH", "BEB_TH"]]) + context.bot.sendMessage(chat_id=chat_id, text="available commands", reply_markup=markup, parse_mode=telegram.ParseMode.HTML) + if text == "BEBLID": + params = {'rescorer': 'true'} + elif text == "GEM": + params = {'rescorer': 'false'} + r = requests.get(endpoint_rescorer, params=params) + res = r.text + print(res) + update.message.reply_text(res) +''' + +def call_service(query): + print(query) + files = {'img': query} + r = requests.post(endpoint, files=files) + return r.text + + +updater = Updater('2140606085:AAHEBR3a_O9b8E8tbJFaWopDUvT4ptAUkP4') + +updater.dispatcher.add_handler(MessageHandler(Filters.photo, start)) +#updater.dispatcher.add_handler(MessageHandler(Filters.text, commands)) +updater.start_polling() + +updater.idle() diff --git a/ExtensionBotBase64.py b/ExtensionBotBase64.py new file mode 100644 index 0000000..9c6eee3 --- /dev/null +++ b/ExtensionBotBase64.py @@ -0,0 +1,105 @@ +from telegram.ext import Updater, CommandHandler, MessageHandler, Filters +import requests +import json +import telegram +import re +import uuid +import urllib +import cv2 +import io +import numpy as np +import json +import LFUtilities +import base64 + +endpoint = "http://bilioso.isti.cnr.it:8190/bcir/searchByImgB64" + +log_folder = "/media/Data/data/extension/img_recognition/bot" + + +def url_to_file(url): + dest_file = uuid.uuid4().hex + ".png" + dest_path = log_folder + "/" + dest_file + req = urllib.request.Request( + url, + data=None, + headers={ + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' + } + ) + resp = urllib.request.urlopen(req) + image = np.asarray(bytearray(resp.read()), dtype="uint8") + decoded = cv2.imdecode(image, cv2.IMREAD_COLOR) + resized = LFUtilities.resize(500, decoded) + cv2.imwrite(dest_path, resized) + #im = Image.fromarray(image) + #im.save(dest_path) + return dest_path + + +def start(update, context): + chat_id = update.effective_chat.id + # custom_keyboard = [['top-left', 'top-right'], ['bottom-left', 'bottom-right']] + # reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) + # context.bot.send_message(chat_id=chat_id, text = "Custom Keyboard Test", reply_markup = reply_markup) + # context.bot.send_message(chat_id=chat_id, text = "Custom Keyboard Test") + photo_id = update.message.photo[-1].file_id + query = context.bot.getFile(photo_id) + params = {'url': query.file_path} + img_file = url_to_file(query.file_path) + + with open(img_file, "rb") as image_file: + encoded_string = base64.b64encode(image_file.read()) + + # r = requests.get(endpoint, params=params) + # json_res = json.loads(r.text) + response = "Sorry, I can't recognize it :-(" + # if json_res is not None: + # title = re.sub("\\d", "", json_res['title']) + # response = "*" + json_res['author'] + "*, _" + title + "_\n\n" + # response += json_res['artworkPage'] + # update.message.reply_text(response) + text = endpoint + '?tohtml=true&url=' + query.file_path + + + + + print(text) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + data = {'image': encoded_string, 'securityID': 'FA6mMmeWZ8JjWKz5', 'rescorer': 'false', 'lf_impl': 'beblid'} + r = requests.post(endpoint, data=data) + text = json.loads(r.text) + print(text) + + #context.bot.send_message(chat_id=chat_id, text='GEM', parse_mode=telegram.ParseMode.HTML) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + data = {'image': encoded_string, 'securityID': 'FA6mMmeWZ8JjWKz5', 'rescorer': 'true', 'lf_impl': 'beblid'} + r = requests.post(endpoint, data=data) + text = json.loads(r.text) + print(text) + + # context.bot.send_message(chat_id=chat_id, text='GEM', parse_mode=telegram.ParseMode.HTML) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + + + +def hello(bot, update): + update.message.reply_text( + 'Hello {}'.format(update.message.from_user.first_name)) + + +def call_service(query): + files = {'img': query} + r = requests.post(endpoint, files=files) + return r.text + + +updater = Updater('2140606085:AAHEBR3a_O9b8E8tbJFaWopDUvT4ptAUkP4') + +updater.dispatcher.add_handler(MessageHandler(Filters.photo, start)) +updater.dispatcher.add_handler(CommandHandler('hello', hello)) +updater.start_polling() +updater.idle() diff --git a/ExtensionBotTest.py b/ExtensionBotTest.py new file mode 100755 index 0000000..c94daba --- /dev/null +++ b/ExtensionBotTest.py @@ -0,0 +1,87 @@ +from telegram.ext import Updater, CommandHandler, MessageHandler, Filters +import requests +import json +import telegram +import re + +endpoint = "http://bilioso.isti.cnr.it:8290/bcirtest/searchByURL" + + +def start(update, context): + chat_id = update.effective_chat.id + # custom_keyboard = [['top-left', 'top-right'], ['bottom-left', 'bottom-right']] + # reply_markup = telegram.ReplyKeyboardMarkup(custom_keyboard) + # context.bot.send_message(chat_id=chat_id, text = "Custom Keyboard Test", reply_markup = reply_markup) + # context.bot.send_message(chat_id=chat_id, text = "Custom Keyboard Test") + photo_id = update.message.photo[-1].file_id + query = context.bot.getFile(photo_id) + params = {'url': query.file_path} + print(query.file_path) + # r = requests.get(endpoint, params=params) + # json_res = json.loads(r.text) + response = "Sorry, I can't recognize it :-(" + # if json_res is not None: + # title = re.sub("\\d", "", json_res['title']) + # response = "*" + json_res['author'] + "*, _" + title + "_\n\n" + # response += json_res['artworkPage'] + # update.message.reply_text(response) + text = endpoint + '?tohtml=true&url=' + query.file_path + + + + + print(text) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + #-GEM-# + params = {'url': query.file_path} + r = requests.get(endpoint, params=params) + text = json.loads(r.text) + print(text) + + context.bot.send_message(chat_id=chat_id, text='GEM', parse_mode=telegram.ParseMode.HTML) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + #-ORB-# + params = {'url': query.file_path, 'rescorer': 'true', 'lf_impl': 'orb'} + r = requests.get(endpoint, params=params) + text = json.loads(r.text) + print(text) + context.bot.send_message(chat_id=chat_id, text='ORB', parse_mode=telegram.ParseMode.HTML) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + #-BEBLID-# + params = {'url': query.file_path, 'rescorer': 'true', 'lf_impl': 'beblid'} + r = requests.get(endpoint, params=params) + text = json.loads(r.text) + print(text) + + context.bot.send_message(chat_id=chat_id, text='BEBLID', parse_mode=telegram.ParseMode.HTML) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + + # -LATCH-# + params = {'url': query.file_path, 'rescorer': 'true', 'lf_impl': 'latch'} + r = requests.get(endpoint, params=params) + text = json.loads(r.text) + print(text) + + context.bot.send_message(chat_id=chat_id, text='LATCH', parse_mode=telegram.ParseMode.HTML) + context.bot.send_message(chat_id=chat_id, text=text, parse_mode=telegram.ParseMode.HTML) + +def hello(bot, update): + update.message.reply_text( + 'Hello {}'.format(update.message.from_user.first_name)) + + +def call_service(query): + files = {'img': query} + r = requests.post(endpoint, files=files) + return r.text + + +updater = Updater('2140606085:AAHEBR3a_O9b8E8tbJFaWopDUvT4ptAUkP4') + +updater.dispatcher.add_handler(MessageHandler(Filters.photo, start)) +updater.dispatcher.add_handler(CommandHandler('hello', hello)) +updater.start_polling() +updater.idle() diff --git a/GEMExtractor.py b/GEMExtractor.py new file mode 100755 index 0000000..550cdf9 --- /dev/null +++ b/GEMExtractor.py @@ -0,0 +1,10 @@ +import numpy as np +import WebAppSettings as settings +import requests + + +def extract(img_path): + files = {'image': ('img', open(img_path, 'rb'))} + data = {'resize': 'true'} + r = requests.post(settings.feature_extractor, data=data, files=files) + return np.array(r.json()) diff --git a/GEMSearcher.py b/GEMSearcher.py new file mode 100755 index 0000000..7de58ef --- /dev/null +++ b/GEMSearcher.py @@ -0,0 +1,61 @@ +import h5py +import numpy as np +import WebAppSettings as settings + + +class GEMSearcher: + + + def __init__(self): + #self.dataset = h5py.File(settings.dataset_file, 'r')['rmac'][...] + + #np.save('/media/Data/data/beni_culturali/deploy/dataset', self.dataset) + self.descs = np.load(settings.DATASET_GEM) + #self.desc1 = np.load(settings.DATASET1) + #self.desc2 = np.load(settings.DATASET2) + + #self.descs = (self.desc1 + self.desc2) / 2 + #self.descs /= np.linalg.norm(self.descs, axis=1, keepdims=True) + self.ids = np.loadtxt(settings.DATASET_IDS, dtype=str).tolist() + + + def get_id(self, idx): + return self.ids[idx] + + + def add(self, desc, id): + self.ids.append(id) + self.descs = np.vstack((self.descs, desc)) + self.save() + + + def remove(self, id): + idx = self.ids.index(id) + del self.ids[idx] + self.descs = np.delete(self.descs, idx, axis=0) + + + def search_by_id(self, query_id, k=10): + query_idx = self.ids.index(query_id) + return self.search_by_img(self.descs[query_idx], k) + + def search_by_img(self, query, k=10): + # print('----------query features-------') + #print(query) + dot_product = np.dot(self.descs, query[0]) + idx = dot_product.argsort()[::-1][:k] + res = [] + for i in idx: + res.append((self.ids[i], round(float(dot_product[i]), 3))) + return res + + def save(self, is_backup=False): + descs_file = settings.DATASET + ids_file = settings.DATASET_IDS + + if is_backup: + descs_file += '.bak' + ids_file += '.bak' + + np.save(descs_file, self.descs) + np.savetxt(ids_file, self.ids, fmt='%s') diff --git a/Heic2Png.py b/Heic2Png.py new file mode 100644 index 0000000..50201db --- /dev/null +++ b/Heic2Png.py @@ -0,0 +1,16 @@ +from PIL import Image +import pyheif + +def conv(image_path): + new_name = image_path.replace('heic', 'png') + heif_file = pyheif.read(image_path) + data = Image.frombytes( + heif_file.mode, + heif_file.size, + heif_file.data, + "raw", + heif_file.mode, + heif_file.stride, + ) + data.save(new_name, "PNG") + return new_name \ No newline at end of file diff --git a/LATCHBulkExtractionFromFileList.py b/LATCHBulkExtractionFromFileList.py new file mode 100755 index 0000000..9d890d3 --- /dev/null +++ b/LATCHBulkExtractionFromFileList.py @@ -0,0 +1,33 @@ +from pathlib import Path +import tqdm + +import LFUtilities +import LATCHExtractor as lf +import argparse +import os + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='LATCH bulk extraction') + parser.add_argument('src', type=str, help='text file containing a list of img paths') + parser.add_argument('dest', type=str, help='LATCH dest file') + + args = parser.parse_args() + src = args.src + dest = args.dest + + with open(src, 'r') as src_file: + dataset = [] + + print('Extracting lf...') + for line in src_file: + try: + kp, des = lf.extract(line.strip()) + dataset.append((kp, des)) + except: + print("cannot process '%s'" % line) + pass + + LFUtilities.save(dataset, dest) + + print('lf extracted.') diff --git a/LATCHExtractor.py b/LATCHExtractor.py new file mode 100755 index 0000000..2835848 --- /dev/null +++ b/LATCHExtractor.py @@ -0,0 +1,16 @@ +import cv2 +import LFUtilities + +import LATCHParameters as params + +detector = cv2.ORB_create(params.KEYPOINTS) +#descriptor = cv2.xfeatures2d.LATCH_create(1, True, 15) +descriptor = cv2.xfeatures2d.LATCH_create() + + +def extract(img_path): + img = LFUtilities.resize(params.IMG_SIZE, cv2.imread(img_path)) + kp = detector.detect(img, None) + kp, des = descriptor.compute(img, kp) + return (kp, des) + diff --git a/LATCHParameters.py b/LATCHParameters.py new file mode 100755 index 0000000..1cf62dc --- /dev/null +++ b/LATCHParameters.py @@ -0,0 +1,5 @@ +THRESHOLD = 70 +MIN_GOOD_MATCHES = 12 +MIN_INLIERS = 8 +KEYPOINTS = 5000 +IMG_SIZE = 500 \ No newline at end of file diff --git a/LATCHRescorer.py b/LATCHRescorer.py new file mode 100755 index 0000000..59cc558 --- /dev/null +++ b/LATCHRescorer.py @@ -0,0 +1,67 @@ +import cv2 +import numpy as np + +import LFUtilities +import LATCHParameters +import WebAppSettings as settings + + +class LATCHRescorer: + + def __init__(self): + self.lf = LFUtilities.load(settings.DATASET_LATCH) + self.ids = np.loadtxt(settings.DATASET_IDS, dtype=str).tolist() + + #self.orb = cv2.LATCH_create() + self.bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) + + def rescore_by_id(self, query_id, resultset): + query_idx = self.ids.index(query_id) + return self.rescore_by_img(self.lf[query_idx], resultset) + + def rescore_by_img(self, query, resultset): + max_inliers = -1 + res = [] + + for data_id, _ in resultset: + data_idx = self.ids.index(data_id) + try: + data_el = self.lf[data_idx] + matches = self.bf.match(query[1], data_el[1]) + good = [m for m in matches if m.distance <= LATCHParameters.THRESHOLD] + if len(good) > LATCHParameters.MIN_GOOD_MATCHES: + src_pts = np.float32([query[0][m.queryIdx].pt for m in good]).reshape(-1, 1, 2) + dst_pts = np.float32([data_el[0][m.trainIdx].pt for m in good]).reshape(-1, 1, 2) + + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 1.0) + matches_mask = mask.ravel().tolist() + # print(len(good)) + inliers = np.count_nonzero(matches_mask) + # print(inliers) + if (inliers >= LATCHParameters.MIN_INLIERS and inliers > max_inliers): + max_inliers = inliers + res.append((data_id, inliers)) + except: + print('rescore error evaluating ' + data_id) + pass + + if res: + res.sort(key=lambda result: result[1], reverse=True) + return res + + def add(self, lf): + self.lf.append(lf) + + def remove(self, idx): + self.descs = np.delete(self.descs, idx, axis=0) + + def save(self, is_backup=False): + lf_save_file = settings.DATASET_LF + ids_file = settings.DATASET_IDS_LF + if lf_save_file != "None": + if is_backup: + lf_save_file += '.bak' + ids_file += '.bak' + + LFUtilities.save(lf_save_file, self.lf) + np.savetxt(ids_file, self.ids, fmt='%s') diff --git a/LFBulkExtraction.py b/LFBulkExtraction.py new file mode 100755 index 0000000..510d19c --- /dev/null +++ b/LFBulkExtraction.py @@ -0,0 +1,38 @@ +from pathlib import Path +import tqdm + +import LFUtilities +import ORBExtractor as lf +import argparse +import os + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='LF bulk extraction') + parser.add_argument('src', type=str, help='img src folder path') + parser.add_argument('dest', type=str, help='lf dest folder') + + args = parser.parse_args() + src = args.src + dest = args.dest + + paths = Path(src).rglob('*.*') + paths_list = list(paths) + + dataset = [] + + print('Extracting lf...') + for path in tqdm.tqdm(paths_list): + try: + kp, des = lf.extract(os.path.join(path.parent, path.name)) + dataset.append((kp, des)) + except: + print("cannot process '%s'" % path) + pass + + LFUtilities.save(dataset, os.path.join(dest, 'dataset_lf.dat')) + with open(os.path.join(dest, 'dataset_lf.ids'), 'w') as f: + for path in paths_list: + id, _ = os.path.splitext(path.name) + f.write("%s\n" % id) + print('lf extracted.') diff --git a/LFSearcher.py b/LFSearcher.py new file mode 100755 index 0000000..f5c4536 --- /dev/null +++ b/LFSearcher.py @@ -0,0 +1,54 @@ +import cv2 +import numpy as np +import pickle as pickle + +import LFUtilities +import WebAppSettings as settings +from BEBLIDSearcher import BEBLIDSearcher +import GEMExtractor as fe +import ORBExtractor as lf +import BEBLIDExtractor as beblid_lf +import LATCHExtractor as latch_lf + + +class Searcher: + + def __init__(self): + # self.dataset = h5py.File(settings.dataset_file, 'r')['rmac'][...] + + # np.save('/media/Data/data/beni_culturali/deploy/dataset', self.dataset) + self.search_engine = BEBLIDSearcher() + + def get_id(self, idx): + return self.search_engine.get_id(idx) + + def add(self, img_file, id): + self.save(True) + + desc = fe.extract(img_file) + orb = lf.extract(img_file) + self.search_engine.add(desc, id) + + self.save() + print('added ' + id) + + def remove(self, id): + self.save(True) + self.search_engine.remove(id) + self.save() + print('removed ' + id) + + def search_by_id(self, query_id, k=10): + kq = k + res = self.search_engine.search_by_id(query_id) + return res + + def search_by_img(self, query_img, k=10): + kq = k + query_desc = beblid_lf.extract(query_img) + res = self.search_engine.search_by_img(query_desc) + return res + + def save(self, is_backup=False): + self.search_engine.save(is_backup) + #self.rescorer.save(is_backup) diff --git a/LFUtilities.py b/LFUtilities.py new file mode 100755 index 0000000..75abcb8 --- /dev/null +++ b/LFUtilities.py @@ -0,0 +1,59 @@ +import cv2 +import numpy as np +import pickle as pickle +import os + +def resize(max_side, img): + if img.shape[1] > img.shape[0]: + r = max_side / img.shape[1] + dim = (max_side, int(img.shape[0] * r)) + else: + r = max_side / img.shape[0] + dim = (int(img.shape[1] * r), max_side) + + # perform the actual resizing of the image and show it + resized = cv2.resize(img, dim, interpolation=cv2.INTER_AREA) + return resized + + +def pickle_keypoints(keypoints, descriptors): + i = 0 + temp_array = [] + for point in keypoints: + temp = (point.pt, point.size, point.angle, point.response, point.octave, + point.class_id, descriptors[i]) + i += 1 + temp_array.append(temp) + return temp_array + + +def unpickle_keypoints(array): + keypoints = [] + descriptors = [] + for point in array: + temp_feature = cv2.KeyPoint(x=point[0][0],y=point[0][1], size=point[1], angle=point[2], response=point[3], octave=point[4], class_id=point[5]) + temp_descriptor = point[6] + keypoints.append(temp_feature) + descriptors.append(temp_descriptor) + return keypoints, np.array(descriptors) + + +def load(lf_path): + print('loading LF dataset ' + lf_path) + ser_dataset = pickle.load(open(lf_path, "rb")) + lf_dataset = [] + for item in ser_dataset: + kp, desc = unpickle_keypoints(item) + lf_dataset.append((kp, desc)) + return lf_dataset + + +def save(lf_data, lf_path): + data = [] + for lf in lf_data: + data.append(pickle_keypoints(lf[0], lf[1])) + pickle.dump(data, open(lf_path, 'wb')) + + + + diff --git a/ORBBulkExtractionFromFileList.py b/ORBBulkExtractionFromFileList.py new file mode 100755 index 0000000..64a6441 --- /dev/null +++ b/ORBBulkExtractionFromFileList.py @@ -0,0 +1,33 @@ +from pathlib import Path +import tqdm + +import LFUtilities +import ORBExtractor as lf +import argparse +import os + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='ORB bulk extraction') + parser.add_argument('src', type=str, help='text file containing a list of img paths') + parser.add_argument('dest', type=str, help='ORB dest file') + + args = parser.parse_args() + src = args.src + dest = args.dest + + with open(src, 'r') as src_file: + dataset = [] + + print('Extracting lf...') + for line in src_file: + try: + kp, des = lf.extract(line.strip()) + dataset.append((kp, des)) + except: + print("cannot process '%s'" % line) + pass + + LFUtilities.save(dataset, dest) + + print('lf extracted.') diff --git a/ORBExtractor.py b/ORBExtractor.py new file mode 100755 index 0000000..56b7b11 --- /dev/null +++ b/ORBExtractor.py @@ -0,0 +1,17 @@ +import cv2 +from pathlib import Path +import tqdm +import pickle +import os + +import LFUtilities +import ORBParameters as params + +orb = cv2.ORB.create(params.KEYPOINTS) + + +def extract(img_path): + img = LFUtilities.resize(params.IMG_SIZE, cv2.imread(img_path)) + kp, des = orb.detectAndCompute(img, mask=None) + return (kp, des) + diff --git a/ORBParameters.py b/ORBParameters.py new file mode 100755 index 0000000..ab45c4b --- /dev/null +++ b/ORBParameters.py @@ -0,0 +1,5 @@ +THRESHOLD = 35 +MIN_GOOD_MATCHES = 12 +MIN_INLIERS = 8 +KEYPOINTS = 5000 +IMG_SIZE = 500 \ No newline at end of file diff --git a/ORBRescorer.py b/ORBRescorer.py new file mode 100755 index 0000000..23d6ed6 --- /dev/null +++ b/ORBRescorer.py @@ -0,0 +1,67 @@ +import cv2 +import numpy as np + +import LFUtilities +import ORBParameters +import WebAppSettings as settings + + +class ORBRescorer: + + def __init__(self): + self.lf = LFUtilities.load(settings.DATASET_LF) + self.ids = np.loadtxt(settings.DATASET_IDS, dtype=str).tolist() + + #self.orb = cv2.ORB_create() + self.bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) + + def rescore_by_id(self, query_id, resultset): + query_idx = self.ids.index(query_id) + return self.rescore_by_img(self.lf[query_idx], resultset) + + def rescore_by_img(self, query, resultset): + max_inliers = -1 + res = [] + + for data_id, _ in resultset: + data_idx = self.ids.index(data_id) + try: + data_el = self.lf[data_idx] + matches = self.bf.match(query[1], data_el[1]) + good = [m for m in matches if m.distance <= ORBParameters.THRESHOLD] + if len(good) > ORBParameters.MIN_GOOD_MATCHES: + src_pts = np.float32([query[0][m.queryIdx].pt for m in good]).reshape(-1, 1, 2) + dst_pts = np.float32([data_el[0][m.trainIdx].pt for m in good]).reshape(-1, 1, 2) + + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 1.0) + matches_mask = mask.ravel().tolist() + # print(len(good)) + inliers = np.count_nonzero(matches_mask) + # print(inliers) + if (inliers >= ORBParameters.MIN_INLIERS and inliers > max_inliers): + max_inliers = inliers + res.append((data_id, inliers)) + except: + print('rescore error evaluating ' + data_id) + pass + + if res: + res.sort(key=lambda result: result[1], reverse=True) + return res + + def add(self, lf): + self.lf.append(lf) + + def remove(self, idx): + self.descs = np.delete(self.descs, idx, axis=0) + + def save(self, is_backup=False): + lf_save_file = settings.DATASET_LF + ids_file = settings.DATASET_IDS_LF + if lf_save_file != "None": + if is_backup: + lf_save_file += '.bak' + ids_file += '.bak' + + LFUtilities.save(lf_save_file, self.lf) + np.savetxt(ids_file, self.ids, fmt='%s') diff --git a/Searcher.py b/Searcher.py new file mode 100755 index 0000000..d96a009 --- /dev/null +++ b/Searcher.py @@ -0,0 +1,97 @@ +import json + +import cv2 +import numpy as np +import pickle as pickle + +import LFUtilities +import WebAppSettings as settings +#from ORBRescorer import ORBRescorer +from BEBLIDRescorer import BEBLIDRescorer +#from LATCHRescorer import LATCHRescorer +from GEMSearcher import GEMSearcher +import GEMExtractor as fe +import ORBExtractor as orb_lf +import BEBLIDExtractor as beblid_lf +import LATCHExtractor as latch_lf + + +class Searcher: + + GEM_THRESHOLD = 0.3 + + def __init__(self): + # self.dataset = h5py.File(settings.dataset_file, 'r')['rmac'][...] + + # np.save('/media/Data/data/beni_culturali/deploy/dataset', self.dataset) + self.ids = np.loadtxt(settings.DATASET_IDS, dtype=str).tolist() + + self.search_engine = GEMSearcher() + + # self.orb_rescorer = ORBRescorer() + self.beblid_rescorer = BEBLIDRescorer() + #self.latch_rescorer = LATCHRescorer() + + def get_id(self, idx): + return self.search_engine.get_id(idx) + + def add(self, img_file, id): + # self.save(True) + + #desc = fe.extract(img_file) + #orb = lf.extract(img_file) + #self.search_engine.add(desc, id) + #self.rescorer.add(orb) + + #self.save() + print('added ' + id) + + def remove(self, id): + #self.save(True) + #self.search_engine.remove(id) + #self.rescorer.remove(idx) + #self.save() + print('removed ' + id) + + def search_by_id(self, query_id, k=10, rescorer=False, lf_impl='BEBLID'): + kq = k + if rescorer: + kq = settings.k_reorder + res = self.search_engine.search_by_id(query_id, kq) + if rescorer: + if lf_impl == 'BEBLID': + res_lf = self.beblid_rescorer.rescore_by_id(query_id, res) + #res = res_lf if res_lf else res[:k] + res = res_lf + return res + + def search_by_img(self, query_img, k=10, rescorer=False, lf_impl='BEBLID'): + if rescorer: + print(lf_impl) + kq = k + if rescorer: + kq = settings.k_reorder + query_desc = fe.extract(query_img) + res = self.search_engine.search_by_img(query_desc, kq) + print(res[0]) + if rescorer: + if lf_impl == 'BEBLID': + query_lf = beblid_lf.extract(query_img) + res_lf = self.beblid_rescorer.rescore_by_img(query_lf, res) + if res_lf: + label = res_lf[0][0].split('/')[0] + res = [label, res_lf[0][1]] + else: + res = None + else: + if res[0][1] > self.GEM_THRESHOLD: + label = res[0][0].split('/')[0] + res = [label, res[0][1]] + else: + res = None + + return res + + def save(self, is_backup=False): + self.search_engine.save(is_backup) + #self.rescorer.save(is_backup) diff --git a/TestClient.py b/TestClient.py new file mode 100755 index 0000000..acb6424 --- /dev/null +++ b/TestClient.py @@ -0,0 +1,21 @@ +import requests +import base64 + + +BASE_URL = 'http://bilioso.isti.cnr.it:8190/bcir/' + +image_path = '/home/paolo/Dropbox/extension_logs/352998a9ee4f490b9a56f84d05983168.png_90.jpg' + +#searchByImg +files = {'image': ('query', open(image_path, 'rb'))} +post_data = {'securityID': 'A6mMmeWZ8JjWKz5', 'orientation': "1"} + +r = requests.post(BASE_URL + 'searchByImg', files=files, data=post_data) +print(r.json()) + +with open(image_path, "rb") as image_file: + base64_img = base64.b64encode(image_file.read()) + base64_data = {'image': base64_img, 'securityID': 'FA6mMmeWZ8JjWKz5', 'orientation': "8"} + + r = requests.post(BASE_URL + 'searchByImgB64', data=base64_data) + print(r.json()) diff --git a/TestFeatures.py b/TestFeatures.py new file mode 100755 index 0000000..96b28b6 --- /dev/null +++ b/TestFeatures.py @@ -0,0 +1,56 @@ + +import json + +from Searcher import Searcher +import WebAppSettings as settings + + +def search_by_img(img_file, lf_impl, rescorer=False): + if lf_impl is not "GEM": + rescorer = True + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + return results + + +if __name__ == '__main__': + #testset= "/media/Data/data/extension/test_set/listfiles.txt" + testset= "/media/Data/data/extension/merged_train_test/test/listfiles.txt" + + settings.load_setting('conf_train_test.json') + + global searcher + searcher = Searcher() + + # Using readlines() + file1 = open(testset, 'r') + Lines = file1.readlines() + + count = 0 + # Strips the newline character + + #features = ["GEM", "ORB", "LATCH", "BEBLID"] + features = ["GEM", "BEBLID"] + + + counters = {"GEM":0, "ORB":0, "LATCH":0, "BEBLID":0} + count_orb = 0 + count_latch = 0 + count_beblid = 0 + + for line in Lines: + classname_q = line.replace("/media/Data/data/extension/merged_train_test/test/", "").split("/")[0] + print("Query {}: {}".format(count, line.strip())) + for f in features: + results = search_by_img(line.strip(), f) + if results is None or results[0][1] < 0.3: + results = ["unknown", 1.0] + classname = results[0][0].split("/")[0] + if (classname_q == classname): + counters[f] = counters[f] + 1 + print(results[0][0] + '", "conf":' + str(results[0][1])) + + count += 1 + + for f in features: + print(f'{f}: {counters}/{count}') + diff --git a/TestFeaturesVairo.py b/TestFeaturesVairo.py new file mode 100755 index 0000000..c0dc6f0 --- /dev/null +++ b/TestFeaturesVairo.py @@ -0,0 +1,72 @@ + +import json + +from Searcher import Searcher +import WebAppSettings as settings + +def search_by_img(img_file, lf_impl, rescorer=False): + if lf_impl is not "GEM": + rescorer = True + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + return results + + + +if __name__ == '__main__': + testset= "/media/Data/data/extension/test_set/listfiles.txt" + + settings.load_setting('conf_test.json') + + global searcher + searcher = Searcher() + + # Using readlines() + file1 = open(testset, 'r') + Lines = file1.readlines() + + count = 0 + # Strips the newline character + + features = ["GEM", "ORB", "LATCH", "BEBLID"] + counters = {"GEM":0, "ORB":0, "LATCH":0, "BEBLID":0} + # features = ["GEM", "BEBLID"] + # counters = {"GEM":0, "BEBLID":0} + + out_csv = '' + + for line in Lines: + classname_q = line.replace("/media/Data/data/extension/test_set/", "").split("/")[0] + filename_q = line.replace("/media/Data/data/extension/test_set/", "").split("/")[1] + print("Query {}: {}".format(count, line.strip())) + + out_line = '' + out_line = out_line + f'{classname_q},{filename_q};' + + for f in features: + results = search_by_img(line.strip(), f) + if results is None: + results = ["unknown", 1.0] + classname = results[0][0].split("/")[0] + filename = results[0][0].split("/")[1] + if (classname_q == classname): + counters[f] = counters[f] + 1 + print(results[0][0] + '", "conf":' + str(results[0][1])) + + out_line = out_line + f'{classname},{filename},{results[0][1]};' + + print(out_line) + out_csv = out_line + '\n' + count += 1 + + print(f'{f}: {counters}/{count}') + print(f'GEM accuracy: {counters["GEM"]}/{count}') + print(f'BEBLID accuracy: {counters["BEBLID"]}/{count}') + + #open text file + out_file = open("out_csv.txt", "w") + + #write string to file + out_file.write(out_csv) + + #close file + out_file.close() \ No newline at end of file diff --git a/ThumbnailCreator.py b/ThumbnailCreator.py new file mode 100755 index 0000000..89c4a6e --- /dev/null +++ b/ThumbnailCreator.py @@ -0,0 +1,47 @@ +import glob, os +from PIL import Image +import argparse +from pathlib import Path +import tqdm + + +w, h = 200,120 + +PATTERN = 'keyframes' +REPLACE = 'thumbs' + + +def resize_img(src, dest): + paths = Path(src).rglob('*.*') + paths_list = list(paths) + + for path in tqdm.tqdm(paths_list): + outfile = str(path).replace(PATTERN, REPLACE) + folders = os.path.dirname(outfile) + + #print(outfile) + + if not os.path.isdir(folders): + #print(folders) + os.makedirs(folders) + + try: + im = Image.open(path) + if im.mode in ("RGBA", "P"): + im = im.convert("RGB") + im.thumbnail((w, h), Image.ANTIALIAS) + im.save(outfile, "JPEG") + except IOError: + print("cannot create thumbnail for '%s'" % path) + pass + + +if __name__ == '__main__': + # parser = argparse.ArgumentParser(description='Image resizing') + # parser.add_argument('src', type=str, help='images source folder path') + # parser.add_argument('dest', type=str, help='images dest folder path') + + #args = parser.parse_args() + #resize_img(args.src, args.dest) + resize_img('/media/Data/data/rai/img/keyframes', '/media/Data/data/rai/img/keyframes') + #resize_img('/media/Data/data/test/gem/img/originals/ImmaginiComparazioni', '/media/Data/data/test/gem/img/ImmaginiComparazioni_resized') diff --git a/WebApp.py b/WebApp.py new file mode 100755 index 0000000..cf5fd72 --- /dev/null +++ b/WebApp.py @@ -0,0 +1,276 @@ +from re import split + +from flask import Flask, request, redirect, url_for, flash, render_template, send_from_directory, abort, Response, session +from random import randint +import cv2 +import io +import numpy as np +import json + +import urllib + +import LFUtilities +from Searcher import Searcher +from GEMSearcher import GEMSearcher +import WebAppSettings as settings +import uuid +import requests +import os, os.path +from PIL import Image +import tornado.wsgi +import tornado.httpserver +import argparse +import base64 +from Heic2Png import conv +from datetime import datetime + + +app = Flask(__name__) +app.secret_key = "27eduCBA09" + + + +security_id = 'FA6mMmeWZ8JjWKz5' +rescorer = False +lf_impl = 'BEBLID' + +HEIC_MAGIC_NUMBER = "AAAAGGZ0eXA=" + + +@app.route('/bcir/') +def api_root(): + print('index_with_randoms.html') + random_ids = [] + for i in range(0, 15): + random_ids.append(searcher.get_id(randint(0, 600))) + return render_template('index_with_randoms.html', random_ids=random_ids) + + +def url_to_file(url): + dest_file = uuid.uuid4().hex + ".png" + session["query"] = settings.log_folder + '/' + dest_file + + dest_path = settings.logs + "/" + dest_file + req = urllib.request.Request( + url, + data=None, + headers={ + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' + } + ) + resp = urllib.request.urlopen(req) + image = np.asarray(bytearray(resp.read()), dtype="uint8") + decoded = cv2.imdecode(image, cv2.IMREAD_COLOR) + resized = LFUtilities.resize(500, decoded) + cv2.imwrite(dest_path, resized) + #im = Image.fromarray(image) + #im.save(dest_path) + return dest_path + + +def post_to_file(image): + dest_file = uuid.uuid4().hex + ".png" + session["query"] = settings.log_folder + '/' + dest_file + dest_path = settings.logs + "/" + dest_file + + in_memory_file = io.BytesIO() + image.save(in_memory_file) + data = np.fromstring(in_memory_file.getvalue(), dtype=np.uint8) + decoded = cv2.imdecode(data, cv2.IMREAD_COLOR) + resized = LFUtilities.resize(500, decoded) + cv2.imwrite(dest_path, resized) + return dest_path + +def set_rescorer(rescore_param): + global rescorer + if rescore_param is not None: + if rescore_param == 'true': + rescorer = True + elif rescore_param == 'false': + rescorer = False + +def base64_to_file(image_base64): + ext = ".jpg" + if (image_base64.startswith(HEIC_MAGIC_NUMBER)): + ext = ".heic" + dest_file = uuid.uuid4().hex + ext + dest_path = settings.logs + "/" + dest_file + with open(dest_path, "wb") as image_file: + byte_content = base64.b64decode(image_base64) + image_file.write(byte_content) + if (image_base64.startswith(HEIC_MAGIC_NUMBER)): + dest_path = conv(dest_path) + return dest_path + + +def get_res(results, query_url=None, img_base64=None): + if query_url is not None: + return render_template('search.html', results=results, query_url=query_url) + elif results is None: + results = '{"classname":"Unknown"}' + else: + results = '{"classname":"' + results[0] + '", "conf":' + str(results[1]) + '}' + print(results) + json_res = json.dumps(results) + print(json_res) + if img_base64 != None: + html_txt = str(datetime.now()) + html_txt += '
' + html_txt += results + html_txt += '
' + html_txt += '' + html_txt += '


' + html_txt += '\n' + with open("/home/paolo/Dropbox/extension_logs/report.html", "a+") as myfile: + myfile.write(html_txt) + return json_res + +def get_resDict(results, query_url=None): + if query_url is not None: + return render_template('search.html', results=results, query_url=query_url) + elif results is None: + results = {"classname":"Unknown"} + else: + results = {"classname":"' + results[0][0] + '", "conf":' + str(results[0][1]) + '} + print(results) + json_res = json.dumps(results) + print(json_res) + + return json_res + + +@app.route('/bcir/searchById') +def search_by_id(): + id = request.args.get('id') + set_rescorer(request.args.get("rescorer")) + results = searcher.search_by_id(id, settings.k, rescorer, lf_impl) + query_url = None + if request.args.get("tohtml") is not None: + query_url = id + ".jpg" + return get_res(results, query_url) + + +@app.route('/bcir/searchByImg', methods=['POST']) +def search_by_img(): + if 'image' not in request.files: + return Response(json.dumps("Error, unable to get the image"), status=401, mimetype='application/json') + + sec_id = request.form.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + + file = request.files['image'] + img_file = post_to_file(file) + set_rescorer(request.form.get("rescorer")) + + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(results, query_url) + +@app.route('/bcir/searchByImgB64', methods=['POST']) +def search_by_img_base64(): + print("query by base64 received") + #print(request) + #print(request.form) + sec_id = request.form.get("securityID") + + #to fix a problem with photo orientation + try: + orientation = request.form.get("orientation") + orientation = int(orientation) + except: + orientation = 1 + + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + image = request.form.get('image') + if image: + img_file = base64_to_file(image) + else: + flash('No img sent') + return redirect(request.url) + + set_rescorer(request.form.get("rescorer")) + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(results, query_url, img_base64=image) + + +@app.route('/bcir/searchByURL') +def search_by_url(): + sec_id = request.args.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + url = request.args.get('url') + img_file = url_to_file(url) + set_rescorer(request.args.get("rescorer")) + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + query_url = None + if request.args.get("tohtml") is not None: + query_url = url + return get_res(results, query_url) + +@app.route('/bcir/setRescorer') +def set_bot_rescorer(): + set_rescorer(request.args.get("rescorer")) + return "Rescorer set to " + str(rescorer) + + +@app.route('/bcir/') +def download_file(filename): + print(filename) + values = filename.split('/') + folder = values[0] + name = values[1] + print(folder) + print(name) + + return send_from_directory(settings.working_folder + '/' + folder, name, as_attachment=False) + +""" +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = BeniCulturaliSearcher() + + #app.run(host='0.0.0.0', port=8090, ssl_context='adhoc') + app.run(host='0.0.0.0', port=settings.port) + + # app.run(host='0.0.0.0', port=settings.port) +""" + +def start_tornado(app, port=8190): + http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app)) + http_server.listen(port) + app.logger.info("Tornado server starting on port {}".format(port)) + tornado.ioloop.IOLoop.instance().start() + + +def start_from_terminal(app): + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = Searcher() + + #if args.debug: + # app.run(debug=True, host='0.0.0.0', port=settings.port) +# else: + #start_tornado(app, settings.port) + + app.run(debug=True, host='0.0.0.0', port=settings.port) + + +if __name__ == '__main__': + start_from_terminal(app) + diff --git a/WebAppFaultTolerant.py b/WebAppFaultTolerant.py new file mode 100644 index 0000000..7f994bb --- /dev/null +++ b/WebAppFaultTolerant.py @@ -0,0 +1,283 @@ +from re import split + +from flask import Flask, request, redirect, url_for, flash, render_template, send_from_directory, abort, Response, session +from random import randint +import cv2 +import io +import numpy as np +import json + +import urllib + +import LFUtilities +from Searcher import Searcher +from GEMSearcher import GEMSearcher +import WebAppSettings as settings +import uuid +import requests +import os, os.path +from PIL import Image +import tornado.wsgi +import tornado.httpserver +import argparse +import base64 +from Heic2Png import conv +from datetime import datetime + + +app = Flask(__name__) +app.secret_key = "27eduCBA09" + + + +security_id = 'FA6mMmeWZ8JjWKz5' +rescorer = False +lf_impl = 'BEBLID' + +HEIC_MAGIC_NUMBER = "AAAAGGZ0eXA=" + + +@app.route('/bcir/') +def api_root(): + print('index_with_randoms.html') + random_ids = [] + for i in range(0, 15): + random_ids.append(searcher.get_id(randint(0, 600))) + return render_template('index_with_randoms.html', random_ids=random_ids) + + +def url_to_file(url): + dest_file = uuid.uuid4().hex + ".png" + session["query"] = settings.log_folder + '/' + dest_file + + dest_path = settings.logs + "/" + dest_file + req = urllib.request.Request( + url, + data=None, + headers={ + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' + } + ) + resp = urllib.request.urlopen(req) + image = np.asarray(bytearray(resp.read()), dtype="uint8") + decoded = cv2.imdecode(image, cv2.IMREAD_COLOR) + resized = LFUtilities.resize(500, decoded) + cv2.imwrite(dest_path, resized) + #im = Image.fromarray(image) + #im.save(dest_path) + return dest_path + + +def post_to_file(image): + dest_file = uuid.uuid4().hex + ".png" + session["query"] = settings.log_folder + '/' + dest_file + dest_path = settings.logs + "/" + dest_file + + in_memory_file = io.BytesIO() + image.save(in_memory_file) + data = np.fromstring(in_memory_file.getvalue(), dtype=np.uint8) + decoded = cv2.imdecode(data, cv2.IMREAD_COLOR) + resized = LFUtilities.resize(500, decoded) + cv2.imwrite(dest_path, resized) + return dest_path + +def set_rescorer(rescore_param): + global rescorer + if rescore_param is not None: + if rescore_param == 'true': + rescorer = True + elif rescore_param == 'false': + rescorer = False + +def base64_to_file(image_base64): + ext = ".jpg" + if (image_base64.startswith(HEIC_MAGIC_NUMBER)): + ext = ".heic" + dest_file = uuid.uuid4().hex + ext + dest_path = settings.logs + "/" + dest_file + with open(dest_path, "wb") as image_file: + byte_content = base64.b64decode(image_base64) + image_file.write(byte_content) + if (image_base64.startswith(HEIC_MAGIC_NUMBER)): + dest_path = conv(dest_path) + return dest_path + + +def get_res(results, query_url=None, img_base64=None): + if query_url is not None: + return render_template('search.html', results=results, query_url=query_url) + elif results is None: + results = '{"classname":"Unknown"}' + else: + results = '{"classname":"' + results[0] + '", "conf":' + str(results[1]) + '}' + print(results) + json_res = json.dumps(results) + print(json_res) + if img_base64 != None: + html_txt = str(datetime.now()) + html_txt += '
' + html_txt += results + html_txt += '
' + html_txt += '' + html_txt += '


' + html_txt += '\n' + with open("/home/paolo/Dropbox/extension_logs/report.html", "a+") as myfile: + myfile.write(html_txt) + return json_res + +def get_resDict(results, query_url=None): + if query_url is not None: + return render_template('search.html', results=results, query_url=query_url) + elif results is None: + results = {"classname":"Unknown"} + else: + results = {"classname":"' + results[0][0] + '", "conf":' + str(results[0][1]) + '} + print(results) + json_res = json.dumps(results) + print(json_res) + + return json_res + +def rotate_img(img_path, degree): + im1 = Image.open(img_path) + im2 = im1.rotate(degree) + dest = img_path + str(degree) + ".jpg" + im2.save(dest) + return dest + + +@app.route('/bcir/searchById') +def search_by_id(): + id = request.args.get('id') + set_rescorer(request.args.get("rescorer")) + results = searcher.search_by_id(id, settings.k, rescorer, lf_impl) + query_url = None + if request.args.get("tohtml") is not None: + query_url = id + ".jpg" + return get_res(results, query_url) + + +@app.route('/bcir/searchByImg', methods=['POST']) +def search_by_img(): + if 'image' not in request.files: + return Response(json.dumps("Error, unable to get the image"), status=401, mimetype='application/json') + + sec_id = request.form.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + + file = request.files['image'] + img_file = post_to_file(file) + set_rescorer(request.form.get("rescorer")) + + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(results, query_url) + +@app.route('/bcir/searchByImgB64', methods=['POST']) +def search_by_img_base64(): + print("query by base64 received") + #print(request) + #print(request.form) + sec_id = request.form.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + image = request.form.get('image') + if image: + img_file = base64_to_file(image) + else: + flash('No img sent') + return redirect(request.url) + + set_rescorer(request.form.get("rescorer")) + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + if results is None: + print('No results. trying ' + str(90) + ' degrees') + degree_90 = rotate_img(img_file, 90) + results = searcher.search_by_img(degree_90, settings.k, rescorer, lf_impl) + if results is None: + print('No results. trying ' + str(270) + ' degrees') + degree_270 = rotate_img(img_file, 270) + results = searcher.search_by_img(degree_270, settings.k, rescorer, lf_impl) + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(results, query_url, img_base64=image) + + +@app.route('/bcir/searchByURL') +def search_by_url(): + sec_id = request.args.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + url = request.args.get('url') + img_file = url_to_file(url) + set_rescorer(request.args.get("rescorer")) + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + query_url = None + if request.args.get("tohtml") is not None: + query_url = url + return get_res(results, query_url) + +@app.route('/bcir/setRescorer') +def set_bot_rescorer(): + set_rescorer(request.args.get("rescorer")) + return "Rescorer set to " + str(rescorer) + + +@app.route('/bcir/') +def download_file(filename): + print(filename) + values = filename.split('/') + folder = values[0] + name = values[1] + print(folder) + print(name) + + return send_from_directory(settings.working_folder + '/' + folder, name, as_attachment=False) + +""" +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = BeniCulturaliSearcher() + + #app.run(host='0.0.0.0', port=8090, ssl_context='adhoc') + app.run(host='0.0.0.0', port=settings.port) + + # app.run(host='0.0.0.0', port=settings.port) +""" + +def start_tornado(app, port=8190): + http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app)) + http_server.listen(port) + app.logger.info("Tornado server starting on port {}".format(port)) + tornado.ioloop.IOLoop.instance().start() + + +def start_from_terminal(app): + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = Searcher() + + #if args.debug: + # app.run(debug=True, host='0.0.0.0', port=settings.port) +# else: + #start_tornado(app, settings.port) + + app.run(debug=False, host='0.0.0.0', port=settings.port) + + +if __name__ == '__main__': + start_from_terminal(app) + diff --git a/WebAppFaultTolerant2.py b/WebAppFaultTolerant2.py new file mode 100644 index 0000000..0885d8d --- /dev/null +++ b/WebAppFaultTolerant2.py @@ -0,0 +1,378 @@ +from re import split + +from flask import Flask, request, redirect, url_for, flash, render_template, send_from_directory, abort, Response, session +from random import randint +import cv2 +import io +import numpy as np +import json + +import urllib + +import LFUtilities +from Searcher import Searcher +from GEMSearcher import GEMSearcher +import WebAppSettings as settings +import uuid +import requests +import os, os.path +from PIL import Image +import tornado.wsgi +import tornado.httpserver +import argparse +import base64 +from Heic2Png import conv +from datetime import datetime + + +app = Flask(__name__) +app.secret_key = "27eduCBA09" + + + +security_id = 'FA6mMmeWZ8JjWKz5' +rescorer = False +lf_impl = 'BEBLID' + +HEIC_MAGIC_NUMBER = "AAAAGGZ0eXA=" + + +@app.route('/bcir/') +def api_root(): + print('index_with_randoms.html') + random_ids = [] + for i in range(0, 15): + random_ids.append(searcher.get_id(randint(0, 600))) + return render_template('index_with_randoms.html', random_ids=random_ids) + + +def url_to_file(url): + dest_file = uuid.uuid4().hex + ".png" + session["query"] = settings.log_folder + '/' + dest_file + + dest_path = settings.logs + "/" + dest_file + req = urllib.request.Request( + url, + data=None, + headers={ + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' + } + ) + resp = urllib.request.urlopen(req) + image = np.asarray(bytearray(resp.read()), dtype="uint8") + decoded = cv2.imdecode(image, cv2.IMREAD_COLOR) + resized = LFUtilities.resize(500, decoded) + cv2.imwrite(dest_path, resized) + #im = Image.fromarray(image) + #im.save(dest_path) + return dest_path + + +def post_to_file(image): + dest_file = uuid.uuid4().hex + ".png" + session["query"] = settings.log_folder + '/' + dest_file + dest_path = settings.logs + "/" + dest_file + + in_memory_file = io.BytesIO() + image.save(in_memory_file) + data = np.fromstring(in_memory_file.getvalue(), dtype=np.uint8) + decoded = cv2.imdecode(data, cv2.IMREAD_COLOR) + resized = LFUtilities.resize(500, decoded) + cv2.imwrite(dest_path, resized) + return dest_path + +def set_rescorer(rescore_param): + global rescorer + if rescore_param is not None: + if rescore_param == 'true': + rescorer = True + elif rescore_param == 'false': + rescorer = False + +def base64_to_file(image_base64): + ext = ".jpg" + if (image_base64.startswith(HEIC_MAGIC_NUMBER)): + ext = ".heic" + dest_file = uuid.uuid4().hex + ext + dest_path = settings.logs + "/" + dest_file + with open(dest_path, "wb") as image_file: + byte_content = base64.b64decode(image_base64) + image_file.write(byte_content) + if (image_base64.startswith(HEIC_MAGIC_NUMBER)): + dest_path = conv(dest_path) + return dest_path + + +def get_res(results, query_url=None, img_base64=None): + if query_url is not None: + return render_template('search.html', results=results, query_url=query_url) + elif results is None: + results = '{"classname":"Unknown"}' + else: + results = '{"classname":"' + results[0] + '", "conf":' + str(results[1]) + '}' + print(results) + json_res = json.dumps(results) + print(json_res) + if img_base64 != None: + html_txt = str(datetime.now()) + html_txt += '
' + html_txt += results + html_txt += '
' + html_txt += '' + html_txt += '


' + html_txt += '\n' + with open("/home/paolo/Dropbox/extension_logs/report.html", "a+") as myfile: + myfile.write(html_txt) + return json_res + + +def get_resDict(results, query_url=None): + if query_url is not None: + return render_template('search.html', results=results, query_url=query_url) + elif results is None: + results = {"classname":"Unknown"} + else: + results = {"classname":"' + results[0][0] + '", "conf":' + str(results[0][1]) + '} + print(results) + json_res = json.dumps(results) + print(json_res) + + return json_res + + +def rotate_img(img_path, degree): + im1 = Image.open(img_path) + im2 = im1.rotate(degree, expand=True) + dest = img_path + "_" + str(degree) + ".jpg" + im2.save(dest) + return dest + + +@app.route('/bcir/searchById') +def search_by_id(): + id = request.args.get('id') + set_rescorer(request.args.get("rescorer")) + results = searcher.search_by_id(id, settings.k, rescorer, lf_impl) + query_url = None + if request.args.get("tohtml") is not None: + query_url = id + ".jpg" + return get_res(results, query_url) + + +@app.route('/bcir/searchByImg', methods=['POST']) +def search_by_img(): + if 'image' not in request.files: + return Response(json.dumps("Error, unable to get the image"), status=401, mimetype='application/json') + + sec_id = request.form.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + + file = request.files['image'] + img_file = post_to_file(file) + set_rescorer(request.form.get("rescorer")) + + results_0 = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + degree_90 = rotate_img(img_file, 90) + results_90 = searcher.search_by_img(degree_90, settings.k, rescorer, lf_impl) + degree_270 = rotate_img(img_file, 270) + results_270 = searcher.search_by_img(degree_270, settings.k, rescorer, lf_impl) + + max_res = results_0 + if results_90 is not None: + if max_res is None: + max_res = results_90 + elif results_90[1] > max_res[1]: + max_res = results_90 + if results_270 is not None: + if max_res is None: + max_res = results_270 + elif results_270[1] > max_res[1]: + max_res = results_270 + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(max_res, query_url) + +@app.route('/bcir/searchByImgB64', methods=['POST']) +def search_by_img_base64(): + print("query by base64 received") + #print(request) + #print(request.form) + sec_id = request.form.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + + #to fix a problem with photo orientation + try: + orientation = request.form.get("orientation") + orientation = int(orientation) + except: + orientation = 1 + + image = request.form.get('image') + if image: + img_file = base64_to_file(image) + else: + flash('No img sent') + return redirect(request.url) + + oriented_img = img_file + if orientation == 3: + oriented_img = rotate_img(img_file, 180) + elif orientation == 6: + oriented_img = rotate_img(img_file, 270) + elif orientation == 8: + oriented_img = rotate_img(img_file, 90) + + results = searcher.search_by_img(oriented_img, settings.k, rescorer, lf_impl) + + set_rescorer(request.form.get("rescorer")) + + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(results, query_url, img_base64=image) + + ''' + results_0 = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + degree_90 = rotate_img(img_file, 90) + results_90 = searcher.search_by_img(degree_90, settings.k, rescorer, lf_impl) + degree_270 = rotate_img(img_file, 270) + results_270 = searcher.search_by_img(degree_270, settings.k, rescorer, lf_impl) + + max_res = results_0 + if results_90 is not None: + if max_res is None: + max_res = results_90 + elif results_90[1] > max_res[1]: + max_res = results_90 + if results_270 is not None: + if max_res is None: + max_res = results_270 + elif results_270[1] > max_res[1]: + max_res = results_270 + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(max_res, query_url, img_base64=image) +''' + +@app.route('/bcir/searchByURL') +def search_by_url(): + sec_id = request.args.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + url = request.args.get('url') + img_file = url_to_file(url) + set_rescorer(request.args.get("rescorer")) + + + #to fix a problem with photo orientation + try: + orientation = request.args.get("orientation") + orientation = int(orientation) + except: + orientation = 1 + + oriented_img = img_file + if orientation == 3: + oriented_img = rotate_img(img_file, 180) + elif orientation == 6: + oriented_img = rotate_img(img_file, 90) + elif orientation == 8: + oriented_img = rotate_img(img_file, 270) + + results = searcher.search_by_img(oriented_img, settings.k, rescorer, lf_impl) + + set_rescorer(request.form.get("rescorer")) + + query_url = None + + if request.args.get("tohtml") is not None: + query_url = url + return get_res(results, query_url) + + + results_0 = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + degree_90 = rotate_img(img_file, 90) + results_90 = searcher.search_by_img(degree_90, settings.k, rescorer, lf_impl) + degree_270 = rotate_img(img_file, 270) + results_270 = searcher.search_by_img(degree_270, settings.k, rescorer, lf_impl) + + max_res = results_0 + if results_90 is not None: + if max_res is None: + max_res = results_90 + elif results_90[1] > max_res[1]: + max_res = results_90 + if results_270 is not None: + if max_res is None: + max_res = results_270 + elif results_270[1] > max_res[1]: + max_res = results_270 + query_url = None + if request.args.get("tohtml") is not None: + query_url = url + return get_res(max_res, query_url) + +@app.route('/bcir/setRescorer') +def set_bot_rescorer(): + set_rescorer(request.args.get("rescorer")) + return "Rescorer set to " + str(rescorer) + + +@app.route('/bcir/') +def download_file(filename): + print(filename) + values = filename.split('/') + folder = values[0] + name = values[1] + print(folder) + print(name) + + return send_from_directory(settings.working_folder + '/' + folder, name, as_attachment=False) + +""" +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = BeniCulturaliSearcher() + + #app.run(host='0.0.0.0', port=8090, ssl_context='adhoc') + app.run(host='0.0.0.0', port=settings.port) + + # app.run(host='0.0.0.0', port=settings.port) +""" + +def start_tornado(app, port=8190): + http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app)) + http_server.listen(port) + app.logger.info("Tornado server starting on port {}".format(port)) + tornado.ioloop.IOLoop.instance().start() + + +def start_from_terminal(app): + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = Searcher() + + #if args.debug: + # app.run(debug=True, host='0.0.0.0', port=settings.port) +# else: + #start_tornado(app, settings.port) + + app.run(debug=False, host='0.0.0.0', port=settings.port) + + +if __name__ == '__main__': + start_from_terminal(app) + diff --git a/WebAppSettings.py b/WebAppSettings.py new file mode 100755 index 0000000..ee3add3 --- /dev/null +++ b/WebAppSettings.py @@ -0,0 +1,41 @@ +import json +import os + +def load_setting(conf_file): + global port, feature_extractor, k, k_reorder, img_folder, log_folder, logs, working_folder, data_folder, DATASET_GEM, DATASET1, DATASET2, DATASET_LF, DATASET_IDS, DATASET_BEBLID, DATASET_LATCH + + with open(conf_file) as settings_file: + + settings = json.load(settings_file) + + port = settings['port'] + feature_extractor = settings['fe_service'] + + k = settings['k'] + k_reorder = settings['k_reorder'] + working_folder = settings['working_folder'] + + data_folder = os.path.join(working_folder, settings['data_folder']) + + if not os.path.isdir(data_folder): + os.mkdir(data_folder) + + DATASET_GEM = os.path.join(data_folder, 'gem.npy') + #DATASET1 = os.path.join(data_folder, 'dataset_resized.npy') + #DATASET2 = os.path.join(data_folder, 'dataset_bw.npy') + #DATASET_LF = os.path.join(data_folder, 'dataset_lf.dat') + #DATASET_LF = os.path.join(data_folder, 'orb_5k.dat') + DATASET_IDS = os.path.join(data_folder, 'dataset.ids') + #DATASET_BEBLID = os.path.join(data_folder, 'dataset_beblid.dat') + DATASET_BEBLID = os.path.join(data_folder, 'beblid.dat') + #DATASET_LATCH = os.path.join(data_folder, 'dataset_latch.dat') + #DATASET_LATCH = os.path.join(data_folder, 'latch_5k.dat') + + img_folder = settings['img_folder'] + log_folder = settings['log_folder'] + #temporary for mobile app debugging + log_folder = settings['log_folder'] + log_folder = '/home/paolo/Dropbox/extension_logs' + logs = os.path.join(working_folder, log_folder) + if not os.path.isdir(logs): + os.mkdir(logs) diff --git a/WebAppTest.py b/WebAppTest.py new file mode 100755 index 0000000..e9e299e --- /dev/null +++ b/WebAppTest.py @@ -0,0 +1,290 @@ +from re import split + +from flask import Flask, request, redirect, url_for, flash, render_template, send_from_directory, abort, Response +from random import randint +import cv2 +import io +import numpy as np +import json + +import urllib + +from Searcher import Searcher +from GEMSearcher import GEMSearcher +import WebAppSettings as settings +import uuid +import requests +import os, os.path +from PIL import Image +import tornado.wsgi +import tornado.httpserver +import argparse +import base64 + +app = Flask(__name__) + +security_id = 'FA6mMmeWZ8JjWKz5' + + +@app.route('/bcirtest/') +def api_root(): + print('index_with_randoms.html') + random_ids = [] + for i in range(0, 15): + random_ids.append(searcher.get_id(randint(0, 600))) + return render_template('index_with_randoms.html', random_ids=random_ids) + + +def url_to_file(url): + dest_file = uuid.uuid4().hex + ".png" + dest_path = settings.logs + "/" + dest_file + req = urllib.request.Request( + url, + data=None, + headers={ + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36' + } + ) + resp = urllib.request.urlopen(req) + image = np.asarray(bytearray(resp.read()), dtype="uint8") + decoded = cv2.imdecode(image, cv2.IMREAD_COLOR) + cv2.imwrite(dest_path, decoded) + #im = Image.fromarray(image) + #im.save(dest_path) + return dest_path + + +def post_to_file(image): + dest_file = uuid.uuid4().hex + ".png" + dest_path = settings.logs + "/" + dest_file + image.save(dest_path) + return dest_path + +def base64_to_file(image_base64): + dest_file = uuid.uuid4().hex + ".png" + dest_path = settings.logs + "/" + dest_file + with open(dest_path, "wb") as image_file: + byte_content = base64.b64decode(image_base64) + image_file.write(byte_content) + return dest_path + + +def get_res(results, query_url=None): + if query_url is not None: + return render_template('search.html', results=results, query_url=query_url) + elif results is None: + results = '{"classname":"Unknown"}' + else: + results = '{"classname":"' + results[0][0] + '", "conf":' + str(results[0][1]) + '}' + print(results) + json_res = json.dumps(results) + print(json_res) + + return json_res + + +@app.route('/bcirtest/searchById') +def search_by_id(): + id = request.args.get('id') + rescorer = False + lf_impl = 'ORB' + if request.args.get("rescorer") == 'true': + rescorer = True + + if request.args.get("lf_impl") == 'beblid': + lf_impl = 'BEBLID' + elif request.args.get("lf_impl") == 'latch': + lf_impl = 'LATCH' + #results = searcher.search_by_id(id, settings.k, rescorer, lf_impl) + results = searcher.search_by_id(id, settings.k) + query_url = None + if request.args.get("tohtml") is not None: + query_url = id + ".jpg" + return get_res(results, query_url) + + +@app.route('/bcirtest/searchByImg', methods=['POST']) +def search_by_img(): + if 'image' not in request.files: + return Response(json.dumps("Error, unable to get the image"), status=401, mimetype='application/json') + + sec_id = request.form.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + + + file = request.files['image'] + img_file = post_to_file(file) + rescorer = False + lf_impl = 'ORB500' + if request.form.get("rescorer") == 'true': + rescorer = True + if request.form.get("lf_impl") == 'beblid': + lf_impl = 'BEBLID' + elif request.form.get("lf_impl") == 'latch': + lf_impl = 'LATCH' + elif request.form.get("lf_impl") == 'orb': + lf_impl = 'ORB' + #dest_file = uuid.uuid4().hex + ".jpg" + #dest_path = settings.logs + "/" + dest_file + #file.save(dest_path) + #files = {'image': (dest_file, open(dest_path, 'rb'))} + #r = requests.post(settings.rmac_service, files=files) + #results = search_engine.search_by_img(np.array(r.json()), settings.k) + #results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(results, query_url) + +@app.route('/bcirtest/searchByImgB64', methods=['POST']) +def search_by_img_base64(): + sec_id = request.form.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + image = request.form.get('image') + if image: + img_file = base64_to_file(image) + else: + flash('No img sent') + return redirect(request.url) + + + rescorer = False + lf_impl = 'ORB500' + if request.form.get("rescorer") == 'true': + rescorer = True + if request.form.get("lf_impl") == 'beblid': + lf_impl = 'BEBLID' + elif request.form.get("lf_impl") == 'latch': + lf_impl = 'LATCH' + elif request.form.get("lf_impl") == 'orb': + lf_impl = 'ORB' + #dest_file = uuid.uuid4().hex + ".jpg" + #dest_path = settings.logs + "/" + dest_file + #file.save(dest_path) + #files = {'image': (dest_file, open(dest_path, 'rb'))} + #r = requests.post(settings.rmac_service, files=files) + #results = search_engine.search_by_img(np.array(r.json()), settings.k) + #results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + results = searcher.search_by_img(img_file, settings.k) + query_url = None + if request.form.get("tohtml") is not None: + query_url = "" + return get_res(results, query_url) + + +@app.route('/bcirtest/searchByURL') +def search_by_url(): + sec_id = request.args.get("securityID") + #if sec_id != security_id: + # return Response(json.dumps("Error 401, not authorized"), status=401, mimetype='application/json') + url = request.args.get('url') + rescorer = False + if request.args.get("rescorer") == 'true': + rescorer = True + img_file = url_to_file(url) + # query = cv2.imdecode(image, cv2.IMREAD_COLOR) + # dest_file = uuid.uuid4().hex + ".jpg" + # dest_path = settings.logs + "/" + dest_file + # cv2.imwrite(dest_path, query) + # files = {'image': open(dest_path, 'rb')} + # r = requests.post(settings.rmac_service, files=files) + # results = search_engine.search_by_img(np.array(r.json()), settings.k) + rescorer = False + lf_impl = 'ORB500' + if request.args.get("rescorer") == 'true': + rescorer = True + if request.args.get("lf_impl") == 'beblid': + lf_impl = 'BEBLID' + elif request.args.get("lf_impl") == 'latch': + lf_impl = 'LATCH' + elif request.args.get("lf_impl") == 'orb': + lf_impl = 'ORB' + #results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + results = searcher.search_by_img(img_file, settings.k, rescorer, lf_impl) + query_url = None + if request.args.get("tohtml") is not None: + query_url = url + return get_res(results, query_url) + +@app.route('/bcirtest/addImg', methods=['POST']) +def add_img(): + if 'image' not in request.files: + flash('No file part') + return redirect(request.url) + try: + file = request.files['image'] + id = request.files['image'].filename + id, _ = os.path.splitext(id) + img_file = post_to_file(file) + searcher.add(img_file, id) + json_res = json.dumps("done") + return json_res + except: + abort(500) + + +@app.route('/bcirtest/rmImg') +def remove_img(): + try: + id = request.args.get('id') + searcher.remove(id) + json_res = json.dumps("done") + return json_res + except: + abort(500) + +@app.route('/bcirtest/') +def download_file(filename): + print(filename) + values = filename.split('/') + print(values) + print(settings.img_folder) + + return send_from_directory(settings.img_folder, filename, as_attachment=False) + +""" +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = BeniCulturaliSearcher() + + #app.run(host='0.0.0.0', port=8090, ssl_context='adhoc') + app.run(host='0.0.0.0', port=settings.port) + + # app.run(host='0.0.0.0', port=settings.port) +""" + +def start_tornado(app, port=8190): + http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app)) + http_server.listen(port) + app.logger.info("Tornado server starting on port {}".format(port)) + tornado.ioloop.IOLoop.instance().start() + + +def start_from_terminal(app): + parser = argparse.ArgumentParser(description='Reading configuration file') + parser.add_argument('conf', type=str, help='Configuration file path') + + args = parser.parse_args() + settings.load_setting(args.conf) + global searcher + searcher = Searcher() + + #if args.debug: + # app.run(debug=True, host='0.0.0.0', port=settings.port) +# else: + #start_tornado(app, settings.port) + + app.run(debug=True, host='0.0.0.0', port=8290) + + +if __name__ == '__main__': + start_from_terminal(app) + diff --git a/__pycache__/BEBLIDExtractor.cpython-37.pyc b/__pycache__/BEBLIDExtractor.cpython-37.pyc new file mode 100755 index 0000000..f43d089 Binary files /dev/null and b/__pycache__/BEBLIDExtractor.cpython-37.pyc differ diff --git a/__pycache__/BEBLIDExtractor.cpython-39.pyc b/__pycache__/BEBLIDExtractor.cpython-39.pyc new file mode 100755 index 0000000..d405057 Binary files /dev/null and b/__pycache__/BEBLIDExtractor.cpython-39.pyc differ diff --git a/__pycache__/BEBLIDParameters.cpython-37.pyc b/__pycache__/BEBLIDParameters.cpython-37.pyc new file mode 100644 index 0000000..87adaa1 Binary files /dev/null and b/__pycache__/BEBLIDParameters.cpython-37.pyc differ diff --git a/__pycache__/BEBLIDParameters.cpython-39.pyc b/__pycache__/BEBLIDParameters.cpython-39.pyc new file mode 100755 index 0000000..0215956 Binary files /dev/null and b/__pycache__/BEBLIDParameters.cpython-39.pyc differ diff --git a/__pycache__/BEBLIDRescorer.cpython-37.pyc b/__pycache__/BEBLIDRescorer.cpython-37.pyc new file mode 100644 index 0000000..f73e962 Binary files /dev/null and b/__pycache__/BEBLIDRescorer.cpython-37.pyc differ diff --git a/__pycache__/BEBLIDRescorer.cpython-39.pyc b/__pycache__/BEBLIDRescorer.cpython-39.pyc new file mode 100755 index 0000000..7c50384 Binary files /dev/null and b/__pycache__/BEBLIDRescorer.cpython-39.pyc differ diff --git a/__pycache__/BEBLIDSearcher.cpython-37.pyc b/__pycache__/BEBLIDSearcher.cpython-37.pyc new file mode 100755 index 0000000..cd52f49 Binary files /dev/null and b/__pycache__/BEBLIDSearcher.cpython-37.pyc differ diff --git a/__pycache__/GEMExtractor.cpython-37.pyc b/__pycache__/GEMExtractor.cpython-37.pyc new file mode 100755 index 0000000..9747a87 Binary files /dev/null and b/__pycache__/GEMExtractor.cpython-37.pyc differ diff --git a/__pycache__/GEMExtractor.cpython-39.pyc b/__pycache__/GEMExtractor.cpython-39.pyc new file mode 100755 index 0000000..8d76fcd Binary files /dev/null and b/__pycache__/GEMExtractor.cpython-39.pyc differ diff --git a/__pycache__/GEMSearcher.cpython-37.pyc b/__pycache__/GEMSearcher.cpython-37.pyc new file mode 100644 index 0000000..6e7cd1a Binary files /dev/null and b/__pycache__/GEMSearcher.cpython-37.pyc differ diff --git a/__pycache__/GEMSearcher.cpython-39.pyc b/__pycache__/GEMSearcher.cpython-39.pyc new file mode 100755 index 0000000..f6df008 Binary files /dev/null and b/__pycache__/GEMSearcher.cpython-39.pyc differ diff --git a/__pycache__/Heic2Png.cpython-37.pyc b/__pycache__/Heic2Png.cpython-37.pyc new file mode 100644 index 0000000..d52a7a2 Binary files /dev/null and b/__pycache__/Heic2Png.cpython-37.pyc differ diff --git a/__pycache__/LATCHExtractor.cpython-37.pyc b/__pycache__/LATCHExtractor.cpython-37.pyc new file mode 100755 index 0000000..5f06c00 Binary files /dev/null and b/__pycache__/LATCHExtractor.cpython-37.pyc differ diff --git a/__pycache__/LATCHExtractor.cpython-39.pyc b/__pycache__/LATCHExtractor.cpython-39.pyc new file mode 100755 index 0000000..ef44395 Binary files /dev/null and b/__pycache__/LATCHExtractor.cpython-39.pyc differ diff --git a/__pycache__/LATCHParameters.cpython-37.pyc b/__pycache__/LATCHParameters.cpython-37.pyc new file mode 100755 index 0000000..3b95abc Binary files /dev/null and b/__pycache__/LATCHParameters.cpython-37.pyc differ diff --git a/__pycache__/LATCHParameters.cpython-39.pyc b/__pycache__/LATCHParameters.cpython-39.pyc new file mode 100755 index 0000000..6d3b073 Binary files /dev/null and b/__pycache__/LATCHParameters.cpython-39.pyc differ diff --git a/__pycache__/LATCHRescorer.cpython-37.pyc b/__pycache__/LATCHRescorer.cpython-37.pyc new file mode 100755 index 0000000..31bb265 Binary files /dev/null and b/__pycache__/LATCHRescorer.cpython-37.pyc differ diff --git a/__pycache__/LATCHRescorer.cpython-39.pyc b/__pycache__/LATCHRescorer.cpython-39.pyc new file mode 100755 index 0000000..d5a6e46 Binary files /dev/null and b/__pycache__/LATCHRescorer.cpython-39.pyc differ diff --git a/__pycache__/LFSearcher.cpython-37.pyc b/__pycache__/LFSearcher.cpython-37.pyc new file mode 100755 index 0000000..2eb332a Binary files /dev/null and b/__pycache__/LFSearcher.cpython-37.pyc differ diff --git a/__pycache__/LFUtilities.cpython-37.pyc b/__pycache__/LFUtilities.cpython-37.pyc new file mode 100755 index 0000000..0252ad1 Binary files /dev/null and b/__pycache__/LFUtilities.cpython-37.pyc differ diff --git a/__pycache__/LFUtilities.cpython-39.pyc b/__pycache__/LFUtilities.cpython-39.pyc new file mode 100755 index 0000000..ac59b4d Binary files /dev/null and b/__pycache__/LFUtilities.cpython-39.pyc differ diff --git a/__pycache__/ORBExtractor.cpython-37.pyc b/__pycache__/ORBExtractor.cpython-37.pyc new file mode 100755 index 0000000..eeeb03e Binary files /dev/null and b/__pycache__/ORBExtractor.cpython-37.pyc differ diff --git a/__pycache__/ORBExtractor.cpython-39.pyc b/__pycache__/ORBExtractor.cpython-39.pyc new file mode 100755 index 0000000..b567d02 Binary files /dev/null and b/__pycache__/ORBExtractor.cpython-39.pyc differ diff --git a/__pycache__/ORBParameters.cpython-37.pyc b/__pycache__/ORBParameters.cpython-37.pyc new file mode 100755 index 0000000..6b5d14b Binary files /dev/null and b/__pycache__/ORBParameters.cpython-37.pyc differ diff --git a/__pycache__/ORBParameters.cpython-39.pyc b/__pycache__/ORBParameters.cpython-39.pyc new file mode 100755 index 0000000..cd582ab Binary files /dev/null and b/__pycache__/ORBParameters.cpython-39.pyc differ diff --git a/__pycache__/ORBRescorer.cpython-37.pyc b/__pycache__/ORBRescorer.cpython-37.pyc new file mode 100755 index 0000000..234b20b Binary files /dev/null and b/__pycache__/ORBRescorer.cpython-37.pyc differ diff --git a/__pycache__/ORBRescorer.cpython-39.pyc b/__pycache__/ORBRescorer.cpython-39.pyc new file mode 100755 index 0000000..13c8094 Binary files /dev/null and b/__pycache__/ORBRescorer.cpython-39.pyc differ diff --git a/__pycache__/Searcher.cpython-37.pyc b/__pycache__/Searcher.cpython-37.pyc new file mode 100644 index 0000000..73ecc28 Binary files /dev/null and b/__pycache__/Searcher.cpython-37.pyc differ diff --git a/__pycache__/Searcher.cpython-38.pyc b/__pycache__/Searcher.cpython-38.pyc new file mode 100644 index 0000000..f31aaac Binary files /dev/null and b/__pycache__/Searcher.cpython-38.pyc differ diff --git a/__pycache__/Searcher.cpython-39.pyc b/__pycache__/Searcher.cpython-39.pyc new file mode 100755 index 0000000..ff8dadc Binary files /dev/null and b/__pycache__/Searcher.cpython-39.pyc differ diff --git a/__pycache__/WebAppSettings.cpython-37.pyc b/__pycache__/WebAppSettings.cpython-37.pyc new file mode 100644 index 0000000..ee4cb74 Binary files /dev/null and b/__pycache__/WebAppSettings.cpython-37.pyc differ diff --git a/__pycache__/WebAppSettings.cpython-39.pyc b/__pycache__/WebAppSettings.cpython-39.pyc new file mode 100755 index 0000000..18d7012 Binary files /dev/null and b/__pycache__/WebAppSettings.cpython-39.pyc differ diff --git a/conf.json b/conf.json new file mode 100755 index 0000000..3aca10a --- /dev/null +++ b/conf.json @@ -0,0 +1,11 @@ +{ + "port": 8190, + "img_host": "http://bilioso.isti.cnr.it:8030/bcimages", + "fe_service": "http://localhost:5000/extract", + "k": 15, + "k_reorder": 15, + "working_folder": "/workspace/data", + "img_folder": "/workspace/data/data/img/dataset", + "log_folder": "logs", + "data_folder": "data" +} diff --git a/conf_local.json b/conf_local.json new file mode 100755 index 0000000..4396746 --- /dev/null +++ b/conf_local.json @@ -0,0 +1,11 @@ +{ + "port": 8190, + "img_host": "http://bilioso.isti.cnr.it:8190/bcimages", + "fe_service": "http://localhost:5000/extract", + "k": 15, + "k_reorder": 15, + "working_folder": "/media/Data/data/extension/img_recognition", + "img_folder": "/media/Data/data/extension/datasetMerged", + "log_folder": "logs", + "data_folder": "data" +} diff --git a/conf_local_orig.json b/conf_local_orig.json new file mode 100644 index 0000000..5ca12a3 --- /dev/null +++ b/conf_local_orig.json @@ -0,0 +1,11 @@ +{ + "port": 8190, + "img_host": "http://bilioso.isti.cnr.it:8190/bcimages", + "fe_service": "http://localhost:5000/extract", + "k": 15, + "k_reorder": 15, + "working_folder": "/media/Data/data/extension/img_recognition", + "img_folder": "/media/Data/data/extension/img_recognition/data/img/dataset", + "log_folder": "logs", + "data_folder": "data" +} diff --git a/conf_release1.json b/conf_release1.json new file mode 100644 index 0000000..effb136 --- /dev/null +++ b/conf_release1.json @@ -0,0 +1,11 @@ +{ + "port": 8190, + "img_host": "http://bilioso.isti.cnr.it:8190/bcimages", + "fe_service": "http://localhost:5000/extract", + "k": 500, + "k_reorder": 500, + "working_folder": "/media/Data/data/extension/datasetEnriched", + "img_folder": "/media/Data/data/extension/datasetEnriched/img", + "log_folder": "logs", + "data_folder": "data" +} diff --git a/conf_test.json b/conf_test.json new file mode 100755 index 0000000..a32a9a5 --- /dev/null +++ b/conf_test.json @@ -0,0 +1,11 @@ +{ + "port": 8190, + "img_host": "http://bilioso.isti.cnr.it:8190/bcimages", + "fe_service": "http://localhost:5000/extract", + "k": 15, + "k_reorder": 15, + "working_folder": "/media/Data/data/extension/datasetMerged", + "img_folder": "/media/Data/data/extension/datasetMerged", + "log_folder": "logs", + "data_folder": "data" +} diff --git a/conf_train_test.json b/conf_train_test.json new file mode 100644 index 0000000..1c94530 --- /dev/null +++ b/conf_train_test.json @@ -0,0 +1,11 @@ +{ + "port": 8190, + "img_host": "http://bilioso.isti.cnr.it:8190/bcimages", + "fe_service": "http://localhost:5000/extract", + "k": 15, + "k_reorder": 15, + "working_folder": "/media/Data/data/extension/merged_train_test", + "img_folder": "/media/Data/data/extension/merged_train_test/train", + "log_folder": "logs", + "data_folder": "data" +} diff --git a/static/img/ACC 130111[1].jpg b/static/img/ACC 130111[1].jpg new file mode 100755 index 0000000..61813cd Binary files /dev/null and b/static/img/ACC 130111[1].jpg differ diff --git a/static/img/Search.png b/static/img/Search.png new file mode 100755 index 0000000..e20ff1e Binary files /dev/null and b/static/img/Search.png differ diff --git a/static/img/aimh_logo.png b/static/img/aimh_logo.png new file mode 100644 index 0000000..2e585a5 Binary files /dev/null and b/static/img/aimh_logo.png differ diff --git a/static/img/deepImgSearch.png b/static/img/deepImgSearch.png new file mode 100755 index 0000000..d6e71b0 Binary files /dev/null and b/static/img/deepImgSearch.png differ diff --git a/static/img/favicon.ico b/static/img/favicon.ico new file mode 100755 index 0000000..e4f1d6e Binary files /dev/null and b/static/img/favicon.ico differ diff --git a/static/img/refresh.png b/static/img/refresh.png new file mode 100755 index 0000000..3ea3486 Binary files /dev/null and b/static/img/refresh.png differ diff --git a/static/js/ui.js b/static/js/ui.js new file mode 100755 index 0000000..91aee8e --- /dev/null +++ b/static/js/ui.js @@ -0,0 +1,105 @@ +function changeImage(imageURL, objectID) { + //alert(imageURL + " - " + objectID); + if (document.getElementById('objId').value==objectID || objectID == "" || imageURL == "null" || objectID == "null") { + document.getElementById('advSearch').style.display = 'none'; + //document.getElementById('comboInfo').style.display = 'none'; + document.getElementById('queryImage').src='queryImage'; + document.getElementById('objId').value=''; + document.getElementById('objId').name="disabled"; + } + else { + document.getElementById('advSearch').style.display = ''; + //document.getElementById('comboInfo').style.display = ''; + document.getElementById('queryImage').src=imageURL; + document.getElementById('objId').value=objectID; + document.getElementById('objId').name="id"; + + //document.getElementById('imageQueryCheckbox').checked='checked'; + document.getElementById('objId').name="id"; + document.getElementById('queryImage').style.display = ''; + + if (document.getElementById('imageToUpload') != null) { + document.getElementById('imageToUpload').value=""; + } + } +// if (imageURL != "null" && imageURL != "" && imageURL == objectID) { +// document.getElementById('objId').name="url"; +// } +} + +function imageQuery() { + //alert(imageURL + " - " + objectID); + if (!document.getElementById('imageQueryCheckbox').checked) { + document.getElementById('objId').name="disabled"; + document.getElementById('queryImage').style.display = 'none'; + } + else { + document.getElementById('objId').name="id"; + document.getElementById('queryImage').style.display = ''; + } +} + +function changeQueryBySampleMod(mode) { + if (mode == "url") { + document.getElementById("uploadText").style.display = 'none'; + document.getElementById("uploadLink").style.display = ''; + document.getElementById("urlText").style.display = ''; + document.getElementById("urlLink").style.display = 'none'; + document.getElementById("imageToUpload").style.display = 'none'; + document.getElementById("urlToUpload").style.display = ''; + document.getElementById("imageToUpload").value = ''; + +// document.getElementById("imageToUpload").type="text"; +// document.getElementById("imageToUpload").name="url"; +// document.getElementById("imageToUpload").size="49"; + document.getElementById("searchbar").action="./searchByURL" + document.getElementById("searchbar").enctype=""; + document.getElementById("searchbar").method="GET"; + + + } else { + document.getElementById("uploadText").style.display = ''; + document.getElementById("uploadLink").style.display = 'none'; + document.getElementById("urlText").style.display = 'none'; + document.getElementById("urlLink").style.display = ''; + + document.getElementById("urlToUpload").style.display = 'none'; + document.getElementById("imageToUpload").style.display = ''; + document.getElementById("urlToUpload").value = ''; + +// document.getElementById("imageToUpload").type="file"; +// document.getElementById("imageToUpload").name="imgFile"; +// document.getElementById("imageToUpload").size="38"; + + document.getElementById("searchbar").action="./searchByImg" + document.getElementById("searchbar").enctype="multipart/form-data"; + document.getElementById("searchbar").method="POST"; + } +} + +function trim(str) { + return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); +} + +function getWindowHeight() { + var windowHeight = 0; + if (typeof(window.innerHeight) == 'number') { + windowHeight = window.innerHeight; + } + else { + if (document.documentElement && document.documentElement.clientHeight) { + windowHeight = document.documentElement.clientHeight; + } + else { + if (document.body && document.body.clientHeight) { + windowHeight = document.body.clientHeight; + } + } + } + return windowHeight; +} + +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1) + min); +} + diff --git a/static/styles/polaroidStyle.css b/static/styles/polaroidStyle.css new file mode 100755 index 0000000..fdd76cc --- /dev/null +++ b/static/styles/polaroidStyle.css @@ -0,0 +1,207 @@ + + +a.polaroid { + display: block; + text-decoration: none; + color: #333; + padding: 10px 10px 20px 10px; + width: 150px; + border: 1px solid #BFBFBF; + background-color: white; + z-index: 2; + font-size: 0.7em; + -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3); + -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3); + box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3); + -webkit-transition: all 0.5s ease-in; +} +a.polaroid:hover, +a.polaroid:focus, +a.polaroid:active { + z-index: 999; + border-color: #6A6A6A; + -webkit-box-shadow: 15px 15px 20px rgba(0,0, 0, 0.4); + -moz-box-shadow: 15px 15px 20px rgba(0,0, 0, 0.4); + box-shadow: 15px 15px 20px rgba(0,0, 0, 0.4); + -webkit-transform: rotate(0deg) scale(1.05); + -moz-transform: rotate(0deg) scale(1.05); + transform: rotate(0deg) scale(1.05); +} +.polaroid img { + margin: 0 0 15px; + width: 150px; + height: 150px; +} + +a img { + border: none; + display: block; +} + +.photo-album { + position: relative; + width: 80%; + margin: 0 auto; + max-width: 70em; + height: 450px; + margin-top: 5em; + min-width: 800px; + max-width: 900px; +} +.photo-album .polaroid { + position: absolute; +} +.photo-album h1 { + position: absolute; + z-index: 5; + top: 150px; + text-align: center; + width: 100%; + line-height: 1.9; +} +.photo-album h1 span { + background-color: white; + font-family: "Helvetica Neue",Arial,Helvetica,sans-serif; + padding: 0.4em 0.8em 0.3em 0.8em; + -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3); + -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3); + box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3); + border: 1px solid #6A6A6A; +} +.photo-album .small { + width: 75px; + padding: 6px 6px 12px 6px; + font-size: 0.6em; +} +.photo-album .small img { + width: 75px; + height: 75px; +} +.photo-album .medium { + width: 200px; + padding: 13px 13px 26px 13px; + font-size: 0.8em; +} +.photo-album .medium img { + width: 200px; + height: 200px; +} +.photo-album .large { + width: 300px; + padding: 20px 20px 30px 20px; + font-size: 1em; +} +.photo-album .large img { + width: 300px; + height: 300px; +} +.photo-album .img1 { + bottom: 10px; + right: 365px; + -webkit-transform: rotate(10deg); + -moz-transform: rotate(10deg); + transform: rotate(10deg); +} +.photo-album .img2 { + top: 50px; + right: 20px; + -webkit-transform: rotate(-4deg); + -moz-transform: rotate(-4deg); + transform: rotate(-4deg); +} +.photo-album .img3 { + left: 400px; + top: 0; + -webkit-transform: rotate(-5deg); + -moz-transform: rotate(-5deg); + transform: rotate(-5deg); +} +.photo-album .img4 { + top: 10px; + left: 495px; + -webkit-transform: rotate(-20deg); + -moz-transform: rotate(-20deg); + transform: rotate(-20deg); +} +.photo-album .img5 { + bottom: 0; + right: 0; + -webkit-transform: rotate(1deg); + -moz-transform: rotate(1deg); + transform: rotate(1deg); +} +.photo-album .img6 { + bottom: 10px; + right: 156px; + -webkit-transform: rotate(6deg); + -moz-transform: rotate(6deg); + transform: rotate(6deg); +} +.photo-album .img7 { + bottom:0; + left:400px; + -webkit-transform: rotate(-10deg); + -moz-transform: rotate(-10deg); + transform: rotate(-10deg); +} +.photo-album .img8 { + bottom: -20px; + left: 700px; + -webkit-transform: rotate(-8deg); + -moz-transform: rotate(-8deg); + transform: rotate(-8deg); +} +.photo-album .img9 { + bottom: 0; + left: 0; + -webkit-transform: rotate(-8deg); + -moz-transform: rotate(-8deg); + transform: rotate(-8deg); +} +.photo-album .img10 { + top: 0; + left: 20px; + -webkit-transform: rotate(8deg); + -moz-transform: rotate(8deg); + transform: rotate(8deg); +} +.photo-album .img11 { + top: 0; + right: 0; + -webkit-transform: rotate(-8deg); + -moz-transform: rotate(-8deg); + transform: rotate(-8deg); +} +.photo-album .img12 { + top: 0; + left: 680px; + -webkit-transform: rotate(18deg); + -moz-transform: rotate(18deg); + transform: rotate(18deg); +} +.photo-album .img13 { + bottom: -20px; + right: 630px; + -webkit-transform: rotate(4deg); + -moz-transform: rotate(4deg); + transform: rotate(4deg); +} +.photo-album .img14 { + top: 90px; + left: 430px; + -webkit-transform: rotate(15deg); + -moz-transform: rotate(15deg); + transform: rotate(15deg); +} +.photo-album .img15 { + left:176px; + top:20px; + -webkit-transform: rotate(-8deg); + -moz-transform: rotate(-8deg); + transform: rotate(-8deg); +} + +a:hover, +a:focus { + z-index: 5; +} \ No newline at end of file diff --git a/templates/index_with_randoms.html b/templates/index_with_randoms.html new file mode 100755 index 0000000..0fd3d3d --- /dev/null +++ b/templates/index_with_randoms.html @@ -0,0 +1,72 @@ + + + + + Deep Image Search + + + + + + + + + + +