Commit 1748c6ec authored by Julia Garriga Ferrer's avatar Julia Garriga Ferrer
Browse files

Merge branch 'improve_matching' into 'master'

Improve matching

See merge request julia.garriga/darfix!45
parents 32c236d6 0d3be1a7
Pipeline #22346 passed with stage
in 2 minutes and 18 seconds
py_testproject:
type: test
image: docker-registry.esrf.fr/dau/x11:python3.7_buster
before_script:
- apt-get update -qq && apt-get install -y -qq ocl-icd-opencl-dev opencl-c-headers opencl-clhpp-headers opencl-headers
# - apt-get update -qq && apt install -qq -y ocl-icd-libopencl1
- export SILX_OPENCL=1
script: # Run the tests from the installed module
- python -m pip install --upgrade pip
- pip install --upgrade setuptools wheel
......
......@@ -26,8 +26,7 @@
__authors__ = ["J. Garriga"]
__license__ = "MIT"
__date__ = "21/01/2020"
__date__ = "28/02/2020"
import cv2
import numpy
......@@ -101,7 +100,8 @@ class ComponentsMatching():
dst = numpy.linalg.norm(X - Y) # their euclidean distances
return dst
def match_components(self, id1=None, id2=None, method=Method.orb_feature_matching):
def match_components(self, id1=None, id2=None, method=Method.orb_feature_matching,
tol=8):
"""
Match components. Given the components x1,...,xn of dataset 1 and the
components y1,...,ym of dataset 2, this function computes the pairs
......@@ -122,7 +122,7 @@ class ComponentsMatching():
id1 = 0
id2 = 1
matches = {}
good = {}
final_matches = {}
if method == Method.orb_feature_matching:
self.descriptors = self._create_descriptors()
......@@ -133,42 +133,65 @@ class ComponentsMatching():
if component1.descriptor is not None:
for j, component2 in enumerate(self.descriptors[id2]):
if component2.descriptor is not None:
# Match descriptors
matches[(i, j)] = bf.match(component1.descriptor,
component2.descriptor)
good[(i, j)] = numpy.array(bf.match(component1.descriptor,
component2.descriptor))
best_v = []
# Add matches sorted by number of matches found.
for x, y in sorted(matches, key=lambda match: len(matches[match]),
for x, y in sorted(good, key=lambda match: len(good[match]),
reverse=True):
# Only add match if neither x nor y are already in the list.
if x not in final_matches.keys() and y not in final_matches.values():
final_matches[x] = y
kp1 = []
kp2 = []
for match in good[(x, y)]:
kp1 += [self.descriptors[id1][x].keypoints[match.queryIdx].pt]
kp2 += [self.descriptors[id2][y].keypoints[match.trainIdx].pt]
if len(kp1) > 1 and len(kp2) > 1:
v = numpy.mean(numpy.array(kp2) - numpy.array(kp1), axis=0)
else:
v = numpy.array(kp2) - numpy.array(kp1)
if not numpy.any(best_v):
best_v = v
final_matches[x] = y
elif numpy.linalg.norm(best_v - v) < tol:
final_matches[x] = y
elif method == Method.sift_feature_matching:
keypoints = self._create_sift_keypoints()
best_v = []
mp = sift.MatchPlan()
# Match components with id1 and id2
for i, kp1 in enumerate(keypoints[id1]):
for j, kp2 in enumerate(keypoints[id2]):
# Match descriptors
matches[(i, j)] = mp.match(kp1, kp2)
good[(i, j)] = mp.match(kp1, kp2)
# Add matches sorted by number of matches found.
for x, y in sorted(matches, key=lambda match: matches[match].shape[0],
for x, y in sorted(good, key=lambda match: good[match].shape[0],
reverse=True):
# Only add match if neither x nor y are already in the list.
if x not in final_matches.keys() and y not in final_matches.values():
final_matches[x] = y
v = numpy.array([numpy.median(good[(x, y)][:, 1].x - good[(x, y)][:, 0].x),
numpy.median(good[(x, y)][:, 1].y - good[(x, y)][:, 0].y)])
if not numpy.any(best_v):
best_v = v
final_matches[x] = y
elif numpy.linalg.norm(best_v - v) < tol:
final_matches[x] = y
elif method == Method.euclidean_distance:
for i, X in enumerate(self.components[id1]):
for j, Y in enumerate(self.components[id2]):
matches[(i, j)] = self.euclidean_distance(X, Y)
good[(i, j)] = self.euclidean_distance(X, Y)
# Add matches sorted by distance.
for x, y in sorted(matches, key=lambda match: matches[match]):
for x, y in sorted(good, key=lambda match: good[match]):
# Only add match if neither x nor y are already in the list.
if x not in final_matches.keys() and y not in final_matches.values():
final_matches[x] = y
return final_matches, matches
return final_matches, good
def draw_matches(self, final_matches, matches, id1=None, id2=None,
displayMatches=False):
......@@ -201,6 +224,7 @@ class ComponentsMatching():
assert all((isinstance(match, cv2.DMatch) for match in values)
for values in matches.values()), \
"Dictionary `matches` has to contain values of type `cv2.DMatch`"
img = cv2.drawMatches(self.descriptors[id1][i].image,
self.descriptors[id1][i].keypoints,
self.descriptors[id2][j].image,
......
......@@ -33,6 +33,8 @@ import unittest
import numpy
from silx.opencl.common import ocl
from darfix.core.componentsMatching import ComponentsMatching, Method
from skimage import data
......@@ -63,8 +65,12 @@ class TestComponentsMatching(unittest.TestCase):
self.assertNotEqual(ed, 0)
def test_match_components(self):
@unittest.skipUnless(ocl, "PyOpenCl is missing")
def test_sift_match(self):
final_matches, matches = self.componentsMatching.match_components(method=Method.sift_feature_matching)
self.assertEqual(final_matches[0], 1)
def test_orb_match(self):
final_matches, matches = self.componentsMatching.match_components(method=Method.orb_feature_matching)
self.assertEqual(final_matches[0], 1)
......@@ -79,3 +85,9 @@ class TestComponentsMatching(unittest.TestCase):
final_matches, matches = self.componentsMatching.match_components(method=Method.euclidean_distance)
stack = self.componentsMatching.draw_matches(final_matches, matches)
self.assertEqual(stack[2].shape, (512, 1024))
@unittest.skipUnless(ocl, "PyOpenCl is missing")
def test_draw_matches2(self):
final_matches, matches = self.componentsMatching.match_components(method=Method.sift_feature_matching)
stack = self.componentsMatching.draw_matches(final_matches, matches)
self.assertEqual(stack[2].shape, (512, 1024))
%% Cell type:code id: tags:
``` python
import silx
comp1 = "/users/garrigaf/Documents/tests/Nexus/heat1/layer0"
comp2 = "/users/garrigaf/Documents/tests/Nexus/heat1/layer1"
from darfix.io.utils import read_components
d1, c1, W1 = read_components(comp1)
d2, c2, W2 = read_components(comp2)
```
%% Cell type:code id: tags:
``` python
```
%% Cell type:code id: tags:
``` python
Z = kmeans.predict(W.T).reshape((2, len(c1)))
```
%% Cell type:code id: tags:
``` python
Z
```
%% Output
array([[12, 4, 8, 14, 28, 17, 7, 11, 10, 26, 19, 6, 23, 1, 0, 21,
13, 15, 20, 2, 4, 20, 18, 24, 3, 27, 16, 9, 22, 5],
[20, 13, 6, 18, 25, 7, 9, 11, 29, 15, 4, 19, 27, 21, 20, 14,
8, 0, 10, 17, 5, 1, 3, 24, 23, 16, 16, 22, 2, 22]],
dtype=int32)
%% Cell type:code id: tags:
``` python
from matplotlib import pyplot as plt
keys = list(d1.keys())
plt.scatter(d1[keys[0]], d1[keys[1]], c=W1.T[1], cmap="jet")
```
%% Output
<matplotlib.collections.PathCollection at 0x7fd3d29f8128>
%% Cell type:code id: tags:
``` python
plt.scatter(d2[keys[0]], d2[keys[1]], c=W2.T[10], cmap="jet")
```
%% Output
<matplotlib.collections.PathCollection at 0x7fd3d2833dd8>
This source diff could not be displayed because it is too large. You can view the blob instead.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment