Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #50

Merged
merged 2 commits into from
Jul 27, 2024
Merged

Dev #50

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ third_party/QuadTreeAttention
desktop.ini
*.egg-info
output.pkl
log.txt
experiments*
gen_example.py
datasets/lines/terrace0.JPG
Expand Down
31 changes: 27 additions & 4 deletions hloc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
import logging
import sys

import torch
from packaging import version

__version__ = "1.5"

LOG_PATH = "log.txt"


def read_logs():
sys.stdout.flush()
with open(LOG_PATH, "r") as f:
return f.read()


def flush_logs():
sys.stdout.flush()
logs = open(LOG_PATH, "w")
logs.close()


formatter = logging.Formatter(
fmt="[%(asctime)s %(name)s %(levelname)s] %(message)s",
datefmt="%Y/%m/%d %H:%M:%S",
)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
handler.setLevel(logging.INFO)

logs_file = open(LOG_PATH, "w")
logs_file.close()

file_handler = logging.FileHandler(filename=LOG_PATH)
file_handler.setFormatter(formatter)
file_handler.setLevel(logging.INFO)
stdout_handler = logging.StreamHandler()
stdout_handler.setFormatter(formatter)
stdout_handler.setLevel(logging.INFO)
logger = logging.getLogger("hloc")
logger.setLevel(logging.INFO)
logger.addHandler(handler)
logger.addHandler(file_handler)
logger.addHandler(stdout_handler)
logger.propagate = False

try:
Expand Down
84 changes: 70 additions & 14 deletions ui/app_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from easydict import EasyDict as edict
from omegaconf import OmegaConf

