Skip to content

Instantly share code, notes, and snippets.

@PeterSprague
Last active January 10, 2024 13:23
Show Gist options
  • Save PeterSprague/68bc55e162cdd2fe80139499dd30402d to your computer and use it in GitHub Desktop.
Save PeterSprague/68bc55e162cdd2fe80139499dd30402d to your computer and use it in GitHub Desktop.
Function to create a RGNIR image from RGB & NIR images, then align the NIR channel to Red channel
def generate_RGNIR_image(iterations,acc):
import cv2
import numpy as np
# assumes images are exactly the same size
# safe in this case, but could include a test and/or a resize
RGB_image_bgr = cv2.imread(RGB_src_img_path)
#print('RGB src image shape: ', RGB_image_bgr.shape)
NIR_image_bgr = cv2.imread(NIR_src_img_path)
#print('NIR src image shape: ', NIR_image_bgr.shape)
# Get the individual colour components of the images
# NIR camera only uses 'Red' channel
# break out the colour channels
(B, G, R) = cv2.split(RGB_image_bgr)
(BNIR, GNIR, RNIR) = cv2.split(NIR_image_bgr)
# merge to form RGNIR image
RGNIR_src_img_bgr = cv2.merge((RNIR,G,R))
#print('RGNIR src image shape: ', RGNIR_src_img_bgr.shape)
# aligning new RGNIR NIR channel to Red channel
# https://docs.opencv.org/3.4.4/dc/d6b/group__video__track.html#ga7ded46f9a55c0364c92ccd2019d43e3a
# https://www.learnopencv.com/image-alignment-ecc-in-opencv-c-python/
# not used
def get_gradient(im) :
# Calculate the x and y gradients using Sobel operator
grad_x = cv2.Sobel(im,cv2.CV_32F,1,0,ksize=3)
grad_y = cv2.Sobel(im,cv2.CV_32F,0,1,ksize=3)
# Combine the two gradients
grad = cv2.addWeighted(np.absolute(grad_x), 0.5, np.absolute(grad_y), 0.5, 0)
return grad
im_colour = RGNIR_src_img_bgr
# Find the width and height
sz = im_colour.shape
height = sz[0];
width = sz[1]
#print('im_colour.shape: ',sz)
# create np array to build aligned image in
im_aligned = np.zeros((height,width,3), dtype=np.uint8)
#print('im_aligned.shape: ',im_aligned.shape)
# copy red & green channels into
im_aligned[:,:,2] = R
im_aligned[:,:,1] = G
# Define motion model
warp_mode = cv2.MOTION_HOMOGRAPHY
# Set the warp matrix to identity.
if warp_mode == cv2.MOTION_HOMOGRAPHY :
warp_matrix = np.eye(3, 3, dtype=np.float32)
else :
warp_matrix = np.eye(2, 3, dtype=np.float32)
# Set the stopping criteria for the algorithm
# iterations = 500 #OpenCV default @50, tutorial @5000
# acc = 1e-8 #OpenCV default @0.001, tutorial @1e-10, => 1e-8
# tested w count = 50 --> 5000 & acc = 1e-3, minimal time to compute difference
# original parameters
#criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 5000, 1e-10)
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, iterations, acc)
# Warp the RNIR (blue) channel to the red channel
# removed original use of channel gradient -->
# aligns correctly with 500 iterations/acc=1e-8 if image/channel is ~=<1sec @ 4m/s different
for i in range(0,1) :
print('warping channel(s) against Red')
(cc, warp_matrix) = cv2.findTransformECC (im_colour[:,:,2],
im_colour[:,:,i],
warp_matrix,
warp_mode, criteria)
if warp_mode == cv2.MOTION_HOMOGRAPHY :
# Use Perspective warp when the transformation is a Homography
im_aligned[:,:,i] = cv2.warpPerspective (im_colour[:,:,i],
warp_matrix,
(width,height),
flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)
else :
# Use Affine warp when the transformation is not a Homography
im_aligned[:,:,i] = cv2.warpAffine(im_colour[:,:,i],
warp_matrix,
(width, height),
flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP);
print('warp matrix: ',warp_matrix)
# Show final output
#cv2.imshow("Colour Image", im_colour)
#cv2.imshow("Aligned Image", im_aligned)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
return im_aligned
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment