micasense / imageprocessing

MicaSense RedEdge and Altum image processing tutorials
https://www.micasense.com
MIT License
247 stars 148 forks source link

Alignment for a whole directory #165

Open sgtkellox opened 2 years ago

sgtkellox commented 2 years ago

I used your code to make some alignments and I like the result, yet I found it a bit inconvenient that you have to process the images one by one. I made some changes to process directorys of images, it works fine. Shall I submitt the code to you? Regards, Felix

poynting commented 2 years ago

Have you seen the Batch Processing notebook?

On Thu, Aug 12, 2021, 10:56 AM sgtkellox @.***> wrote:

I used your code to make some alignments and I like the result, yet I found it a bit inconvenient that you have to process the images one by one. I made some changes to process directorys of images, it works fine. Shall I submitt the code to you? Regards, Felix

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/micasense/imageprocessing/issues/165, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABSNZUYWPU2VPQZKO57WJYTT4QDMNANCNFSM5CBZNCBQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

XingWei19 commented 2 years ago

I used your code to make some alignments and I like the result, yet I found it a bit inconvenient that you have to process the images one by one. I made some changes to process directorys of images, it works fine. Shall I submitt the code to you? Regards, Felix

Hello Felix, I am working on batch processing RedEdge 5-band images. I would like to test your codes if you are willing to share them. Thanks, Xing

sgtkellox commented 2 years ago

I will have a look at that notebook. @XingWei19 ill paste my code here so you can use it. Ill assume that is ok. Here you go, hope it helps:

import os, glob
import micasense.capture as capture
import cv2
import numpy as np
import matplotlib.pyplot as plt
import micasense.imageutils as imageutils
import micasense.plotutils as plotutils
import imageio

path = path goes here 

os.mkdir(os.path.join(path,"cir_aligned"))
os.mkdir(os.path.join(path,"rgb_aligned"))

files = os.listdir(path)
names = []
for fileName in files:
    if fileName.endswith(".tif"):
        name = fileName.split("_",2)
        if not name[0]+"_"+name[1] in names:
            names.append(name[0]+"_"+name[1])

for name in names:
    panelNames = None

    imagePath = os.path.join(path)
    imageNames = glob.glob(os.path.join(imagePath,name+'_*.tif'))

    if panelNames is not None:
        panelCap = capture.Capture.from_filelist(panelNames)
    else:
        panelCap = None

    cap = capture.Capture.from_filelist(imageNames)

    if panelCap is not None:
        if panelCap.panel_albedo() is not None:
            panel_reflectance_by_band = panelCap.panel_albedo()
        else:
            panel_reflectance_by_band = [0.67, 0.69, 0.68, 0.61, 0.67] #RedEdge band_index order
        panel_irradiance = panelCap.panel_irradiance(panel_reflectance_by_band)    
        img_type = "reflectance"
        cap.plot_undistorted_reflectance(panel_irradiance)
    else:
        if cap.dls_present():
            img_type='reflectance'
            cap.plot_undistorted_reflectance(cap.dls_irradiance())
        else:
            img_type = "radiance"
            cap.plot_undistorted_radiance()
    match_index = 1 # Index of the band 
    max_alignment_iterations = 10
    warp_mode = cv2.MOTION_HOMOGRAPHY
    pyramid_levels = 0 

    print("Alinging images. Depending on settings this can take from a few seconds to many minutes")

    warp_matrices, alignment_pairs = imageutils.align_capture(cap,ref_index = match_index,max_iterations = max_alignment_iterations,warp_mode = warp_mode,pyramid_levels = pyramid_levels)

    print("Finished Aligning, warp matrices={}".format(warp_matrices))

    cropped_dimensions, edges = imageutils.find_crop_bounds(cap, warp_matrices, warp_mode=warp_mode)
    im_aligned = imageutils.aligned_capture(cap, warp_matrices, warp_mode, cropped_dimensions, match_index, img_type=img_type)

    figsize=(16,13)   # use this size for export-sized display

    rgb_band_indices = [cap.band_names_lower().index('red'),
                    cap.band_names_lower().index('green'),
                    cap.band_names_lower().index('blue')]
    cir_band_indices = [cap.band_names_lower().index('nir'),
                    cap.band_names_lower().index('red'),
                    cap.band_names_lower().index('green')]

    im_display = np.zeros((im_aligned.shape[0],im_aligned.shape[1],im_aligned.shape[2]), dtype=np.float32 )

    im_min = np.percentile(im_aligned[:,:,rgb_band_indices].flatten(), 0.5)  # modify these percentiles to adjust contrast
    im_max = np.percentile(im_aligned[:,:,rgb_band_indices].flatten(), 99.5)  # for many images, 0.5 and 99.5 are good values

    for i in rgb_band_indices:
        im_display[:,:,i] =  imageutils.normalize(im_aligned[:,:,i], im_min, im_max)

    rgb = im_display[:,:,rgb_band_indices]

    for i in cir_band_indices:
        im_display[:,:,i] =  imageutils.normalize(im_aligned[:,:,i])

    cir = im_display[:,:,cir_band_indices]
    fig, axes = plt.subplots(1, 2, figsize=figsize)

    gaussian_rgb = cv2.GaussianBlur(rgb, (9,9), 10.0)
    gaussian_rgb[gaussian_rgb<0] = 0
    gaussian_rgb[gaussian_rgb>1] = 1
    unsharp_rgb = cv2.addWeighted(rgb, 1.5, gaussian_rgb, -0.5, 0)
    unsharp_rgb[unsharp_rgb<0] = 0
    unsharp_rgb[unsharp_rgb>1] = 1

    gamma = 1.4
    gamma_corr_rgb = unsharp_rgb**(1.0/gamma)
    fig = plt.figure(figsize=figsize)
    imtype = 'jpg' # or 'jpg'

    imageio.imwrite(os.path.join(path,"rgb_aligned",name+'rgb.'+imtype), (255*gamma_corr_rgb).astype('uint8'))
    imageio.imwrite(os.path.join(path,"cir_aligned",name+'cir.'+imtype), (255*cir).astype('uint8'))
poynting commented 2 years ago

It's not necessary to align each capture each time. It's much faster to use one image with good features to find an alignment matrix, then use that to align all of the images from the same capture session.

The batch processing notebook does this, using the output of the alignment notebook.

The 10-band Batch Processing notebook further improves this by using the imgset.save_stacks function which is internally multithreaded. The 10-band approach can also be used with 5-band or 6-band data.

XingWei19 commented 2 years ago

@sgtkellox Thank you for sharing your codes. I appreciate it.

XingWei19 commented 2 years ago

@poynting When I testing the 10-band Batch Processing notebook, I got an error saying, "ImageSet' object has no attribute 'save_stacks". Do I need to update the library/package to use this function? Thanks

karimelgazar commented 2 years ago

use imgset.process_imageset instead

zekrimohamed commented 2 years ago

@poynting When I tested the 10-band Batch Processing notebook, I got an error saying, "ImageSet' object has no attribute 'save_stacks". Do I need to update the library/package to use this function? Thanks

YY-99999 commented 2 years ago

Hi @poynting

I am having same issue "ImageSet' object has no attribute 'save_stacks". I have tried imgset.process_imageset and it seemed not working as well. Any ideas ? Many Thanks

alegent commented 1 year ago

I am having same errors on using both imgset.save_stacks() and imgset.process_imageset() . Any progress on this issue?