Skip to main content

Extract_patches

Simple function for local patch extraction from local features keypoints

Install

pip install extract_patches

How to use

extract_patches accepts following formats:

  • OpenCV keypoints
  • Ellipse format [x y a b c], see further in Oxford-Affine
  • Affine features format [x y a11 a12 a21 a22], see further here
  • OpenCV keypoints + A (a11 a12 a21, a22), say from AffNet output

First, let's delect some local features, e.g. OpenCV ORB.

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import cv2
import math
import seaborn as sns
from time import time
from PIL import Image
from extract_patches.core import extract_patches

img1 = cv2.cvtColor(cv2.imread('data/img/prague.png'), cv2.COLOR_BGR2RGB)

det = cv2.ORB_create(500)
kps1, descs1 = det.detectAndCompute(img1,None)

vis_img1 = None
vis_img1 = cv2.drawKeypoints(cv2.cvtColor(img1,cv2.COLOR_RGB2GRAY),kps1,vis_img1, 
                             flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
plt.imshow(vis_img1)
<matplotlib.image.AxesImage at 0x7feb58b46790>

png

from extract_patches.core import extract_patches

extract_patches performs extraction from the appropriate level of image pyramid, removing high freq artifacts. Border mode is set to "replicate", so the patch don't have crazy black borders.

PATCH_SIZE is output patch size.

mrSize is a scale coefficient, related to the image area covered in the original image by local feature. There are different conventions (if any common), e.g. for ORB is mrSize is recommend to set to 1.0, as kpt.size already contains correct number. For the OpenCV SIFT, on the other hand, one should use mrSize=6.0

PATCH_SIZE = 65
mrSize = 1.0
t=time()
patches = extract_patches(kps1, img1, PATCH_SIZE, mrSize, 'cv2')
print ('pyr OpenCV version for 500 kps, [s]', time()-t)

show_idx = 300
fig = plt.figure(figsize=(12, 20))
for i in range(1,6):
    fig.add_subplot(1, 5, i) 
    plt.imshow(patches[show_idx+i])
pyr OpenCV version for 500 kps, [s] 0.025847196578979492

png

Now try with ellipse (x y a b c) format. Let's download Hessian-Affine from VGG website and detect local features with it

!rm h_affine.ln
!wget http://www.robots.ox.ac.uk/~vgg/research/affine/det_eval_files/h_affine.ln.gz
!gunzip h_affine.ln.gz
!chmod +x h_affine.ln
!./h_affine.ln  -hesaff -i img/prague.png -o prague.hesaff -thres 100
--2020-01-27 15:21:55--  http://www.robots.ox.ac.uk/~vgg/research/affine/det_eval_files/h_affine.ln.gz
Resolving www.robots.ox.ac.uk (www.robots.ox.ac.uk)... 129.67.94.2
Connecting to www.robots.ox.ac.uk (www.robots.ox.ac.uk)|129.67.94.2|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3199317 (3.1M) [application/x-gzip]
Saving to: ‘h_affine.ln.gz’

h_affine.ln.gz      100%[===================>]   3.05M  1.80MB/s    in 1.7s    

2020-01-27 15:21:56 (1.80 MB/s) - ‘h_affine.ln.gz’ saved [3199317/3199317]

hessian affine  detector...
cgood 1902 cbad 560 all 2462
cor nb 1679
detection time: 0.4

number of points : 1562
output file: prague.hesaff

Now read extracted local features from txt file

from extract_patches.laf import visualize_LAFs, ells2LAFs
ells = np.loadtxt('prague.hesaff', skiprows=2).astype(np.float32)
print (f"Shape is {ells.shape}")
print (ells[0:5])
Shape is (1562, 5)
[[ 1.33920e+02  1.25280e+02  3.40137e-02 -2.62884e-02  9.84345e-02]
 [ 6.63840e+02  1.85760e+02  4.18373e-02  2.33503e-02  7.24527e-02]
 [ 6.78240e+02  1.92960e+02  1.07543e-01 -2.07333e-02  3.04518e-02]
 [ 4.14720e+02  1.98720e+02  3.24049e-02 -3.11269e-03  7.01242e-02]
 [ 5.68800e+02  2.00160e+02  2.22278e-02  3.34806e-02  1.39287e-01]]

Now visualize detected features

from extract_patches.laf import visualize_LAFs, ells2LAFs
visualize_LAFs(img1, ells2LAFs(ells))

png

And visualize some patches

show_idx=1500
PATCH_SIZE = 65
mrSize = 5.0

t=time()
patches_ells = extract_patches(ells, img1, PATCH_SIZE, mrSize, 'ellipse')
el=time()-t
print (f'extract from ellipse features for 1500 kps, {el:.5f} [s]', )
fig = plt.figure(figsize=(14, 20))
for i in range(1,6):
    fig.add_subplot(1, 5, i) 
    plt.imshow(patches_ells[show_idx+i])

extract from ellipse features for 1500 kps, 0.24170 [s]

png

Let's try now MSER detector, which could output local features in affine format

#And lets try x y a11 a12 a21 a22 format. MSER can output in it
!wget http://www.robots.ox.ac.uk/~vgg/research/affine/det_eval_files/mser.tar.gz
!tar -xf mser.tar.gz
!./mser.ln -i img/prague.png -o prague.mser  -t 4
--2020-01-27 15:22:05--  http://www.robots.ox.ac.uk/~vgg/research/affine/det_eval_files/mser.tar.gz
Resolving www.robots.ox.ac.uk (www.robots.ox.ac.uk)... 129.67.94.2
Connecting to www.robots.ox.ac.uk (www.robots.ox.ac.uk)|129.67.94.2|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 558415 (545K) [application/x-gzip]
Saving to: ‘mser.tar.gz.6’

mser.tar.gz.6       100%[===================>] 545.33K  1.66MB/s    in 0.3s    

2020-01-27 15:22:05 (1.66 MB/s) - ‘mser.tar.gz.6’ saved [558415/558415]

Read and extract from MSERs

def read_mser_file(fname):
    with open(fname, 'r') as f:
        out = []
        lines = f.readlines()
        num_feats1 = int(lines[0])
        num_feats2 = int(lines[0+num_feats1+1])
        for l in lines[1:num_feats1]:
            out.append(np.array([float(x) for x in l.strip().split(' ')]).reshape(1,-1))
        for l in lines[num_feats1+2:]:
            out.append(np.array([float(x) for x in l.strip().split(' ')]).reshape(1,-1))
    return np.concatenate(out,axis=0)[:,:6]
mser_xyA = read_mser_file('prague.mser')
print (f"Shape is {mser_xyA.shape}")
print (mser_xyA[0:5])
visualize_LAFs(img1, mser_xyA)
Shape is (361, 6)
[[ 79.2818   410.027     12.2143    -3.72324   -3.72324    3.38642 ]
 [  6.23611  433.042      7.13002   -1.6485    -1.6485     4.45321 ]
 [546.992    445.621      8.79801    2.71022    2.71022   13.7868  ]
 [659.924    344.894      7.26102    0.842102   0.842102   1.73304 ]
 [651.968    344.841     15.5017     1.13132    1.13132    3.68829 ]]

png

PATCH_SIZE = 65
mrSize = 5.0

t=time()
patches_mser = extract_patches(mser_xyA, img1, PATCH_SIZE, mrSize, 'xyA')
el = time()-t
print (f'extract from a11, a12, a21, a22 features for 360 kps, {el:.5f} [s]')

show_idx=150
fig = plt.figure(figsize=(14, 20))
for i in range(1,6):
    fig.add_subplot(1, 5, i) 
    plt.imshow(patches_mser[show_idx+i])
extract from a11, a12, a21, a22 features for 360 kps, 0.02284 [s]

png

Metadata

Release files for extract-patches 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for extract-patches 0.2.0
File Size Uploaded Provenance
extract_patches-0.2.0.tar.gz 12.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for extract-patches 0.2.0
File Interpreter ABI Platform
extract_patches-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 25.1 kB

Release files / extract_patches-0.2.0.tar.gz

Download URL extract_patches-0.2.0.tar.gz
Size 12.7 kB
Tags Source
SHA-256 checksum
How to use checksums
6f142589209c1f7e37462210a81128ffee72435bd7614d6a02216e79208dcc80
BLAKE2b-256 checksum
How to use checksums
919f97ea04157f6760b16c27240fc1d8154f65dc841f1b6305dd6e1e9b0fd3b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release files / extract_patches-0.2.0-py3-none-any.whl

Download URL extract_patches-0.2.0-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a2b3d2c6afc1cfd4cf7fd3698c4eadbbe2044c149906f6e74b071da465f14497
BLAKE2b-256 checksum
How to use checksums
e4d7d661bdeed19dd6839cff74bb2e122da14bf670ed0ecbb2d6fe2bd80f36ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Security for extract-patches 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for extract_patches-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page