Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

decon() sometimes changes the size of image. #66

Open
ajan890 opened this issue Oct 4, 2024 · 1 comment
Open

decon() sometimes changes the size of image. #66

ajan890 opened this issue Oct 4, 2024 · 1 comment

Comments

@ajan890
Copy link

ajan890 commented Oct 4, 2024

Hi @tlambert03,

While testing my code, I noticed that sometimes the image (in this case, ndarrays loaded from .nrrd files) would change shape seemingly randomly. I am unsure about the cause of this and believe it is some sort of bug present in the library. I would appreciate it if you are able to give some pointers on how I can work around this issue.

Additionally, I noticed that the edges of the image are not being deconvolved. Correct me if I am wrong, but I think this is due to the nature of the algorithm, hence the padding before applying the deconvolution.

I have provided a snippet of my code, as well as some sample data in case you want to reproduce the error. You will have to extract the zip folder and provide the file paths as displayed in the main function.

Thank you!

sample_data.zip

import nrrd
from pathlib import Path
from numpy import pad
from pycudadecon import decon, make_otf

def process_cube(
        input_file: Path,   # path to nrrd file
        temp_folder: Path,  # path to a temporary folder (folder must exist before function runs)
        psf: str,           # string representing path to psf file
        pad_amount: int,    # amount to pad to each side of image before applying deconvolution
        n_iters: int = 9,
        dz_data: float = 0.7,
        dx_data: float = 0.7,
        dz_psf: float = 1.8,
        dxy_psf: float = 0.2,
        background: int = 0,
        wavelength_em: int = 525,
        na: float = 0.4,
        nimm: float = 1.42
): 
    # read input file
    img, header = nrrd.read(input_file.__str__())

    # generate otf file from psf file
    otf_file = make_otf(
            psf,
            outpath=(temp_folder / 'otf.tif').__str__(),
            dzpsf=dz_psf,
            dxpsf=dxy_psf,
            wavelength=wavelength_em,
            na=na,
            nimm=nimm,
            fixorigin=0,
        )

    print("Image shape before pad: ", img.shape)

    # pad to ensure edges of image are deconvolved
    img = pad(img, pad_amount, 'reflect')
    
    print("Image shape (after pad), before deconvolution: ", img.shape)

    # run deconvolution    
    img = decon(
        img,
        otf_file,
        fpattern=None,
        n_iters=n_iters,
        dzdata=dz_data,
        dxdata=dx_data,
        dzpsf=dz_psf,
        dxpsf=dxy_psf,
        background=background,
        wavelength=wavelength_em,
        na=na,
        nimm=nimm
    )
    print("Image shape after deconvolution: ", img.shape)
    
    # ... rest of code is irrelevant

if __name__ == '__main__':
    # change pad_amount to different integers.  sometimes the deconvolution causes image to change size.
    # .nrrd file along with psf.tif are provided as sample data.

    process_cube(
        Path("C:/path/to/file/y00006400.x00019200.nrrd"),
        Path("C:/path/to/temp/folder"),
        "C:/path/to/psf.tif",
        pad_amount=1
    )
@tlambert03
Copy link
Owner

Hi @ajan890 and thanks for your note, and the example code. Could you save me a bit of time and also paste the output that you're getting when you run that script? I'm specifically curious to see exactly what the shapes are.

I suspect the reason is that cudadecon pads the image to an efficient size for FFTs (which is one that can be factorized into 2s, 3s, 5s, and 7s as per CUFFT recs). It does that here:

https://github.com/scopetools/cudadecon/blob/a679bf4c2a7e2c7579ca47a7719d0e99ea72974a/src/RL-Biggs-Andrews.cpp#L18-L43

If it's really important for your application that the output be exactly the same size as the input, I think i would probably create one additional small function that simply pads or crops the result to the size of your input image (and if you wanted to contribute that here, i would be happy to discuss a PR)

Additionally, I noticed that the edges of the image are not being deconvolved. Correct me if I am wrong, but I think this is due to the nature of the algorithm, hence the padding before applying the deconvolution.

Indeed, deconvolution will always have some edge artifacts, and your strategy of padding a bit with reflection (and preferably chopping that off afterwards) is about as good of a strategy as any to try to get everything you can out of the edges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants