• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

j2kun / pmfp-code / 15749643688

19 Jun 2025 04:45AM UTC coverage: 99.046% (-0.05%) from 99.099%
15749643688

Pull #90

github

web-flow
Merge 4a7a02969 into 90d0954e7
Pull Request #90: build(deps): bump urllib3 from 2.3.0 to 2.5.0

1868 of 1886 relevant lines covered (99.05%)

0.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.45
/tips/image_alignment.py
1
import numpy as np
1✔
2

3

4
def max_index2d(arr):
1✔
5
    return np.unravel_index(np.argmax(arr), arr.shape)
1✔
6

7

8
def align_images(image1, image2):
1✔
9
    """Aligns two greyscale images using the discrete Fourier transform.
10

11
    Args:
12
        image1: A greyscale image.
13
        image2: A second greyscale image.
14

15
    Returns:
16
        A tuple containing the (row, column) pixel offset required to transform
17
        image2 to align with image1. The values of row are in the range [-N/2, N/2),
18
        where N is the number of rows in the image. A shift that would go
19
        beyond the bounds of the image is considered a cyclic shift. The same is true
20
        for the column shift and the image width.
21
    """
22
    # Apply window function to reduce edge effects. From Wikipedia
23
    # (https://en.wikipedia.org/wiki/Window_function): "Two-dimensional windows
24
    # are commonly used in image processing to reduce unwanted high-frequencies
25
    # in the image Fourier transform."
26
    #
27
    # There appears to be little practical difference between the "np.hanning"
28
    # and "np.hamming" window methods. "The Hamming window is 92% Hann window
29
    # and 8% rectangular window." (https://dsp.stackexchange.com/a/56408/1658).
30
    #
31
    # R. Hovden, Y. Jiang, H. Xin, L.F. Kourkoutis (2015). "Periodic Artifact
32
    # Reduction in Fourier Transforms of Full Field Atomic Resolution Images".
33
    # Microscopy and Microanalysis. 21 (2): 436–441. arXiv:2210.09024
34
    window = np.hamming(image1.shape[0])[:, None] * np.hamming(image1.shape[1])[None, :]
1✔
35
    image1_windowed = image1 * window
1✔
36
    image2_windowed = image2 * window
1✔
37

38
    # Use double precision for FFT operations
39
    f1 = np.fft.fft2(image1_windowed).astype(np.complex128)
1✔
40
    f2 = np.fft.fft2(image2_windowed).astype(np.complex128)
1✔
41

42
    # Normalize cross-power spectrum with small epsilon to avoid division by zero
43
    eps = 1e-15
1✔
44
    cross_power = (f1 * f2.conj()) / (np.abs(f1 * f2.conj()) + eps)
1✔
45

46
    correlation_sum = np.real(np.fft.ifft2(cross_power))
1✔
47
    correlation_sum = np.fft.fftshift(correlation_sum)
1✔
48

49
    # Find the peak location and value
50
    max_loc = max_index2d(correlation_sum)
1✔
51
    peak_value = correlation_sum[max_loc]
1✔
52

53
    # Calculate the mean and std of the correlation surface
54
    mean_correlation = np.mean(correlation_sum)
1✔
55
    std_correlation = np.std(correlation_sum)
1✔
56

57
    # If the peak is not significantly higher than the background, assume no shift
58
    if (peak_value - mean_correlation) < 3 * std_correlation:
1✔
59
        return 0, 0
×
60

61
    shape = np.array(image1.shape)
1✔
62
    shift = np.array([max_loc[0], max_loc[1]]) - shape // 2
1✔
63

64
    return shift[0], shift[1]
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc