|
"""Run the TPAMI 2023 Perceptual model. |
|
|
|
Run the model of the paper |
|
A Deep Perceptual Measure for Lens and Camera Calibration, TPAMI 2023 |
|
https://lvsn.github.io/deepcalib/ |
|
through the public Dashboard available at http://rachmaninoff.gel.ulaval.ca:8005. |
|
""" |
|
|
|
import argparse |
|
import json |
|
import re |
|
import time |
|
from pathlib import Path |
|
|
|
from selenium import webdriver |
|
from selenium.webdriver.common.by import By |
|
from tqdm import tqdm |
|
|
|
|
|
|
|
JS_DROP_FILES = "var k=arguments,d=k[0],g=k[1],c=k[2],m=d.ownerDocument||document;for(var e=0;;){var f=d.getBoundingClientRect(),b=f.left+(g||(f.width/2)),a=f.top+(c||(f.height/2)),h=m.elementFromPoint(b,a);if(h&&d.contains(h)){break}if(++e>1){var j=new Error('Element not interactable');j.code=15;throw j}d.scrollIntoView({behavior:'instant',block:'center',inline:'center'})}var l=m.createElement('INPUT');l.setAttribute('type','file');l.setAttribute('multiple','');l.setAttribute('style','position:fixed;z-index:2147483647;left:0;top:0;');l.onchange=function(q){l.parentElement.removeChild(l);q.stopPropagation();var r={constructor:DataTransfer,effectAllowed:'all',dropEffect:'none',types:['Files'],files:l.files,setData:function u(){},getData:function o(){},clearData:function s(){},setDragImage:function i(){}};if(window.DataTransferItemList){r.items=Object.setPrototypeOf(Array.prototype.map.call(l.files,function(x){return{constructor:DataTransferItem,kind:'file',type:x.type,getAsFile:function v(){return x},getAsString:function y(A){var z=new FileReader();z.onload=function(B){A(B.target.result)};z.readAsText(x)},webkitGetAsEntry:function w(){return{constructor:FileSystemFileEntry,name:x.name,fullPath:'/'+x.name,isFile:true,isDirectory:false,file:function z(A){A(x)}}}}}),{constructor:DataTransferItemList,add:function t(){},clear:function p(){},remove:function n(){}})}['dragenter','dragover','drop'].forEach(function(v){var w=m.createEvent('DragEvent');w.initMouseEvent(v,true,true,m.defaultView,0,0,0,b,a,false,false,false,false,0,null);Object.setPrototypeOf(w,null);w.dataTransfer=r;Object.setPrototypeOf(w,DragEvent.prototype);h.dispatchEvent(w)})};m.documentElement.appendChild(l);l.getBoundingClientRect();return l" |
|
|
|
|
|
def setup_driver(): |
|
"""Setup the Selenium browser.""" |
|
options = webdriver.FirefoxOptions() |
|
geckodriver_path = "/snap/bin/geckodriver" |
|
driver_service = webdriver.FirefoxService(executable_path=geckodriver_path) |
|
return webdriver.Firefox(options=options, service=driver_service) |
|
|
|
|
|
def run(args): |
|
"""Run on an image folder.""" |
|
driver = setup_driver() |
|
driver.get("http://rachmaninoff.gel.ulaval.ca:8005/") |
|
time.sleep(5) |
|
result_div = driver.find_element(By.ID, "estimated-parameters-display") |
|
|
|
def upload_image(path): |
|
path = Path(path).absolute().as_posix() |
|
elem = driver.find_element(By.ID, "dash-uploader") |
|
inp = driver.execute_script(JS_DROP_FILES, elem, 25, 25) |
|
inp._execute("sendKeysToElement", {"value": [path], "text": path}) |
|
|
|
def run_image(path, prev_result, timeout_seconds=60): |
|
|
|
|
|
upload_image(path) |
|
started = time.time() |
|
while True: |
|
result = result_div.text |
|
if (result != prev_result) and result: |
|
return result |
|
prev_result = result |
|
if (time.time() - started) > timeout_seconds: |
|
raise TimeoutError |
|
|
|
result = str(result_div.text) |
|
number = r"(nan|-?\d*\.?\d*)" |
|
pattern = re.compile( |
|
f"Pitch: {number}° / Roll: {number}° / HFOV : {number}° / Distortion: {number}" |
|
) |
|
|
|
paths = sorted(args.images.iterdir()) |
|
results = {} |
|
for path in (pbar := tqdm(paths)): |
|
pbar.set_description(path.name) |
|
result = run_image(path, result) |
|
match = pattern.match(result) |
|
if match is None: |
|
print("Error, cannot parse:", result, path) |
|
continue |
|
results[path.name] = tuple(map(float, match.groups())) |
|
|
|
args.results.write_text(json.dumps(results)) |
|
driver.close() |
|
|
|
|
|
if __name__ == "__main__": |
|
parser = argparse.ArgumentParser() |
|
parser.add_argument("images", type=Path) |
|
parser.add_argument("results", type=Path) |
|
args = parser.parse_args() |
|
run(args) |
|
|