#! /usr/bin/env python
"""
This script demonstrates detection and tracking of
Harris corners.
NOT COMPLETE
"""
import numpy as np
import cv2 as cv
# Load images and convert to greyscale
I1c = cv.imread("frame27.jpeg")
I1 = cv.cvtColor(I1c, cv.COLOR_BGR2GRAY)
I2c = cv.imread("frame28.jpeg")
I2 = cv.cvtColor(I2c, cv.COLOR_BGR2GRAY)
# Settings for the Sobel filter
scale = 1
delta = 0
ddepth = cv.CV_16S
# Calculate Derivatives
It = I2 - I1
Ix = cv.Sobel(I1, ddepth, 1, 0, ksize=3, scale=scale, delta=delta, borderType=cv.BORDER_DEFAULT)
Iy = cv.Sobel(I1, ddepth, 0, 1, ksize=3, scale=scale, delta=delta, borderType=cv.BORDER_DEFAULT)
Ix = cv.convertScaleAbs(Ix)
Iy = cv.convertScaleAbs(Iy)
# Debug Output (image file)
test = cv.addWeighted(Ix, 0.5, Iy, 0.5, 0)
cv.imwrite("sobeledges.jpeg",test)
# Harris Corners - dst is the Harris heuristic for each pixel
# TODO: Look up and tune parameters
dst = cv.cornerHarris(I1,2,3,0.04)
# Debug Output (image file)
harris = I1c.copy()
harris[dst>0.01*dst.max()]=[0,0,255]
cv.imwrite("harris.jpeg",harris)
def filterFP(l,r=36):
"""
Given a list l=[(h,x,y)] of corners (x,y) with Harris strength h,
return a new list of such points by removing points with squared
distance less than r from a point with greater strength.
"""
if l == []: return l
else:
(h0,x0,y0) = l[-1]
l0 = [ (h,x,y) for (h,x,y) in l[:-1] if ((x-x0)**2+(y-y0)**2 > r) ]
l1 = filterFP(l0,r)
l1.append(l[-1])
return l1
# Get sorted list of Harris Corners with strength
fpt = dst>0.01*dst.max()
fpt = np.transpose(fpt.nonzero())
fplist = [ (dst[x,y,],x,y) for (x,y) in list(fpt) ]
fplist.sort()
fplist = filterFP(fplist)
# Debug Output (image file)
harris = I1c.copy()
fpl = [ (x,y) for (h,x,y) in fplist ]
for i in fpl:
harris[i]=[0,0,255]
cv.imwrite("harris-filtered.jpeg",harris)
# Element-wise products
Ixx = Ix*Ix
Ixy = Ix*Iy
Iyy = Iy*Iy
Ixt = Ix*It
Iyt = Iy*It
# Good to check if the shapes are the same here. It depends on boundary conditions when filtering.
print(I1.shape)
print(It.shape)
print(Ix.shape)
print(Ixt.shape)
print(Ixx.shape)
# Calculate the G matrix and b vector for Algoritm 4.1
# - we consider only the very strongest feature point
(h,x,y) = fplist[-1]
print( f"({x},{y}) has strength {h}" )
# - make the window
wsize = 5
ws = int(np.floor(wsize/2))
mask = np.zeros((I1.shape),dtype=bool)
mask[x-ws:x+ws+1,y-ws:y+ws+1] = True
# - calculate G and b
G = np.array( [ [ Ixx[mask].sum(), Ixy[mask].sum() ],
[ Ixy[mask].sum(), Iyy[mask].sum() ] ] )
b = np.array( [ Ixt[mask].sum(), Iyt[mask].sum() ] )
print( f"G = {G}" )
print( f"b = {b}" )
# Motion estimate in best feature
Ginv = np.linalg.inv(G)
u = - Ginv @ b.transpose()
print( f"G inverse {Ginv}" )
print( f"Motion vector u is {u}" )
# TODO: validate
# Draw motion vector
pos0 = np.array([x,y],dtype=int)
pos1 = np.round(pos0 + 25*u).astype(int)
print ( f"{pos0} -> {pos1}" )
colour = (0, 255, 0)
thickness = 1
# NOTE: OpenCV writes the horizontal co-ordinate first
test = cv.arrowedLine(harris, (y,x), (pos1[1],pos1[0]), colour, thickness)
test[x,y] = (0,0,255)
cv.imwrite("motion.jpeg",test)