Coupled Decomposition - Part III¶
[2]:
import math
import os
import sys
sys.path.insert(0, os.path.abspath('/data/autocnet'))
import autocnet
from autocnet import CandidateGraph
# The GPU based extraction library that contains SIFT extraction and matching
import cudasift as cs
# A method to resize the images on the fly.
from scipy.misc import imresize
# Fundamental matrix computation
from autocnet.transformation import fundamental_matrix as fm
from autocnet.transformation.decompose import coupled_decomposition
from scipy.spatial.distance import cdist
%pylab inline
figsize(16,4)
Populating the interactive namespace from numpy and matplotlib
Preprocessing¶
[3]:
a = 'AS15-P-0111_CENTER_LRG_CROPPED.png'
b = 'AS15-P-0112_CENTER_LRG_CROPPED.png'
adj = {a:[b],
b:[a]}
cg = CandidateGraph.from_adjacency(adj)
# Enable the GPU
autocnet.cuda(enable=True, gpu=0)
[4]:
# Write a custom keypoint extraction function - this could get monkey patched onto the graph object...
def extract(arr, downsample_amount=None, **kwargs):
total_size = arr.shape[0] * arr.shape[1]
if not downsample_amount:
downsample_amount = math.ceil(total_size / 12500**2)
shape = (int(arr.shape[0] / downsample_amount), int(arr.shape[1] / downsample_amount))
# Downsample
arr = imresize(arr, shape, interp='lanczos')
npts = max(arr0.shape) / 3.5
sd = cs.PySiftData(npts)
cs.ExtractKeypoints(arr, sd, **kwargs)
kp, des = sd.to_data_frame()
kp = kp[['x', 'y', 'scale', 'sharpness', 'edgeness', 'orientation', 'score', 'ambiguity']]
kp['score'] = 0.0
kp['ambiguity'] = 0.0
return kp, des, sd, downsample_amount, arr
[5]:
# Write a generic decomposer
def custom_decompose(arr0, arr1):
kp0, des0, sd0, downsample_amount0, arr0 = extract(arr0, thresh=1)
kp1, des1, sd1, downsample_amount1, arr1 = extract(arr1, thresh=1)
# Now apply matching, outlier detection, and compute a fundamental matrix
sd0 = cs.PySiftData.from_data_frame(kp0, des0)
sd1 = cs.PySiftData.from_data_frame(kp1, des1)
# Apply the matcher
cs.PyMatchSiftData(sd0, sd1)
matches, _ = sd0.to_data_frame()
# Generic decision about ambiguity and score based on quantiles
# Apply outlier detection methods for the matches
ambiguity_threshold = matches.ambiguity.quantile(0.01) # Grabbing the 1%s in this data set
score = matches.score.quantile(0.85)
submatches = matches.query('ambiguity <= {} and score >= {}'.format(ambiguity_threshold, score))
# Compute a fundamental matrix
kpa = submatches[['x','y']]
kpb = submatches[['match_xpos', 'match_ypos']]
F, mask = fm.compute_fundamental_matrix(kpa, kpb, method='ransac', reproj_threshold=2.0)
F = fm.enforce_singularity_constraint(F)
# Grab the inliers
inliers = submatches[mask]
# Prepare for coupled decomposition
midx = arr0.shape[1] / 2
midy = arr0.shape[0] / 2
mid = np.array([[midx, midy]])
dists = cdist(mid, inliers[['x', 'y']])
mid_correspondence = inliers.iloc[np.argmin(dists)]
mid_correspondence
# Decompose the images into quadrants
smembership, dmembership, = coupled_decomposition(arr0, arr1,
sorigin=mid_correspondence[['x', 'y']],
dorigin=mid_correspondence[['match_xpos', 'match_ypos']],
theta=0)
# Return the membership decisions
return smembership, dmembership
[6]:
import pandas as pd
gd0 = cg.node[0].geodata
gd1 = cg.node[1].geodata
membership0 = np.zeros(gd0.raster_size[::-1], dtype=np.int8)
membership1 = np.zeros(gd1.raster_size[::-1], dtype=np.int8)
# Recursively decompose twice.
pcounter = 0
for k in range(2):
print(k)
partitions = np.unique(membership0)
for p in partitions:
# Get the source extent as MBR
sypart, sxpart = np.where(membership0 == p)
minsy = np.min(sypart)
maxsy = np.max(sypart) + 1
minsx = np.min(sxpart)
maxsx = np.max(sxpart) + 1
del sypart, sxpart
# Get the destination extent as MBR
dypart, dxpart = np.where(membership1 == p)
mindy = np.min(dypart)
maxdy = np.max(dypart) + 1
mindx = np.min(dxpart)
maxdx = np.max(dxpart) + 1
# Offsets into classified array
sdy = dypart - min(dypart)
sdx = dxpart - min(dxpart)
print(minsy, maxsy, minsx, maxsx)
print(mindy, maxdy, mindx, maxdx)
arr0 = gd0.read_array(pixels=map(int, [minsx, minsy, maxsx-minsx, maxsy-minsy]))
arr1 = gd1.read_array(pixels=map(int,[mindx, mindy, maxdx-mindx, maxdy-mindy]))
smem, dmem = custom_decompose(arr0, arr1)
smem += pcounter
dmem += pcounter
# Some fancy indexing to get the dmembership into the right place in the global membership
membership0[minsy:maxsy,minsx:maxsx] = smem
membership1[dypart, dxpart] = dmem[sdy, sdx]
pcounter += 4
# Force cleanup
arr0 = None
arr1 = None
0
0 11510 0 59720
0 11568 0 59770
0 0 59720 11510
0 0 59770 11568
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-6-a10dc6618433> in <module>()
43
44 # Some fancy indexing to get the dmembership into the right place in the global membership
---> 45 membership0[minsy:maxsy,minsx:maxsx] = smem
46 membership1[dypart, dxpart] = dmem[sdy, sdx]
47 pcounter += 4
ValueError: could not broadcast input array from shape (2302,11944) into shape (11510,59720)
[ ]: