Source code for DICpy.DIC_2D._lucas_kanade
import numpy as np
import cv2
from DICpy.DIC_2D._image_registration import ImageRegistration
[docs]class LucasKanade(ImageRegistration):
"""
DIC with subpixel resolution using the Lucas-Kanade algorithm implemented in OpenCV-Python, and It is a child class
of `ImageRegistration`.
**Input:**
* **mesh_obj** (`object`)
Object of ``RegularGrid``.
**Attributes:**
* **pixel_dim** (`float`)
Constant to convert pixel into a physical quantity (e.g., mm).
* **mesh_obj** (`object`)
Object of the ``RegularGrid``.
* **u** (`ndarray`)
Displacements in the x (columns) dimension at the center of each cell.
* **v** (`ndarray`)
Displacements in the y (rows) dimension at the center of each cell.
**Methods:**
"""
def __init__(self, mesh_obj=None):
self.pixel_dim = mesh_obj.images_obj.pixel_dim
self.mesh_obj = mesh_obj
self.u = None
self.v = None
super().__init__(mesh_obj=mesh_obj)
[docs] def run(self):
"""
Method for performing the DIC analysis. It overrides the one in ``ImageRegistration``
"""
# Get images and the number of images in the object images.
images = self.mesh_obj.images_obj.images
num_img = self.mesh_obj.images_obj.num_img
# Get the nodes of the grid in the mesh object.
xp = self.mesh_obj.xp
yp = self.mesh_obj.yp
# initialize the lists receiving the horizontal (u) and vertical (v) displacements.
u = []
v = []
# Initialize the accumulator of displacements.
usum = np.zeros((self.mesh_obj.ny - 1, self.mesh_obj.nx - 1))
vsum = np.zeros((self.mesh_obj.ny - 1, self.mesh_obj.nx - 1))
# Loop over the images.
for k in range(num_img - 1):
img_0 = images[k] # image in the time t.
img_1 = images[k + 1] # image in the time t + dt.
centers = [] # list for the centers of the elements in the grid.
positions = [] # list for the position for the pixel positions of the upper left nodes of each element.
lx_list = [] # length in the direction x (columns) of each element.
ly_list = [] # length in the direction y (columns) of each element.
# Loop over the upper left nodes of each element.
for i in range(self.mesh_obj.ny - 1):
for j in range(self.mesh_obj.nx - 1):
positions.append([i, j])
l_x = abs(xp[i + 1, j + 1] - xp[i, j])
l_y = abs(yp[i + 1, j + 1] - yp[i, j])
xc = (xp[i + 1, j + 1] + xp[i, j]) / 2
yc = (yp[i + 1, j + 1] + yp[i, j]) / 2
centers.append(np.array([np.float32(xc), np.float32(yc)]))
lx_list.append(l_x)
ly_list.append(l_y)
l_x = np.max(lx_list)
l_y = np.max(ly_list)
centers = np.array(centers)
positions = np.array(positions)
# Parameters for the Lucas-Kanade method using opencv-python.
lk_params = dict(winSize=(l_x, l_y), maxLevel=10,
criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
# Get the final positions for the optical flow using Lucas-Kanade.
final_positions, st, err = cv2.calcOpticalFlowPyrLK(img_0, img_1, centers, None, **lk_params)
# The next steps are the update of the displacement for the template.
u0 = np.zeros((self.mesh_obj.ny - 1, self.mesh_obj.nx - 1))
v0 = np.zeros((self.mesh_obj.ny - 1, self.mesh_obj.nx - 1))
for i in range(len(final_positions)):
ii = positions[i, 0]
jj = positions[i, 1]
u0[ii, jj] = final_positions[i, 0] - centers[i, 0]
v0[ii, jj] = final_positions[i, 1] - centers[i, 1]
usum = usum + (u0 * self.pixel_dim)
vsum = vsum + (v0 * self.pixel_dim)
u.append(usum)
v.append(vsum)
# Instantiate the displacements.
self.u = np.array(u)
self.v = np.array(v)