Skip to content

Commit

Permalink
Merge pull request #9 from QVPR/conda_pypi_fixes
Browse files Browse the repository at this point in the history
Fixes for pypi/conda release
  • Loading branch information
Tobias-Fischer committed Jun 2, 2021
2 parents 051127d + 2177ecb commit 259874b
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 17 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

name: Upload Python Package

on:
release:
types: [created]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
patchnetvlad/pretrained_models/*
patchnetvlad/results/*
patchnetvlad/output_features/*
results/*

## Python stuff
# Byte-compiled / optimized / DLL files
Expand Down
2 changes: 1 addition & 1 deletion feature_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def main():

torch.cuda.empty_cache() # garbage clean GPU memory, a bug can occur when Pytorch doesn't automatically clear the
# memory after runs
print('Done. Finished extracting and saving features')
print('\n\nDone. Finished extracting and saving features')


if __name__ == "__main__":
Expand Down
18 changes: 13 additions & 5 deletions feature_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def compute_recall(gt, predictions, numQ, n_values, recall_str=''):
def write_kapture_output(opt, eval_set, predictions, outfile_name):
if not exists(opt.result_save_folder):
os.mkdir(opt.result_save_folder)
with open(join(opt.result_save_folder, outfile_name), 'w') as kap_out:
outfile = join(opt.result_save_folder, outfile_name)
print('Writing results to', outfile)
with open(outfile, 'w') as kap_out:
kap_out.write('# kapture format: 1.0\n')
kap_out.write('# query_image, map_image\n')
image_list_array = np.array(eval_set.images)
Expand All @@ -87,7 +89,9 @@ def write_kapture_output(opt, eval_set, predictions, outfile_name):
def write_recalls_output(opt, recalls_netvlad, recalls_patchnetvlad, n_values):
if not exists(opt.result_save_folder):
os.mkdir(opt.result_save_folder)
with open(join(opt.result_save_folder, 'recalls.txt'), 'w') as rec_out:
outfile = join(opt.result_save_folder, 'recalls.txt')
print('Writing recalls to', outfile)
with open(outfile, 'w') as rec_out:
for n in n_values:
rec_out.write("Recall {}@{}: {:.4f}\n".format('NetVLAD', n, recalls_netvlad[n]))
for n in n_values:
Expand Down Expand Up @@ -120,7 +124,8 @@ def feature_match(eval_set, device, opt, config):
if config['feature_match']['pred_input_path'] != 'None':
predictions = np.load(config['feature_match']['pred_input_path']) # optionally load predictions from a np file
else:
if opt.ground_truth_path.split('/')[1][:-4] == 'tokyo247':
if opt.ground_truth_path and 'tokyo247' in opt.ground_truth_path:
print('Tokyo24/7: Selecting only one of the 12 cutouts per panorama')
# followed nnSearchPostprocess in https://github.com/Relja/netvlad/blob/master/datasets/dbTokyo247.m
# noinspection PyArgumentList
_, predictions = faiss_index.search(qFeat, max(n_values) * 12) # 12 cutouts per panorama
Expand All @@ -133,7 +138,7 @@ def feature_match(eval_set, device, opt, config):
predictions = np.array(predictions_new)
else:
# noinspection PyArgumentList
_, predictions = faiss_index.search(qFeat, max(n_values))
_, predictions = faiss_index.search(qFeat, min(len(qFeat), max(n_values)))

reranked_predictions = local_matcher(predictions, eval_set, input_query_local_features_prefix,
input_index_local_features_prefix, config, device)
Expand All @@ -142,16 +147,19 @@ def feature_match(eval_set, device, opt, config):
write_kapture_output(opt, eval_set, predictions, 'NetVLAD_predictions.txt')
write_kapture_output(opt, eval_set, reranked_predictions, 'PatchNetVLAD_predictions.txt')

print('Finished matching features. About to eval GT if GT was provided')
print('Finished matching features.')

# for each query get those within threshold distance
if opt.ground_truth_path is not None:
print('Calculating recalls using ground truth.')
gt = eval_set.get_positives()

global_recalls = compute_recall(gt, predictions, eval_set.numQ, n_values, 'NetVLAD')
local_recalls = compute_recall(gt, reranked_predictions, eval_set.numQ, n_values, 'PatchNetVLAD')

write_recalls_output(opt, global_recalls, local_recalls, n_values)
else:
print('No ground truth was provided; not calculating recalls.')


def main():
Expand Down
2 changes: 1 addition & 1 deletion match_two.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def match_two(model, device, opt, config):
scores, inlier_keypoints_one, inlier_keypoints_two = matcher.match(local_feats_one, local_feats_two)
score = -normalise_func(scores, len(patch_sizes), patch_weights)

print("Similarity score between the two images is: '{:.5f}'. In this example, a larger score indicates a better match.".format(score))
print(f"Similarity score between the two images is: {score:.5f}. Larger scores indicate better matches.")

if config['feature_match']['matcher'] == 'RANSAC':
tqdm.write('====> Plotting Local Features')
Expand Down
8 changes: 4 additions & 4 deletions patchnetvlad/models/local_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,17 @@ def local_matcher(predictions, eval_set, input_query_local_features_prefix,

for q_idx, pred in enumerate(tqdm(predictions, leave=False, desc='Patch compare pred')):
diffs = np.zeros((predictions.shape[1], len(patch_sizes)))
image_name = os.path.splitext(os.path.basename(eval_set.images[eval_set.numDb + q_idx]))[0]
image_name_query = os.path.splitext(os.path.basename(eval_set.images[eval_set.numDb + q_idx]))[0]
qfeat = []
for patch_size in patch_sizes:
qfilename = input_query_local_features_prefix + '_' + 'psize{}_'.format(patch_size) + image_name + '.npy'
qfilename = input_query_local_features_prefix + '_' + 'psize{}_'.format(patch_size) + image_name_query + '.npy'
qfeat.append(torch.transpose(torch.tensor(np.load(qfilename), device=device), 0, 1))
# we pre-transpose here to save compute speed
for k, candidate in enumerate(pred):
image_name = os.path.splitext(os.path.basename(eval_set.images[candidate]))[0]
image_name_index = os.path.splitext(os.path.basename(eval_set.images[candidate]))[0]
dbfeat = []
for patch_size in patch_sizes:
dbfilename = input_index_local_features_prefix + '_' + 'psize{}_'.format(patch_size) + image_name + '.npy'
dbfilename = input_index_local_features_prefix + '_' + 'psize{}_'.format(patch_size) + image_name_index + '.npy'
dbfeat.append(torch.tensor(np.load(dbfilename), device=device))

diffs[k, :], _, _ = matcher.match(qfeat, dbfeat)
Expand Down
6 changes: 6 additions & 0 deletions patchnetvlad/tools/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from PIL import Image
from sklearn.neighbors import NearestNeighbors

from patchnetvlad.tools import PATCHNETVLAD_ROOT_DIR


class PlaceDataset(data.Dataset):
def __init__(self, query_file_path, index_file_path, dataset_root_dir, ground_truth_path, config):
Expand All @@ -52,6 +54,10 @@ def __init__(self, query_file_path, index_file_path, dataset_root_dir, ground_tr
self.images = self.database

self.images = [os.path.join(dataset_root_dir, image) for image in self.images]
# check if images are relative to root dir
if not os.path.isfile(self.images[0]):
if os.path.isfile(os.path.join(PATCHNETVLAD_ROOT_DIR, self.images[0])):
self.images = [os.path.join(PATCHNETVLAD_ROOT_DIR, image) for image in self.images]

self.positives = None
self.distances = None
Expand Down
20 changes: 14 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os
import os, sys
from setuptools import setup, find_packages


Expand All @@ -9,8 +9,19 @@
long_description = f.read()


install_require_list = [
'numpy', 'torch', 'torchvision',
'tqdm', 'scipy', 'Pillow', 'scikit-learn',
'faiss', 'natsort']

# workaround as opencv-python does not show up in "pip list" within a conda environment
# we do not care as conda recipe has py-opencv requirement anyhow
is_conda = os.path.exists(os.path.join(sys.prefix, 'conda-meta'))
if not is_conda:
install_require_list.append('opencv-python')

setup(name='patchnetvlad',
version='0.1.0',
version='0.1.1',
description='Patch-NetVLAD: An open-source Python implementation of the CVPR2021 paper',
long_description = long_description,
long_description_content_type='text/markdown',
Expand All @@ -37,10 +48,7 @@
'Programming Language :: Python :: 3.9',
],
python_requires='>=3.6',
install_requires=[
'numpy', 'torch', 'torchvision',
'tqdm', 'scipy', 'Pillow', 'scikit-learn',
'faiss', 'natsort', 'opencv-python'],
install_requires=install_require_list,
packages=find_packages(),
keywords=[
'python', 'place recognition', 'image retrieval', 'computer vision', 'robotics'
Expand Down

0 comments on commit 259874b

Please sign in to comment.