from hloc import flush_logs, read_logs
from ui.sfm import SfmEngine
from ui.utils import (
GRADIO_VERSION,
Expand All @@ -30,6 +31,11 @@
🐛 Your feedback is valuable to me. Please do not hesitate to report any bugs [here](https://github.com/Vincentqyw/image-matching-webui/issues).
"""

CSS = """
#warning {background-color: #FFCCCB}
.logs_class textarea {font-size: 12px !important}
"""


class ImageMatchingApp:
def __init__(self, server_name="0.0.0.0", server_port=7860, **kwargs):
Expand All @@ -52,7 +58,7 @@ def init_matcher_dropdown(self):
return algos

def init_interface(self):
with gr.Blocks() as self.app:
with gr.Blocks(css=CSS) as self.app:
with gr.Tab("Image Matching"):
with gr.Row():
with gr.Column(scale=1):
Expand Down Expand Up @@ -109,13 +115,36 @@ def init_interface(self):
)

with gr.Accordion("Advanced Setting", open=False):
with gr.Accordion("Image Setting", open=True):
with gr.Row():
image_force_resize_cb = gr.Checkbox(
label="Force Resize",
value=False,
interactive=True,
)
image_setting_height = gr.Slider(
minimum=48,
maximum=2048,
step=16,
label="Image Height",
value=480,
visible=False,
)
image_setting_width = gr.Slider(
minimum=64,
maximum=2048,
step=16,
label="Image Width",
value=640,
visible=False,
)
with gr.Accordion("Matching Setting", open=True):
with gr.Row():
match_setting_threshold = gr.Slider(
minimum=0.0,
maximum=1,
step=0.001,
label="Match thres.",
label="Match threshold",
value=0.1,
)
match_setting_max_keypoints = gr.Slider(
Expand All @@ -131,15 +160,15 @@ def init_interface(self):
minimum=0,
maximum=1,
step=0.001,
label="Keypoint thres.",
label="Keypoint threshold",
value=0.015,
)
detect_line_threshold = ( # noqa: F841
gr.Slider(
minimum=0.1,
maximum=1,
step=0.01,
label="Line thres.",
label="Line threshold",
value=0.2,
)
)
Expand Down Expand Up @@ -195,7 +224,12 @@ def init_interface(self):
"setting_geometry"
],
)

# image resize
image_force_resize_cb.select(
fn=self._on_select_force_resize,
inputs=image_force_resize_cb,
outputs=[image_setting_width, image_setting_height],
)
# collect inputs
state_cache = gr.State({})
inputs = [
Expand All @@ -211,7 +245,9 @@ def init_interface(self):
ransac_max_iter,
choice_geometry_type,
gr.State(self.matcher_zoo),
# state_cache,
image_force_resize_cb,
image_setting_width,
image_setting_height,
]

# Add some examples
Expand All @@ -236,6 +272,25 @@ def init_interface(self):
self.display_supported_algorithms()

with gr.Column():
with gr.Accordion("Open for More: Logs", open=False):
logs = gr.Textbox(
placeholder="\n" * 10,
label="Logs",
info="Verbose from inference will be displayed below.",
lines=10,
max_lines=10,
autoscroll=True,
elem_id="logs",
show_copy_button=True,
container=True,
elem_classes="logs_class",
)
self.app.load(read_logs, None, logs, every=1)
btn_clear_logs = gr.Button(
"Clear logs", elem_id="logs-button"
)
btn_clear_logs.click(flush_logs, [], [])

with gr.Accordion(
"Open for More: Keypoints", open=True
):
Expand Down Expand Up @@ -295,7 +350,6 @@ def init_interface(self):
inputs=match_image_src,
outputs=input_image1,
)

# collect outputs
outputs = [
output_keypoints,
Expand Down Expand Up @@ -336,6 +390,7 @@ def init_interface(self):
ransac_max_iter,
choice_geometry_type,
output_pred,
image_force_resize_cb,
]
button_reset.click(
fn=self.ui_reset_state,
Expand Down Expand Up @@ -422,6 +477,9 @@ def ui_change_imagebox(self, choice):
"source": choice, # The list of image sources to be displayed
}

def _on_select_force_resize(self, visible: bool = False):
return gr.update(visible=visible), gr.update(visible=visible)

def ui_reset_state(
self,
*args: Any,
Expand All @@ -446,6 +504,7 @@ def ui_reset_state(
int,
float,
int,
bool,
]:
"""
Reset the state of the UI.
Expand All @@ -456,13 +515,14 @@ def ui_reset_state(
key: str = list(self.matcher_zoo.keys())[
0
] # Get the first key from matcher_zoo
flush_logs()
return (
None, # image0: Optional[np.ndarray]
None, # image1: Optional[np.ndarray]
self.cfg["defaults"][
"match_threshold"
], # matching_threshold: float
self.cfg["defaults"]["max_keypoints"], # max_features: int
self.cfg["defaults"]["max_keypoints"], # max_keypoints: int
self.cfg["defaults"][
"keypoint_threshold"
], # keypoint_threshold: float
Expand All @@ -487,6 +547,7 @@ def ui_reset_state(
self.cfg["defaults"]["ransac_max_iter"], # ransac_max_iter: int
self.cfg["defaults"]["setting_geometry"], # geometry: str
None, # predictions
False,
)

def display_supported_algorithms(self, style="tab"):
Expand Down Expand Up @@ -589,12 +650,7 @@ def _update_options(self, option):
return gr.Textbox("not set", visible=True)

def _on_select_custom_params(self, value: bool = False):
return gr.Textbox(
label="Camera Params",
value="0,0,0,0",
interactive=value,
visible=value,
)
return gr.update(visible=value)

def _init_ui(self):
with gr.Row():
Expand Down
26 changes: 23 additions & 3 deletions ui/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,9 @@ def run_matching(
ransac_max_iter: int = DEFAULT_RANSAC_MAX_ITER,
choice_geometry_type: str = DEFAULT_SETTING_GEOMETRY,
matcher_zoo: Dict[str, Any] = None,
force_resize: bool = False,
image_width: int = 640,
image_height: int = 480,
use_cached_model: bool = False,
) -> Tuple[
np.ndarray,
Expand All @@ -853,6 +856,11 @@ def run_matching(
ransac_confidence (float, optional): RANSAC confidence level.
ransac_max_iter (int, optional): RANSAC maximum number of iterations.
choice_geometry_type (str, optional): setting of geometry estimation.
matcher_zoo (Dict[str, Any], optional): matcher zoo. Defaults to None.
force_resize (bool, optional): force resize. Defaults to False.
image_width (int, optional): image width. Defaults to 640.
image_height (int, optional): image height. Defaults to 480.
use_cached_model (bool, optional): use cached model. Defaults to False.

Returns:
tuple:
Expand Down Expand Up @@ -902,6 +910,12 @@ def run_matching(
t1 = time.time()

if model["dense"]:
match_conf["preprocessing"]["force_resize"] = force_resize
if force_resize:
match_conf["preprocessing"]["height"] = image_height
match_conf["preprocessing"]["width"] = image_width
logger.info(f"Force resize to {image_width}x{image_height}")

pred = match_dense.match_images(
matcher, image0, image1, match_conf["preprocessing"], device=DEVICE
)
Expand All @@ -925,6 +939,12 @@ def run_matching(
else:
extractor = get_feature_model(extract_conf)

extract_conf["preprocessing"]["force_resize"] = force_resize
if force_resize:
extract_conf["preprocessing"]["height"] = image_height
extract_conf["preprocessing"]["width"] = image_width
logger.info(f"Force resize to {image_width}x{image_height}")

pred0 = extract_features.extract(
extractor, image0, extract_conf["preprocessing"]
)
Expand All @@ -933,9 +953,9 @@ def run_matching(
)
pred = match_features.match_images(matcher, pred0, pred1)
del extractor
gr.Info(
f"Matching images done using: {time.time()-t1:.3f}s",
)
# gr.Info(
# f"Matching images done using: {time.time()-t1:.3f}s",
# )
logger.info(f"Matching images done using: {time.time()-t1:.3f}s")
t1 = time.time()

Expand Down
Loading