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

Odd Behavior with Registration of Self-Same Image #47

Closed
ajamsellem opened this issue May 15, 2023 · 15 comments
Closed

Odd Behavior with Registration of Self-Same Image #47

ajamsellem opened this issue May 15, 2023 · 15 comments

Comments

@ajamsellem
Copy link

I am working on a toy case using chi2_shift where I divide an image into squares N (label them 1,2,3...N) of some given size (in square pixels) and then use chi2_shift to find the shift between 1 and itself, 2 and itself, etc.

Presumably, each of these should return a shift of zero, but I have spotted some odd behavior when histograming these N shifts (which I would expect to give me a well-behaved distribution around zero). For all square sizes, there seem to be some systematically non-zero shift. As the square size gets smaller (e.g. the 25^2 pixel case), the number of shifts that are systematically offset from zero grows. Yet, the size of this systematic offset from zero grows as I increase the size of the squares (see images below – they are in RA/DEC but I have seen the same effect when plotting in raw pixels).

Why does changing the size of these squares cause this systematic effect?

25^2 pixels
square25_edge100
50^2 pixels
square50_edge100
100^2 pixels
square100_edge200
150^2 pixels
square150_edge200
200^2 pixels
square200_edge200

@keflavich
Copy link
Owner

Could you share a reproducible example?

I don't know what's going on here, but I suspect small number statistics and/or an edge effect, especially if this is something that becomes more prominent for smaller images.

I'd also recommend doing tests in pixel space first to separate out the cross-correlation step from the coordinate conversion step.

@ajamsellem
Copy link
Author

ajamsellem commented May 16, 2023

Below is a reproducible example for square size of 25, 50, 100, 150, and 200. I've attached the image array as a csv file along with the histogram outputs. It seems that now the systematic offset does not change linearly with square size, but the number of systematically offset shifts still gets larger with smaller images. I guess there is some regime of image size where chi2_shifts just doesn't really work well?

import numpy as np
import matplotlib.pyplot as plt
from image_registration import chi2_shifts

issue_dir = "[redacted]/py_scripts/shift_functions/github_image_registraiton_issue47/"
save_file = issue_dir + "galaxy_img.csv"
gal_img = np.genfromtxt(save_file, delimiter=",")

square_sizes = [200, 150, 100, 50, 25]
xrange, yrange = gal_img.shape

for sq_sz in square_sizes:
    x_shifts = []
    y_shifts = []
    x_steps = xrange // sq_sz
    y_steps = yrange // sq_sz

    for x_count in range(0, x_steps):
        for y_count in range(0, y_steps):
            square = gal_img[
                y_count * sq_sz : y_count * sq_sz + sq_sz,
                x_count * sq_sz : x_count * sq_sz + sq_sz,
            ]

            dx, dy, __, __ = chi2_shifts.chi2_shift(
                square, square, upsample_factor="auto"
            )
            x_shifts.append(dx)
            y_shifts.append(dy)

    plt.figure()
    ax1 = plt.subplot(1, 2, 1)
    ax2 = plt.subplot(1, 2, 2)
    ax1.hist(x_shifts, bins=100)
    ax1.set_title("X Shifts")
    ax1.set_xlabel("Pixels")
    ax2.hist(y_shifts, bins=100)
    ax2.set_title("Y Shifts")
    ax2.set_xlabel("Pixels")
    # plt.savefig(f"{issue_dir}Square_size_{sq_sz}.pdf", dpi=300, facecolor="white")
    plt.show()

CSV file link: https://drive.google.com/file/d/13LdDPMuv0wUVPZ3NI_0wPfHRSaoD17rh/view?usp=sharing
Square_size_25.pdf
Square_size_50.pdf
Square_size_100.pdf
Square_size_150.pdf
Square_size_200.pdf

@ajamsellem
Copy link
Author

@keflavich, just wanted to make sure my response above didn't slip through. Also, if the example isn't sufficient, please let me know.

@keflavich
Copy link
Owner

yep, sorry, I lost track of this. It looks like a pixel indexing error at first glance.

@keflavich
Copy link
Owner

It looks like even-sized images behave well, but odd-sized images are getting a half-pixel offset.

@ajamsellem
Copy link
Author

But the only odd-sized one is 25x25. The others (which are all even) also have the offset. The offset is just smaller.

@keflavich
Copy link
Owner

yes, but I think the offset is only significant in that first case; in the other cases, it's a (different) rounding error

@ajamsellem
Copy link
Author

ajamsellem commented Jun 15, 2023

I just ran the above code again with odd sizes of 75x75 and 125x125, and they are both on the order of 0.1 pixel error, so that seems right.

Square_size_75.pdf
Square_size_125.pdf

@keflavich
Copy link
Owner

I see a consistent systematic error of 0.0039 pixels, which is 1/256, i.e., 1/zoomfactor/2. So there's an indexing error in the zoom code. I have a fix in prep

@keflavich
Copy link
Owner

ok I've fixed the 0.5-pixel offset, but the other one is more subtle and may not be solvable; technically the accuracy of this algorithm is limited to 1 pixel in the zoomed-in frame, and that becomes +/-0.5 pixels. It might be best to advise in the docs that the uncertainty is never better than 1/usfac, but basically you should consider these 1/usfac offsets to be the algorithmic limit.

@ajamsellem
Copy link
Author

So if I want to improve the accuracy beyond 0.5 pixels, I'll have to increase the upsample factor. I had been using upsample_factor = "auto". Is there any issue with increasing this parameter (beyond slowing things down)?

Also, I think the docs already say that 1/usfac is the best accuracy. But it might be good to make it clear that the imprecision/offset may (or at least can) be systematic like in this case.

@keflavich
Copy link
Owner

usfac='auto' will usually do much better than 0.5 pixels in the input frame. The accuracy is always limited to +/-0.5 pixels in the upsampled frame - but that is usfac smaller than in the input frame. You can use verbose=True to see what automated usfac is adopted. I saw factors of 128 when I ran some of your examples.

Yes, the main cost for a higher upsample factor is time - but it can get pretty steep; I think it scales as either N log N (if FFT is the limiting factor) or as N^2 if there is another limiting factor. I'm not sure which dominates for any given calculation.

@keflavich
Copy link
Owner

I expanded the documentation.

@keflavich
Copy link
Owner

see #48

@ajamsellem
Copy link
Author

Got it. Thanks for the clarifications. They were helpful!

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