def create_feed_dict(data_index): # create feed dict current_image_RGB = cv2.imread(imageNames_RGB[data_index]) current_image_Red = cv2.imread(imageNames_Red[data_index]) current_image_NIR = cv2.imread(imageNames_NIR[data_index]) current_image_Red_Edge = cv2.imread(imageNames_Red_Edge[data_index]) current_image_Green = cv2.imread(imageNames_Green[data_index]) current_image_green, _, _ = cv2.split(current_image_Green) current_image_red, _, _ = cv2.split(current_image_Red) current_image_nir, _, _ = cv2.split(current_image_NIR) current_image_red_edge,_, _ = cv2.split(current_image_Red_Edge) channel_marge = cv2.merge([current_image_red, current_image_nir, current_image_red_edge]) channel_6 = np.concatenate((channel_marge, current_image_RGB), axis=2) ndvi = (current_image_nir - current_image_red) / (current_image_nir + current_image_red) VIgreen = (current_image_green - current_image_red) / (current_image_green + current_image_red) gndvi = (current_image_nir - current_image_green) / (current_image_nir + current_image_green) ndre = (current_image_nir - current_image_red_edge) / (current_image_nir + current_image_red_edge) savi = ((current_image_nir - current_image_red) / (current_image_nir + current_image_red) + 0.5) * 1.5 data_index = str(data_index) masked_ndvi = np.ma.masked_outside(ndvi, 0.45, 1.2) fig, axis = plotutils.plotwithcolorbar(masked_ndvi, 'ndvi', figsize=figsize) plt.draw() fig.savefig(Training_path + data_index + '_ndvi.png') plt.close(fig) masked_vigreen = np.ma.masked_outside(VIgreen, 0.0, 0.2) fig, axis = plotutils.plotwithcolorbar(masked_vigreen, 'vi_green', figsize=figsize) plt.draw() fig.savefig(Training_path + data_index + '_vigreen.png') plt.close(fig) masked_gndvi = np.ma.masked_outside(gndvi, -1, 1) fig, axis = plotutils.plotwithcolorbar(masked_gndvi, 'gndvi', figsize=figsize) plt.draw() fig.savefig(Training_path + data_index + '_gndvi.png') plt.close(fig) masked_ndre = np.ma.masked_outside(ndre, -1, 1) fig, axis = plotutils.plotwithcolorbar(masked_ndre, 'ndre', figsize=figsize) plt.draw() fig.savefig(Training_path + data_index + '_ndre.png') plt.close(fig) masked_savi = np.ma.masked_outside(savi, -1, 1) fig, axis = plotutils.plotwithcolorbar(masked_savi, 'savi', figsize=figsize) plt.draw() fig.savefig(Training_path + data_index + '_savi.png') plt.close(fig)
def plot_raw(self, title=None, figsize=None): ''' Create a single plot of the raw image ''' if title is None: title = '{} Band {} Raw DN'.format(self.band_name, self.band_index) return plotutils.plotwithcolorbar(self.raw(), title=title, figsize=figsize)
def plot_undistorted_radiance(self, title=None, figsize=None): ''' Create a single plot of the undistorted radiance ''' if title is None: title = '{} Band {} Undistorted Radiance'.format( self.band_name, self.band_index) return plotutils.plotwithcolorbar(self.undistorted(self.radiance()), title=title, figsize=figsize)
def plot_vignette(self, title=None, figsize=None): ''' Create a single plot of the vignette ''' if title is None: title = '{} Band {} Vignette'.format(self.band_name, self.band_index) return plotutils.plotwithcolorbar(self.plottable_vignette(), title=title, figsize=figsize)
def plot_radiance(self, title=None, figsize=None): ''' Create a single plot of the image converted to radiance ''' if title is None: title = '{} Band {} Radiance'.format(self.band_name, self.band_index) return plotutils.plotwithcolorbar(self.radiance(), title=title, figsize=figsize)
def plot_intensity(self, title=None, figsize=None): ''' Create a single plot of the image converted to uncalibrated intensity ''' if title is None: title = '{} Band {} Intensity (DN*sec)'.format( self.band_name, self.band_index) return plotutils.plotwithcolorbar(self.intensity(), title=title, figsize=figsize)
def align(pair): """ Determine an alignment matrix between two images @input: Dictionary of the following form: { 'warp_mode': cv2.MOTION_* (MOTION_AFFINE, MOTION_HOMOGRAPHY) 'max_iterations': Maximum number of solver iterations 'epsilon_threshold': Solver stopping threshold 'ref_index': index of reference image 'match_index': index of image to match to reference } @returns: Dictionary of the following form: { 'ref_index': index of reference image 'match_index': index of image to match to reference 'warp_matrix': transformation matrix to use to map match image to reference image frame } Major props to Alexander Reynolds ( https://stackoverflow.com/users/5087436/alexander-reynolds ) for his insight into the pyramided matching process found at https://stackoverflow.com/questions/45997891/cv2-motion-euclidean-for-the-warp-mode-in-ecc-image-alignment-method """ warp_mode = pair['warp_mode'] max_iterations = pair['max_iterations'] epsilon_threshold = pair['epsilon_threshold'] ref_index = pair['ref_index'] match_index = pair['match_index'] translations = pair['translations'] # Initialize the matrix to identity if warp_mode == cv2.MOTION_HOMOGRAPHY: warp_matrix = np.array( [[1, 0, translations[1]], [0, 1, translations[0]], [0, 0, 1]], dtype=np.float32) else: # warp_matrix = np.array([[1,0,0],[0,1,0]], dtype=np.float32) warp_matrix = np.array( [[1, 0, translations[1]], [0, 1, translations[0]]], dtype=np.float32) w = pair['ref_image'].shape[1] nol = int(w / (1280 / 3)) - 1 print("number of pyramid levels: {}".format(nol)) warp_matrix[0][2] /= (2**nol) warp_matrix[1][2] /= (2**nol) if ref_index != match_index: show_debug_images = pair['debug'] # construct grayscale pyramid gray1 = pair['ref_image'] gray2 = pair['match_image'] if gray2.shape[0] < gray1.shape[0]: cv2.resize(gray2, None, fx=gray1.shape[0] / gray2.shape[0], fy=gray1.shape[0] / gray2.shape[0], interpolation=cv2.INTER_AREA) gray1_pyr = [gray1] gray2_pyr = [gray2] for level in range(nol): gray1_pyr[0] = gaussian(normalize(gray1_pyr[0])) gray1_pyr.insert( 0, cv2.resize(gray1_pyr[0], None, fx=1 / 2, fy=1 / 2, interpolation=cv2.INTER_AREA)) gray2_pyr[0] = gaussian(normalize(gray2_pyr[0])) gray2_pyr.insert( 0, cv2.resize(gray2_pyr[0], None, fx=1 / 2, fy=1 / 2, interpolation=cv2.INTER_AREA)) # Terminate the optimizer if either the max iterations or the threshold are reached criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, max_iterations, epsilon_threshold) # run pyramid ECC for level in range(nol + 1): grad1 = gradient(gray1_pyr[level]) grad2 = gradient(gray2_pyr[level]) if show_debug_images: import micasense.plotutils as plotutils plotutils.plotwithcolorbar(gray1_pyr[level], "ref level {}".format(level)) plotutils.plotwithcolorbar(gray2_pyr[level], "match level {}".format(level)) plotutils.plotwithcolorbar(grad1, "ref grad level {}".format(level)) plotutils.plotwithcolorbar(grad2, "match grad level {}".format(level)) print("Starting warp for level {} is:\n {}".format( level, warp_matrix)) cc, warp_matrix = cv2.findTransformECC(grad1, grad2, warp_matrix, warp_mode, criteria, inputMask=None, gaussFiltSize=1) if show_debug_images: print("Warp after alignment level {} is \n{}".format( level, warp_matrix)) if level != nol: # scale up only the offset by a factor of 2 for the next (larger image) pyramid level if warp_mode == cv2.MOTION_HOMOGRAPHY: warp_matrix = warp_matrix * np.array( [[1, 1, 2], [1, 1, 2], [0.5, 0.5, 1]], dtype=np.float32) else: warp_matrix = warp_matrix * np.array( [[1, 1, 2], [1, 1, 2]], dtype=np.float32) return { 'ref_index': pair['ref_index'], 'match_index': pair['match_index'], 'warp_matrix': warp_matrix }
def align(pair): """ Determine an alignment matrix between two images @input: Dictionary of the following form: { 'warp_mode': cv2.MOTION_* (MOTION_AFFINE, MOTION_HOMOGRAPHY) 'max_iterations': Maximum number of solver iterations 'epsilon_threshold': Solver stopping threshold 'ref_index': index of reference image 'match_index': index of image to match to reference } @returns: Dictionary of the following form: { 'ref_index': index of reference image 'match_index': index of image to match to reference 'warp_matrix': transformation matrix to use to map match image to reference image frame } Major props to Alexander Reynolds ( https://stackoverflow.com/users/5087436/alexander-reynolds ) for his insight into the pyramided matching process found at https://stackoverflow.com/questions/45997891/cv2-motion-euclidean-for-the-warp-mode-in-ecc-image-alignment-method """ warp_mode = pair['warp_mode'] max_iterations = pair['max_iterations'] epsilon_threshold = pair['epsilon_threshold'] ref_index = pair['ref_index'] match_index = pair['match_index'] translations = pair['translations'] close_range = pair['close_range'] # Initialize the matrix to identity if warp_mode == cv2.MOTION_HOMOGRAPHY: # warp_matrix = np.array([[1,0,0],[0,1,0],[0,0,1]], dtype=np.float32) warp_matrix = pair['warp_matrix_init'] else: # warp_matrix = np.array([[1,0,0],[0,1,0]], dtype=np.float32) warp_matrix = np.array( [[1, 0, translations[1]], [0, 1, translations[0]]], dtype=np.float32) w = pair['ref_image'].shape[1] if pair['pyramid_levels'] is None: nol = int(w / (1280 / 3)) - 1 else: nol = pair['pyramid_levels'] if pair['debug']: print("number of pyramid levels: {}".format(nol)) warp_matrix[0][2] /= (2**nol) warp_matrix[1][2] /= (2**nol) if close_range: matrix_box = np.zeros((3, 3, 5), dtype=np.float32) matrix_box[:, :, 0] = np.array( [[1.01990501e+00, 6.60780396e-02, 1.61565981e+01], [1.02941529e-02, 1.04839095e+00, -5.93324724e+01], [-2.39299405e-06, 6.57833196e-05, 1.00000000e+00]], dtype=np.float32) matrix_box[:, :, 1] = np.array( [[9.64607505e-01, -5.80503997e-04, -1.90982485e+00], [-1.75293196e-02, 9.55154457e-01, -2.94900879e+01], [-4.10977951e-05, -2.78523751e-06, 1.00000000e+00]], dtype=np.float32) matrix_box[:, :, 3] = np.array( [[1.06259853e+00, 7.81775979e-02, 1.45072993e+01], [1.99893573e-02, 1.10691304e+00, -4.95636256e+01], [3.31475328e-05, 8.63813674e-05, 1.00000000e+00]], dtype=np.float32) matrix_box[:, :, 4] = np.array( [[1.00576555e+00, 3.10690919e-02, 5.54705923e+00], [4.39865262e-03, 1.02901756e+00, -2.45425948e+01], [-1.34695946e-05, 4.22982177e-05, 1.00000000e+00]], dtype=np.float32) warp_matrix = matrix_box[:, :, match_index] # if close_range: # matrix_box = np.zeros((3, 3, 5), dtype=np.float32) # matrix_box[:,:,0] = np.array([[ 9.85234288e-01, -6.02857058e-02, -1.97861800e+01], # [-9.13546319e-03, 9.54160086e-01, 5.71365581e+01], # [ 3.68473019e-06, -6.25908142e-05, 1.00000000e+00]], dtype=np.float32) # matrix_box[:,:,1] = np.array([[1.03681022e+00, 7.94539658e-04, 1.94929221e+00], # [2.05548527e-02, 1.04714741e+00, 3.08336762e+01], # [4.27748983e-05, 3.30673535e-06, 1.00000000e+00]], dtype=np.float32) # matrix_box[:,:,3] = np.array([[ 9.45799261e-01, -6.47190144e-02, -1.73228004e+01], # [-1.90123138e-02, 9.04237787e-01, 4.54668636e+01], # [-3.06740010e-05, -7.49444305e-05, 1.00000000e+00]], dtype=np.float32) # matrix_box[:,:,4] = np.array([[ 9.95893056e-01, -2.93410233e-02, -6.50957883e+00], # [-3.86456817e-03, 9.72735207e-01, 2.37574987e+01], # [ 1.36621685e-05, -4.07031605e-05, 1.00000000e+00]], dtype=np.float32) # warp_matrix = matrix_box[:,:, match_index] if ref_index != match_index: show_debug_images = pair['debug'] # construct grayscale pyramid gray1 = pair['ref_image'] gray2 = pair['match_image'] if gray2.shape[0] < gray1.shape[0]: cv2.resize(gray2, None, fx=gray1.shape[0] / gray2.shape[0], fy=gray1.shape[0] / gray2.shape[0], interpolation=cv2.INTER_AREA) gray1_pyr = [gray1] gray2_pyr = [gray2] for level in range(nol): gray1_pyr[0] = gaussian(normalize(gray1_pyr[0])) gray1_pyr.insert( 0, cv2.resize(gray1_pyr[0], None, fx=1 / 2, fy=1 / 2, interpolation=cv2.INTER_AREA)) gray2_pyr[0] = gaussian(normalize(gray2_pyr[0])) gray2_pyr.insert( 0, cv2.resize(gray2_pyr[0], None, fx=1 / 2, fy=1 / 2, interpolation=cv2.INTER_AREA)) # Terminate the optimizer if either the max iterations or the threshold are reached criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, max_iterations, epsilon_threshold) # run pyramid ECC for level in range(nol + 1): grad1 = gradient(gray1_pyr[level]) grad2 = gradient(gray2_pyr[level]) if show_debug_images: import micasense.plotutils as plotutils plotutils.plotwithcolorbar(gray1_pyr[level], "ref level {}".format(level)) plotutils.plotwithcolorbar(gray2_pyr[level], "match level {}".format(level)) plotutils.plotwithcolorbar(grad1, "ref grad level {}".format(level)) plotutils.plotwithcolorbar(grad2, "match grad level {}".format(level)) print("Starting warp for level {} is:\n {}".format( level, warp_matrix)) # cc, warp_matrix = cv2.findTransformECC(grad1, grad2, warp_matrix, warp_mode, criteria) # print("image correlation = {:4.2f}".format(cc)) if show_debug_images: print("Warp after alignment level {} is \n{}".format( level, warp_matrix)) if level != nol: # scale up only the offset by a factor of 2 for the next (larger image) pyramid level if warp_mode == cv2.MOTION_HOMOGRAPHY: warp_matrix = warp_matrix * np.array( [[1, 1, 2], [1, 1, 2], [0.5, 0.5, 1]], dtype=np.float32) else: warp_matrix = warp_matrix * np.array( [[1, 1, 2], [1, 1, 2]], dtype=np.float32) return { 'ref_index': pair['ref_index'], 'match_index': pair['match_index'], 'warp_matrix': warp_matrix }
############################################################################## #Calculate Radiance to Reflectance Conversion for Each Band using the Calibration Panel Images #Need to perform manually for each band because masked panel area shifts #PREFLIGHT CALIBRATION IMAGES ############## #Band 1 (Blue) #Plotting imageName = os.path.join(CalibrationFolder_preflight, 'IMG_0002_1.tif') imageRaw = plt.imread( imageName).T # Read raw image DN values - 16 bit tif only plt.imshow(imageRaw.T, cmap='gray') plotutils.colormap('viridis') # Optional: pick a color map: 'gray, viridis, plasma, inferno, magma, nipy_spectral' fig = plotutils.plotwithcolorbar(imageRaw.T, title='Raw image values with colorbar') #Image metadata meta = metadata.Metadata(imageName, exiftoolPath=exiftoolPath) bandName = meta.get_item('XMP:BandName') #Converting raw images to Radiance radianceImage, L, V, R = msutils.raw_image_to_radiance(meta, imageRaw.T) plotutils.plotwithcolorbar(V, 'Vignette Factor') plotutils.plotwithcolorbar(R, 'Row Gradient Factor') plotutils.plotwithcolorbar(V * R, 'Combined Corrections') plotutils.plotwithcolorbar(L, 'Vignette and row gradient corrected raw values') plotutils.plotwithcolorbar(radianceImage, 'All factors applied and scaled to radiance') #Mask to panel and calculate radiance
import micasense.metadata as metadata sys.path.append('C:/Users/Isaac Miller/Documents/GitHub/imageprocessing') exiftoolPath = None if os.name == 'nt': exiftoolPath = 'C:/exiftool/exiftool.exe' # get calibration panelPath = os.path.join('.', 'data', '0000SET', '000') panelName = glob.glob(os.path.join(panelPath, 'IMG_0000_1.tif'))[0] panelRaw = plt.imread(panelName) panelMeta = metadata.Metadata(panelName, exiftoolPath=exiftoolPath) radianceImage, L, V, R = msutils.raw_image_to_radiance(panelMeta, panelRaw) plotutils.plotwithcolorbar(V, 'Vignette Factor') plotutils.plotwithcolorbar(R, 'Row Gradient Factor') plotutils.plotwithcolorbar(V * R, 'Combined Corrections') plotutils.plotwithcolorbar(L, 'Vignette and row gradient corrected raw values') plotutils.plotwithcolorbar(radianceImage, 'All factors applied and scaled to radiance') markedImg = radianceImage.copy() ulx = 660 # upper left column (x coordinate) of panel area uly = 490 # upper left row (y coordinate) of panel area lrx = 840 # lower right column (x coordinate) of panel area lry = 670 # lower right row (y coordinate) of panel area cv2.rectangle(markedImg, (ulx, uly), (lrx, lry), (0, 255, 0), 3) # Our panel calibration by band (from MicaSense for our specific panel) panelCalibration = { "Blue": 0.67,
"Blue": 0.66, "Green": 0.67, "Red": 0.67, "Red edge": 0.66, "NIR": 0.6 } # Select panel region from radiance image print( 'Mean Radiance in panel region: {:1.3f} W/m^2/nm/sr'.format(meanRadiance)) panelReflectance = panelCalibration[bandName] radianceToReflectance = panelReflectance / meanRadiance print('Radiance to reflectance conversion factor: {:1.5f}'.format( radianceToReflectance)) reflectanceImage = radianceImage * radianceToReflectance plotutils.plotwithcolorbar(reflectanceImage, 'Converted Reflectane Image') # ulx = int(numpy.min([nw_x,sw_x,ne_x,se_x])*1.2) # lrx = int(numpy.max([nw_x,sw_x,ne_x,se_x])*0.8) # uly = int(numpy.min([nw_y,sw_y,ne_y,se_y])*1.2) # lry = int(numpy.max([nw_y,sw_y,ne_y,se_y])*0.8) # markedImg = reflectanceImage.copy() # cv2.rectangle(markedImg,(ulx,uly),(lrx,lry),(0,255,0),3) # panelRegionRefl = reflectanceImage[uly:lry, ulx:lrx] # panelRegionReflBlur = cv2.GaussianBlur(panelRegionRefl,(55,55),5) # plotutils.plotwithcolorbar(panelRegionReflBlur, 'Smoothed panel region in reflectance image') # print('Min Reflectance in panel region: {:1.2f}'.format(panelRegionRefl.min())) # print('Max Reflectance in panel region: {:1.2f}'.format(panelRegionRefl.max())) # print('Mean Reflectance in panel region: {:1.2f}'.format(panelRegionRefl.mean())) # print('Standard deviation in region: {:1.4f}'.format(panelRegionRefl.std()))