📜 Welcome Back, Visioneer¶

Having successfully passed through Gate 1: The Chamber of Singular Truths, you have proven your mastery of decomposition and reconstruction. The Grand Archivist nods approvingly:

"Well done, apprentice. You have learned to see the essential from the chaotic. Now you face Gate 2, where you must combine purification, detection, and recognition to unlock ancient secrets."

But the Archivist's warning echoes still: "Beware. Those who attempt to pass with borrowed visions or false answers are cursed. Only true effort and understanding unlock the path forward."

🌀 Gate 2: Mosaic of Whispers¶

Theme: Image Denoising, Harris Corner Detection, Feature Matching

In the Gallery of Fragmented Memories, you find a beautiful Byzantine mosaic showing portraits of an ancient philosopher. As you admire it, Professor Dhoom Ketu steps out from the shadows, his wild hair floating and eyes full of mischief.

“Ah! The Mosaic of the Hidden Philosopher!” he says with a grin, handing you the preserved portrait. “This is your reference key.”

Suddenly, the Curse of Temporal Decay strikes—the rest of the mosaic is corrupted with noise and distortions. Professor Ketu sighs, “The curse again! Luckily, I saved the original before it was damaged. Now you can use this for your assignment.”

Run the following code to set things up:

Assignment setup¶

In [ ]:
## Importing recipes
%matplotlib inline

import imageio
import numpy as np
import os
import cv2
import matplotlib.pyplot as plt
from google.colab import drive
from skimage.color import rgb2gray
# Mounting google drive
drive.mount('/content/drive')


import matplotlib.pyplot as plt

def display_images_in_row(images, labels=None, cmap=None):
    """
    Display multiple images in a single row with labels below them.

    Args:
        images (list): List of images (numpy arrays or tensors convertible to numpy).
        labels (list, optional): List of labels corresponding to each image.
        cmap (str, optional): Colormap for displaying grayscale images.
    """
    num_images = len(images)
    print(f"Displaying {num_images} image{'s' if num_images > 1 else ''}")

    fig, axs = plt.subplots(1, num_images, figsize=(4 * num_images, 4))

    # Ensure axs is iterable
    if num_images == 1:
        axs = [axs]

    for i, (ax, img) in enumerate(zip(axs, images)):
        # Choose colormap
        if cmap is None:
            if img.ndim == 2 or (img.ndim == 3 and img.shape[2] == 1):
                ax.imshow(img.squeeze(), cmap="gray")
            else:
                ax.imshow(img)
        else:
            ax.imshow(img, cmap=cmap)

        ax.axis("off")

        # Add label below image if available
        if labels is not None and i < len(labels):
            ax.set_title(labels[i], fontsize=12, fontweight="bold", pad=10)

    plt.tight_layout()
    plt.show()


# Resize the original image to a smaller size
def resize_image(img, max_size=200):
    """Resize image while maintaining aspect ratio"""
    h, w = img.shape[:2]
    if max(h, w) > max_size:
        scale = max_size / max(h, w)
        new_h, new_w = int(h * scale), int(w * scale)
        resized = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_AREA)
        return resized
    return img


## Making recipes
base_path = "/content/drive/My Drive/ES666CV/images/B/"
mosaic_path = os.path.join(base_path, "mosaic.jpg")
key_path = os.path.join(base_path, "key.jpg")

# Load images
mosaic = cv2.imread(mosaic_path)        # BGR format
key = cv2.imread(key_path)

# Convert to RGB for matplotlib display
mosaic_rgb = cv2.cvtColor(mosaic, cv2.COLOR_BGR2RGB)
key_rgb = cv2.cvtColor(key, cv2.COLOR_BGR2RGB)

# Also convert to grayscale (float [0,1]) if needed for processing
mosaic_gray = rgb2gray(mosaic_rgb)
key_gray = rgb2gray(key_rgb)
mosaic_rgb_rs = resize_image(mosaic_rgb, max_size=500)
mosaic_rgb_rs = mosaic_rgb_rs.astype(np.float32) / 255.0
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).

Mosaic and Key¶

In [ ]:
fig, axs = plt.subplots(1, 2, figsize=(10, 5))
axs[0].imshow(mosaic_rgb)
axs[0].set_title("Mosaic")
axs[0].axis("off")
axs[1].imshow(key_rgb)
axs[1].set_title("Key Fragment")
axs[1].axis("off")
plt.show()
No description has been provided for this image

Task 1: Master the Arts of Purification (4 Marks)¶

Professor Ketu: "First, we must counteract the curse using the four sacred filtering techniques."

Implement the four denoising methods (mean, median, bilateral and gaussian) and compare their effectiveness:

In [ ]:
# run this cell as it is

def add_gaussian_noise(img, mean=0, var=0.01):
    if img.dtype != np.float32:
        img = img.astype(np.float32) / 255.0

    sigma = var**0.5
    noise = np.random.normal(mean, sigma, img.shape).astype(np.float32)
    noisy_img = np.clip(img + noise, 0.0, 1.0)

    return noisy_img



def add_salt_pepper_noise(img, amount=0.05):

    noisy_img = img.copy()
    H, W, _ = noisy_img.shape

    num_noisy_pixels = int(amount * H * W)

    row_coords = np.random.randint(0, H, num_noisy_pixels)
    col_coords = np.random.randint(0, W, num_noisy_pixels)

    num_salt = num_noisy_pixels // 2

    noisy_img[row_coords[:num_salt], col_coords[:num_salt], :] = 1.0

    noisy_img[row_coords[num_salt:], col_coords[num_salt:], :] = 0.0

    return noisy_img

def generate_noisy_versions_rgb(img, gaussian_vars, sp_amounts):

    noisy_versions = {
        "gaussian": np.array([add_gaussian_noise(img, var=v) for v in gaussian_vars]),
        "salt_pepper": np.array([add_salt_pepper_noise(img, amount=a) for a in sp_amounts])
    }
    return noisy_versions

gaussian_vars = [0.001, 0.01, 0.05]       # variance levels
sp_amounts = [0.01, 0.05, 0.1]           # salt & pepper intensity

noisy_mosaic = generate_noisy_versions_rgb(mosaic_rgb_rs, gaussian_vars, sp_amounts)
In [ ]:
noisy_mosaic["gaussian"][0].shape
Out[ ]:
(500, 456, 3)
In [ ]:
noisy_mosaic["salt_pepper"][0].shape
Out[ ]:
(500, 456, 3)
In [ ]:
print("Gaussian Noise with different variance")
display_images_in_row(noisy_mosaic["gaussian"],labels=["0.001","0.01","0.05"])
print("Salt and pepper Noise with different intensities")
display_images_in_row(noisy_mosaic["salt_pepper"], labels=["0.01","0.05","0.1"])
Gaussian Noise with different variance
Displaying 3 images
No description has been provided for this image
Salt and pepper Noise with different intensities
Displaying 3 images
No description has been provided for this image

Implement filters here for all the noise levels¶

Image Filtering Theory and Mathematical Formulation¶

This notebook implements four common image filtering techniques — Mean Filter, Median Filter, Gaussian Filter, and Bilateral Filter — all from scratch using NumPy.
Each filter smooths or denoises the image in a different way based on its mathematical formulation.


1. Mean Filter¶

The Mean Filter (also called the Average Filter) smooths the image by replacing each pixel value with the average of its neighbors in a square window of size kernel_size × kernel_size.

Mathematically, for a pixel at position $(i, j)$:

$$ I_{filtered}(i, j) = \frac{1}{k^2} \sum_{m=-p}^{p} \sum_{n=-p}^{p} I(i+m, j+n) $$

where:

  • $I(i, j)$ is the intensity at pixel $(i, j)$
  • $k$ is the kernel size
  • $p = \frac{k-1}{2}$ is the padding size

This acts as a low-pass filter, reducing high-frequency noise but also blurring edges.


2. Median Filter¶

The Median Filter replaces the intensity of each pixel with the median value of the intensities in its neighborhood window.

Mathematically:

$$ I_{filtered}(i, j) = \text{median} \{ I(i+m, j+n) \; | \; -p \le m, n \le p \} $$

This filter is non-linear and is particularly effective for removing Salt-and-Pepper noise, since it discards extreme outliers rather than averaging them.


3. Gaussian Filter¶

The Gaussian Filter performs weighted averaging using a Gaussian kernel, where nearby pixels have higher influence than distant ones.

The 2D Gaussian kernel is defined as:

$$ G(x, y) = \frac{1}{2\pi\sigma^2} \exp\left(-\frac{x^2 + y^2}{2\sigma^2}\right) $$

and the filtering operation is:

$$ I_{filtered}(i, j) = \sum_{m=-p}^{p} \sum_{n=-p}^{p} I(i+m, j+n) \cdot G(m, n) $$

where:

  • $\sigma$ controls the spread of the Gaussian (higher $\sigma$ → more smoothing),
  • the kernel is normalized so that $\sum G(x, y) = 1$.

Gaussian filtering is optimal for removing Gaussian (normally distributed) noise.


4. Bilateral Filter¶

The Bilateral Filter smooths the image while preserving edges, unlike mean or Gaussian filters that blur them.

It combines spatial proximity and intensity similarity into a single weighting function.

$$ I_{filtered}(i, j) = \frac{1}{W_p} \sum_{m=-p}^{p} \sum_{n=-p}^{p} I(i+m, j+n) \cdot f_s(m, n) \cdot f_r(I(i+m, j+n), I(i, j)) $$

where:

  • $f_s(m, n) = \exp\left(-\frac{m^2 + n^2}{2\sigma_s^2}\right)$ is the spatial Gaussian (depends on distance),
  • $f_r(I(i+m, j+n), I(i, j)) = \exp\left(-\frac{(I(i+m, j+n) - I(i, j))^2}{2\sigma_r^2}\right)$ is the range Gaussian (depends on intensity difference),
  • $W_p$ is a normalization factor:

$$ W_p = \sum_{m=-p}^{p} \sum_{n=-p}^{p} f_s(m, n) \cdot f_r(I(i+m, j+n), I(i, j)) $$

The bilateral filter thus smooths within regions but preserves edges because large intensity differences lead to small range weights.

In [ ]:
import numpy as np

def mean_filter(img, kernel_size=3):
    pad = kernel_size // 2
    kernel = np.ones((kernel_size, kernel_size)) / (kernel_size ** 2)
    filtered = np.zeros_like(img, dtype=float)

    # If RGB, apply per channel
    if img.ndim == 3:
        for c in range(img.shape[2]):
            padded = np.pad(img[..., c], pad, mode='reflect')
            for i in range(img.shape[0]):
                for j in range(img.shape[1]):
                    region = padded[i:i+kernel_size, j:j+kernel_size]
                    filtered[i, j, c] = np.sum(region * kernel)
    else:  # Grayscale
        padded = np.pad(img, pad, mode='reflect')
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                region = padded[i:i+kernel_size, j:j+kernel_size]
                filtered[i, j] = np.sum(region * kernel)
    return filtered


def median_filter(img, kernel_size=3):
    pad = kernel_size // 2
    filtered = np.zeros_like(img, dtype=float)

    if img.ndim == 3:
        for c in range(img.shape[2]):
            padded = np.pad(img[..., c], pad, mode='reflect')
            for i in range(img.shape[0]):
                for j in range(img.shape[1]):
                    region = padded[i:i+kernel_size, j:j+kernel_size]
                    filtered[i, j, c] = np.median(region)
    else:
        padded = np.pad(img, pad, mode='reflect')
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                region = padded[i:i+kernel_size, j:j+kernel_size]
                filtered[i, j] = np.median(region)
    return filtered


def gaussian_filter(img, kernel_size=5, sigma=1.0):
    pad = kernel_size // 2
    ax = np.arange(-pad, pad + 1)
    xx, yy = np.meshgrid(ax, ax)
    kernel = np.exp(-(xx**2 + yy**2) / (2 * sigma**2))
    kernel /= np.sum(kernel)

    filtered = np.zeros_like(img, dtype=float)
    if img.ndim == 3:
        for c in range(img.shape[2]):
            padded = np.pad(img[..., c], pad, mode='reflect')
            for i in range(img.shape[0]):
                for j in range(img.shape[1]):
                    region = padded[i:i+kernel_size, j:j+kernel_size]
                    filtered[i, j, c] = np.sum(region * kernel)
    else:
        padded = np.pad(img, pad, mode='reflect')
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                region = padded[i:i+kernel_size, j:j+kernel_size]
                filtered[i, j] = np.sum(region * kernel)
    return filtered


def bilateral_filter(img, diameter=5, sigma_color=0.2, sigma_space=2.0):
    pad = diameter // 2
    ax = np.arange(-pad, pad + 1)
    xx, yy = np.meshgrid(ax, ax)
    spatial_kernel = np.exp(-(xx**2 + yy**2) / (2 * sigma_space**2))

    filtered = np.zeros_like(img, dtype=float)
    if img.ndim == 3:
        for c in range(img.shape[2]):
            padded = np.pad(img[..., c], pad, mode='reflect')
            for i in range(img.shape[0]):
                for j in range(img.shape[1]):
                    region = padded[i:i+diameter, j:j+diameter]
                    diff = region - img[i, j, c]
                    range_kernel = np.exp(-(diff**2) / (2 * sigma_color**2))
                    bilateral_kernel = spatial_kernel * range_kernel
                    bilateral_kernel /= np.sum(bilateral_kernel)
                    filtered[i, j, c] = np.sum(region * bilateral_kernel)
    else:
        padded = np.pad(img, pad, mode='reflect')
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                region = padded[i:i+diameter, j:j+diameter]
                diff = region - img[i, j]
                range_kernel = np.exp(-(diff**2) / (2 * sigma_color**2))
                bilateral_kernel = spatial_kernel * range_kernel
                bilateral_kernel /= np.sum(bilateral_kernel)
                filtered[i, j] = np.sum(region * bilateral_kernel)
    return filtered
In [ ]:
mosaic_rgb.shape
Out[ ]:
(3803, 3469, 3)
In [ ]:
import numpy as np
from skimage.metrics import peak_signal_noise_ratio as psnr

def test_filters_minimal(noisy_versions, filter_functions, filter_names, original_image):
    rows = []
    row_info = []  # keep track of (noise_type, param)

    noise_params = [
        ('gaussian', [0.001, 0.01, 0.05]),
        ('salt_pepper', [0.01, 0.05, 0.1])
    ]

    for noise_type, params in noise_params:
        for i, param in enumerate(params):
            noisy = noisy_versions[noise_type][i]

            # Apply filters
            denoised_imgs = [f(noisy) for f in filter_functions]

            # Ensure denoised images are float32 and 3-channel
            denoised_imgs = [img.astype(np.float32) if img.dtype != np.float32 else img for img in denoised_imgs]
            denoised_imgs = [img if img.ndim == 3 else np.stack([img]*3, axis=-1) for img in denoised_imgs]

            row_imgs = [noisy] + denoised_imgs
            rows.append(row_imgs)
            row_info.append((noise_type, param))

            # Ensure noisy image is float32
            noisy_float = noisy.astype(np.float32) if noisy.dtype != np.float32 else noisy

            # Compute PSNR values
            psnr_values = [psnr(original_image, noisy_float)]
            psnr_values += [psnr(original_image, img) for img in denoised_imgs]

            print(f"\n==== {noise_type.upper()} noise (level={param}) ====")
            for name, value in zip(["Noisy"] + filter_names, psnr_values):
                print(f"{name} Filter → PSNR: {value:.2f} dB")

    # Display all rows
    for i, (row_imgs, (noise_type, param)) in enumerate(zip(rows, row_info)):
        print(f"\nRow {i+1}: {noise_type} noise (level={param})")
        display_images_in_row(row_imgs, ["Noisy"] + filter_names)

    return None

filter_functions = [mean_filter, median_filter, bilateral_filter, gaussian_filter]
filter_names = ['Mean', 'Median', 'Bilateral', 'Gaussian']

test_filters_minimal(noisy_mosaic, filter_functions, filter_names, mosaic_rgb_rs)
==== GAUSSIAN noise (level=0.001) ====
Noisy Filter → PSNR: 30.01 dB
Mean Filter → PSNR: 26.16 dB
Median Filter → PSNR: 26.53 dB
Bilateral Filter → PSNR: 27.13 dB
Gaussian Filter → PSNR: 26.69 dB

==== GAUSSIAN noise (level=0.01) ====
Noisy Filter → PSNR: 20.03 dB
Mean Filter → PSNR: 24.67 dB
Median Filter → PSNR: 24.01 dB
Bilateral Filter → PSNR: 25.59 dB
Gaussian Filter → PSNR: 25.41 dB

==== GAUSSIAN noise (level=0.05) ====
Noisy Filter → PSNR: 13.48 dB
Mean Filter → PSNR: 21.27 dB
Median Filter → PSNR: 19.66 dB
Bilateral Filter → PSNR: 16.99 dB
Gaussian Filter → PSNR: 22.23 dB

==== SALT_PEPPER noise (level=0.01) ====
Noisy Filter → PSNR: 25.64 dB
Mean Filter → PSNR: 25.80 dB
Median Filter → PSNR: 26.95 dB
Bilateral Filter → PSNR: 24.61 dB
Gaussian Filter → PSNR: 26.36 dB

==== SALT_PEPPER noise (level=0.05) ====
Noisy Filter → PSNR: 18.79 dB
Mean Filter → PSNR: 24.11 dB
Median Filter → PSNR: 26.72 dB
Bilateral Filter → PSNR: 20.11 dB
Gaussian Filter → PSNR: 24.83 dB

==== SALT_PEPPER noise (level=0.1) ====
Noisy Filter → PSNR: 15.86 dB
Mean Filter → PSNR: 22.63 dB
Median Filter → PSNR: 26.37 dB
Bilateral Filter → PSNR: 17.33 dB
Gaussian Filter → PSNR: 23.43 dB

Row 1: gaussian noise (level=0.001)
Displaying 5 images
No description has been provided for this image
Row 2: gaussian noise (level=0.01)
Displaying 5 images
No description has been provided for this image
Row 3: gaussian noise (level=0.05)
Displaying 5 images
No description has been provided for this image
Row 4: salt_pepper noise (level=0.01)
Displaying 5 images
No description has been provided for this image
Row 5: salt_pepper noise (level=0.05)
Displaying 5 images
No description has been provided for this image
Row 6: salt_pepper noise (level=0.1)
Displaying 5 images
No description has been provided for this image

📖 Theory Q: Question: Which filtering method works best for gaussian noise and which works for salt and pepper noise? Why?
Ans:

  1. Gaussian Noise:

Gaussian noise is a type of statistical noise that has a normal distribution. It affects almost all pixels in the image by adding small random variations in their intensity values. To remove this type of noise, Gaussian filtering (or sometimes mean filtering) works best.

A Gaussian filter smooths the image by performing a weighted average of neighboring pixel values, where closer pixels have higher weights. This reduces random intensity fluctuations introduced by Gaussian noise while still preserving the overall structure of the image. Hence, Gaussian filtering effectively suppresses Gaussian noise and produces a smoother, cleaner image.

  1. Salt and Pepper Noise:

Salt and pepper noise appears as random occurrences of black (0) and white (255) pixels in an image. Unlike Gaussian noise, it does not affect every pixel but only a small fraction, causing some pixels to take extreme intensity values.

For this type of noise, the Median filter works best. A median filter replaces each pixel’s value with the median of the intensity values in its neighborhood window. Since the median operation is not affected by extreme outliers, it successfully removes the corrupted black and white pixels while preserving the edges and details of the image.

Task 2: Detect the Points of Truth (3 Marks)¶

Professor Ketu: "Seek geometric truth in the original, not the corrupted version! The curse creates false corners."

Implement Harris Corner Detection on the pristine original image:

Harris Corner Detection¶


1. Gradient Computation¶

We first compute the image intensity gradients in the horizontal (x)and vertical (y) directions using finite differences:

$$ I_x(i, j) = \frac{I(i, j+1) - I(i, j-1)}{2} $$

$$ I_y(i, j) = \frac{I(i+1, j) - I(i-1, j)}{2} $$

These gradients represent the rate of change of pixel intensity and help detect edges and corners.


2. Structure Tensor (Second Moment Matrix)¶

At each pixel (i, j), a local window is defined to compute the structure tensor:

$$ M(i, j) = \begin{bmatrix} S_{xx} & S_{xy} \\ S_{xy} & S_{yy} \end{bmatrix} $$

where

$$ S_{xx} = G_\sigma * (I_x^2), \quad S_{yy} = G_\sigma * (I_y^2), \quad S_{xy} = G_\sigma * (I_x I_y) $$

Here, $G_\sigma$ represents a Gaussian filter that smooths the image to reduce noise.


3. Harris Response Function¶

The corner strength is given by:

$$ R = \det(M) - k \, (\text{trace}(M))^2 $$

where

$$ \det(M) = S_{xx} S_{yy} - S_{xy}^2, \quad \text{trace}(M) = S_{xx} + S_{yy} $$

and (k) is an empirical constant, typically $(0.04 \leq k \leq 0.06)$.

Interpretation of (R):

  • (R > 0): significant intensity change in all directions → corner
  • (R < 0): change in one direction → edge
  • $(R \approx 0)$: little or no change → flat region

4. Thresholding¶

After computing (R), corners are selected as points where:

$$ R(i, j) > \text{threshold}_{rel} \times R_{\max} $$

This filters out weak responses and keeps only strong corners.

5. Visualization¶

Detected corner points ((x, y)) are marked as red dots on the original image:

$$ I_{\text{corner}}(x, y) = \begin{cases} [1, 0, 0] & \text{if } R(x, y) > \text{threshold} \\ I(x, y) & \text{otherwise} \end{cases} $$

This results in a visual overlay highlighting the detected corners.

In [ ]:
import numpy as np
from scipy.ndimage import gaussian_filter, maximum_filter
import matplotlib.pyplot as plt

def detect_harris_corner(image, k=0.04, window_size=13, threshold_rel=0.01):
    """
    Harris Corner Detector with Non-Maximum Suppression
    """
    # Convert to grayscale if RGB
    if image.ndim == 3:
        img = np.dot(image[..., :3], [0.299, 0.587, 0.114])
    else:
        img = image.copy()

    img = img.astype(float)

    # Compute gradients
    Ix = np.zeros_like(img)
    Iy = np.zeros_like(img)
    Ix[:, 1:-1] = (img[:, 2:] - img[:, :-2]) / 2.0
    Iy[1:-1, :] = (img[2:, :] - img[:-2, :]) / 2.0

    # Compute products and smooth
    Ixx = gaussian_filter(Ix * Ix, sigma=3.0)
    Iyy = gaussian_filter(Iy * Iy, sigma=3.0)
    Ixy = gaussian_filter(Ix * Iy, sigma=3.0)

    # Harris response
    det_M = (Ixx * Iyy) - (Ixy ** 2)
    trace_M = Ixx + Iyy
    R = det_M - k * (trace_M ** 2)

    # Thresholding
    threshold = threshold_rel * R.max()
    R_thresh = (R > threshold) * R

    # Non-maximum suppression
    R_nms = R_thresh * (R_thresh == maximum_filter(R_thresh, size=window_size))

    # Get corner coordinates
    corners = np.argwhere(R_nms)
    corners = [tuple(pt) for pt in corners]  # (y, x)

    # Create corner image
    corner_image = image.copy().astype(float)
    if image.ndim == 2:
        corner_image = np.stack([corner_image]*3, axis=-1)
    if corner_image.max() > 1:
        corner_image = corner_image / 255.0

    # Draw red dots
    for y, x in corners:
        if 1 < y < image.shape[0]-1 and 1 < x < image.shape[1]-1:
            corner_image[y-1:y+2, x-1:x+2] = [1, 0, 0]

    print(f"Found {len(corners)} corners")
    return corner_image, corners


def display_images_in_row(images, titles=None):
    n = len(images)
    plt.figure(figsize=(5*n,5))
    for i, img in enumerate(images):
        plt.subplot(1, n, i+1)
        plt.imshow(img)
        if titles:
            plt.title(titles[i])
        plt.axis('off')
    plt.show()


# Detect corners
key_harris, key_corners = detect_harris_corner(key_rgb)
mosaic_harris, mosaic_corners = detect_harris_corner(mosaic_rgb)

# Display results
display_images_in_row([key_rgb, key_harris], titles=["Original Key", "Corners Key"])
display_images_in_row([mosaic_rgb, mosaic_harris], titles=["Original Mosaic", "Corners Mosaic"])
Found 2616 corners
Found 24871 corners
No description has been provided for this image
No description has been provided for this image

📖 Theory Q: What mathematical property of the Harris matrix allows it to distinguish between edges and corners?
Ans.Harris Corner Detector: Key Property to Distinguish Edges and Corners

The Harris matrix (structure tensor) at a pixel is:

$$ M = \begin{bmatrix} \sum I_x^2 & \sum I_x I_y \\ \sum I_x I_y & \sum I_y^2 \end{bmatrix} $$

where $(I_x)$ and $(I_y)$ are image gradients in x and y directions.

  • Let $lambda_1$ and $lambda_2$ be the eigenvalues of M, representing intensity change along principal directions.
  • Classification based on eigenvalues:
    • Flat region: $$lambda_1 \approx 0, \lambda_2 \approx 0$$
    • Edge: one large, one small ($$lambda_1 \gg \lambda_2$$ or vice versa)
    • Corner: both large ($$lambda_1, \lambda_2 \gg 0$$)

Harris corner response function:

$$ R = \det(M) - k \cdot (\text{trace}(M))^2 $$

  • $R > 0$ → corner
  • $R < 0$ → edge
  • $R \approx 0$ → flat region

Conclusion:
The eigenvalues of the Harris matrix allow distinguishing corners from edges and flat regions.

Task 3: Find the Hidden Philosopher (3 Marks)¶

Professor Ketu: "Combine my teachings! Let the original guide your search, let clarity reveal the details."

Implement feature matching to find the philoshopher in the mosaic, you can use SSD (Sum of squared differences):

Hint:How can you describe small patches around keypoints in both images?
How do you measure similarity between descriptors?

In [ ]:
import numpy as np

def extract_descriptors(img, corners, patch_size=15):
    """
    Extract simple square patch descriptors around each corner.

    Args:
        img: input image (H,W) or (H,W,3)
        corners: list of (y,x) corner coordinates
        patch_size: size of the patch (should be odd)

    Returns:
        valid_points: list of corners where patch fits
        descriptors: array of flattened patches
    """
    pad = patch_size // 2

    # Convert to grayscale if RGB
    if img.ndim == 3:
        gray = np.dot(img[..., :3], [0.299, 0.587, 0.114])
    else:
        gray = img.copy()

    descriptors = []
    valid_points = []

    # Pad the image to handle border corners
    padded = np.pad(gray, pad, mode='reflect')

    for y, x in corners:
        y_pad, x_pad = y + pad, x + pad
        patch = padded[y_pad - pad:y_pad + pad + 1, x_pad - pad:x_pad + pad + 1]

        if patch.shape == (patch_size, patch_size):
            descriptors.append(patch.flatten())
            valid_points.append([y, x])

    descriptors = np.array(descriptors)
    valid_points = np.array(valid_points)
    return valid_points, descriptors

def match_features(desc1, desc2, pts1, pts2, ratio=0.7):
    """
    Match descriptors using L2 distance and ratio test.

    Args:
        desc1: descriptors from image1 (N1 x D)
        desc2: descriptors from image2 (N2 x D)
        pts1: corner points from image1 (N1 x 2)
        pts2: corner points from image2 (N2 x 2)
        ratio: Lowe's ratio threshold

    Returns:
        matches: list of tuples (pt1, pt2)
    """
    matches = []

    for i, d1 in enumerate(desc1):
        # Compute L2 distance to all descriptors in desc2
        distances = np.linalg.norm(desc2 - d1, axis=1)
        if len(distances) < 2:
            continue
        # Find best and second best match
        idx_sorted = np.argsort(distances)
        best_idx, second_idx = idx_sorted[0], idx_sorted[1]

        if distances[best_idx] < ratio * distances[second_idx]:
            matches.append((pts1[i], pts2[best_idx]))

    return matches


pts_mosaic, desc_mosaic = extract_descriptors(mosaic_rgb, mosaic_corners)
pts_key, desc_key = extract_descriptors(key_rgb, key_corners)
In [ ]:
matches = match_features(desc_key, desc_mosaic, pts_key, pts_mosaic)

print(matches)
mosaic_vis = mosaic_rgb.copy()
for (y1, x1), (y2, x2) in matches:
    cv2.circle(mosaic_vis, (x2, y2), 5, (255, 0, 0), 2)

plt.figure(figsize=(10, 6))
plt.imshow(mosaic_vis)
plt.title("Template key matched in Mosaic")
plt.axis("off")
plt.show()
[(array([  4, 544]), array([1525, 1832])), (array([  4, 589]), array([1525, 1877])), (array([  5, 350]), array([1526, 1638])), (array([  5, 385]), array([1526, 1673])), (array([  5, 452]), array([1526, 1740])), (array([  5, 491]), array([1526, 1779])), (array([  5, 576]), array([1526, 1864])), (array([  5, 623]), array([1526, 1911])), (array([  6, 562]), array([1527, 1850])), (array([  7, 230]), array([1528, 1518])), (array([  9, 185]), array([1530, 1473])), (array([  9, 209]), array([1530, 1497])), (array([  9, 262]), array([1530, 1550])), (array([  9, 602]), array([1530, 1890])), (array([ 10, 174]), array([1531, 1462])), (array([ 10, 275]), array([1531, 1563])), (array([11,  9]), array([1532, 1297])), (array([11, 82]), array([1532, 1370])), (array([ 11, 144]), array([1532, 1432])), (array([ 11, 153]), array([1532, 1441])), (array([12, 28]), array([1533, 1316])), (array([13, 98]), array([1534, 1386])), (array([ 13, 163]), array([1534, 1451])), (array([ 13, 290]), array([1534, 1578])), (array([ 13, 316]), array([1534, 1604])), (array([ 13, 876]), array([1534, 2164])), (array([ 14, 107]), array([1535, 1395])), (array([ 14, 120]), array([1535, 1408])), (array([ 14, 652]), array([1535, 1940])), (array([ 14, 674]), array([1535, 1962])), (array([ 14, 687]), array([1535, 1975])), (array([ 14, 698]), array([1535, 1986])), (array([ 14, 780]), array([1535, 2068])), (array([15, 40]), array([1536, 1328])), (array([15, 61]), array([1536, 1349])), (array([ 15, 762]), array([1536, 2050])), (array([ 15, 814]), array([1536, 2102])), (array([ 16, 342]), array([1537, 1630])), (array([ 16, 626]), array([1537, 1914])), (array([ 17, 368]), array([1538, 1656])), (array([ 17, 426]), array([1538, 1714])), (array([ 17, 448]), array([1538, 1736])), (array([ 17, 490]), array([1538, 1778])), (array([ 17, 561]), array([1538, 1849])), (array([ 17, 835]), array([1538, 2123])), (array([ 18, 718]), array([1539, 2006])), (array([ 18, 855]), array([1539, 2143])), (array([ 18, 901]), array([1539, 2189])), (array([ 19, 436]), array([1540, 1724])), (array([ 19, 603]), array([1540, 1891])), (array([ 19, 934]), array([1540, 2222])), (array([ 21, 239]), array([1542, 1527])), (array([ 21, 400]), array([1542, 1688])), (array([ 23, 202]), array([1544, 1490])), (array([ 24, 152]), array([1545, 1440])), (array([ 25, 266]), array([1546, 1554])), (array([ 26, 164]), array([1547, 1452])), (array([ 26, 309]), array([1547, 1597])), (array([ 26, 771]), array([1547, 2059])), (array([27,  7]), array([1548, 1295])), (array([27, 89]), array([1548, 1377])), (array([ 27, 211]), array([1548, 1499])), (array([ 27, 751]), array([1548, 2039])), (array([29, 20]), array([1550, 1308])), (array([29, 43]), array([1550, 1331])), (array([ 29, 838]), array([1550, 2126])), (array([30, 57]), array([1551, 1345])), (array([30, 72]), array([1551, 1360])), (array([ 30, 472]), array([1551, 1760])), (array([ 31, 459]), array([1552, 1747])), (array([ 31, 497]), array([1552, 1785])), (array([ 31, 509]), array([1552, 1797])), (array([ 31, 710]), array([1552, 1998])), (array([ 31, 740]), array([1552, 2028])), (array([ 31, 790]), array([1552, 2078])), (array([ 33, 557]), array([1554, 1845])), (array([ 34, 533]), array([1555, 1821])), (array([ 34, 579]), array([1555, 1867])), (array([ 34, 613]), array([1555, 1901])), (array([ 34, 630]), array([1555, 1918])), (array([ 34, 932]), array([1555, 2220])), (array([ 35, 242]), array([1556, 1530])), (array([ 36, 596]), array([1557, 1884])), (array([ 37, 252]), array([1558, 1540])), (array([ 37, 398]), array([1558, 1686])), (array([ 37, 891]), array([1558, 2179])), (array([ 37, 942]), array([1558, 2230])), (array([ 38, 149]), array([1559, 1437])), (array([ 38, 232]), array([1558, 1520])), (array([ 38, 277]), array([1559, 1565])), (array([ 39, 133]), array([1560, 1421])), (array([ 39, 266]), array([1560, 1554])), (array([40, 23]), array([1561, 1311])), (array([ 40, 767]), array([1561, 2055])), (array([41, 45]), array([1562, 1333])), (array([ 41, 188]), array([1562, 1476])), (array([ 41, 437]), array([1562, 1725])), (array([ 41, 482]), array([1562, 1770])), (array([ 42, 114]), array([1563, 1402])), (array([ 42, 200]), array([1563, 1488])), (array([ 42, 495]), array([1563, 1783])), (array([ 42, 752]), array([1563, 2040])), (array([ 42, 777]), array([1563, 2065])), (array([43, 78]), array([1564, 1366])), (array([ 43, 471]), array([1564, 1759])), (array([ 43, 530]), array([1564, 1818])), (array([ 43, 702]), array([1564, 1990])), (array([ 43, 722]), array([1564, 2010])), (array([44, 57]), array([1565, 1345])), (array([ 45, 803]), array([1566, 2091])), (array([ 46, 334]), array([1567, 1622])), (array([ 47, 655]), array([1568, 1943])), (array([ 47, 825]), array([1568, 2113])), (array([ 47, 916]), array([1568, 2204])), (array([ 48, 224]), array([1569, 1512])), (array([ 48, 581]), array([1569, 1869])), (array([ 48, 623]), array([1569, 1911])), (array([ 48, 641]), array([1569, 1929])), (array([ 48, 674]), array([1569, 1962])), (array([ 48, 944]), array([1569, 2232])), (array([ 49, 260]), array([1571, 1548])), (array([ 49, 611]), array([1570, 1899])), (array([ 50, 597]), array([1571, 1885])), (array([ 51, 393]), array([1572, 1681])), (array([ 51, 559]), array([1572, 1847])), (array([ 53, 124]), array([1574, 1412])), (array([ 54, 238]), array([1575, 1526])), (array([55, 55]), array([1576, 1343])), (array([ 55, 115]), array([1576, 1403])), (array([ 55, 270]), array([1576, 1558])), (array([ 55, 752]), array([1576, 2040])), (array([ 55, 765]), array([1576, 2053])), (array([ 56, 506]), array([1577, 1794])), (array([ 56, 791]), array([1577, 2079])), (array([ 56, 804]), array([1577, 2092])), (array([ 57, 453]), array([1578, 1741])), (array([ 57, 738]), array([1578, 2026])), (array([58, 90]), array([1579, 1378])), (array([ 58, 493]), array([1579, 1781])), (array([ 58, 520]), array([1579, 1808])), (array([ 59, 415]), array([1580, 1703])), (array([ 59, 655]), array([1580, 1943])), (array([ 59, 673]), array([1580, 1961])), (array([ 60, 612]), array([1581, 1900])), (array([ 60, 695]), array([1581, 1983])), (array([ 60, 778]), array([1581, 2066])), (array([ 61, 192]), array([1582, 1480])), (array([ 61, 929]), array([1582, 2217])), (array([ 62, 589]), array([1583, 1877])), (array([ 62, 643]), array([1583, 1931])), (array([ 62, 831]), array([1583, 2119])), (array([ 63, 176]), array([1584, 1464])), (array([ 63, 883]), array([1584, 2171])), (array([ 64, 242]), array([1585, 1530])), (array([ 64, 349]), array([1585, 1637])), (array([ 64, 364]), array([1585, 1652])), (array([ 64, 548]), array([1585, 1836])), (array([ 64, 863]), array([1585, 2151])), (array([ 64, 920]), array([1585, 2208])), (array([ 65, 907]), array([1586, 2195])), (array([ 66, 942]), array([1587, 2230])), (array([ 67, 163]), array([1588, 1451])), (array([68, 76]), array([1589, 1364])), (array([ 68, 482]), array([1589, 1770])), (array([69, 10]), array([1590, 1298])), (array([69, 64]), array([1590, 1352])), (array([ 70, 104]), array([1591, 1392])), (array([ 70, 462]), array([1591, 1750])), (array([ 71, 731]), array([1592, 2019])), (array([ 71, 741]), array([1592, 2029])), (array([ 71, 782]), array([1592, 2070])), (array([ 72, 179]), array([1593, 1467])), (array([ 72, 536]), array([1593, 1824])), (array([ 72, 674]), array([1593, 1962])), (array([ 72, 697]), array([1593, 1985])), (array([ 72, 833]), array([1593, 2121])), (array([ 73, 558]), array([1594, 1846])), (array([ 73, 662]), array([1594, 1950])), (array([ 74, 193]), array([1595, 1481])), (array([ 74, 755]), array([1595, 2043])), (array([ 75, 609]), array([1596, 1897])), (array([ 76, 506]), array([1597, 1794])), (array([ 77, 284]), array([1598, 1572])), (array([ 77, 407]), array([1598, 1695])), (array([ 77, 635]), array([1598, 1923])), (array([ 78, 585]), array([1599, 1873])), (array([ 78, 848]), array([1599, 2136])), (array([ 78, 894]), array([1599, 2182])), (array([ 79, 247]), array([1600, 1535])), (array([ 80, 421]), array([1601, 1709])), (array([ 80, 548]), array([1601, 1836])), (array([ 81, 264]), array([1602, 1552])), (array([ 81, 388]), array([1602, 1676])), (array([ 82, 811]), array([1603, 2099])), (array([ 82, 823]), array([1603, 2111])), (array([83, 22]), array([1604, 1310])), (array([ 83, 122]), array([1603, 1410])), (array([ 83, 322]), array([1604, 1610])), (array([84, 13]), array([1605, 1301])), (array([84, 85]), array([1605, 1373])), (array([ 84, 799]), array([1605, 2087])), (array([ 85, 179]), array([1606, 1467])), (array([ 85, 708]), array([1606, 1996])), (array([ 85, 786]), array([1606, 2074])), (array([ 86, 694]), array([1607, 1982])), (array([ 86, 739]), array([1607, 2027])), (array([87, 40]), array([1608, 1328])), (array([ 87, 107]), array([1608, 1395])), (array([ 87, 672]), array([1608, 1960])), (array([ 87, 724]), array([1608, 2012])), (array([ 87, 763]), array([1608, 2051])), (array([ 88, 164]), array([1609, 1452])), (array([ 88, 375]), array([1609, 1663])), (array([ 88, 650]), array([1609, 1938])), (array([ 88, 683]), array([1609, 1971])), (array([ 89, 218]), array([1610, 1506])), (array([ 89, 846]), array([1610, 2134])), (array([ 90, 196]), array([1611, 1484])), (array([ 91, 153]), array([1612, 1441])), (array([ 91, 570]), array([1612, 1858])), (array([ 92, 276]), array([1613, 1564])), (array([ 92, 586]), array([1613, 1874])), (array([ 92, 609]), array([1613, 1897])), (array([ 92, 635]), array([1613, 1923])), (array([ 92, 892]), array([1613, 2180])), (array([ 92, 904]), array([1613, 2192])), (array([ 93, 557]), array([1614, 1845])), (array([ 93, 599]), array([1614, 1887])), (array([ 93, 869]), array([1614, 2157])), (array([ 94, 541]), array([1615, 1829])), (array([ 94, 621]), array([1615, 1909])), (array([ 94, 748]), array([1615, 2036])), (array([ 95, 485]), array([1616, 1773])), (array([ 96, 119]), array([1617, 1407])), (array([ 96, 262]), array([1617, 1550])), (array([ 96, 331]), array([1617, 1619])), (array([ 96, 364]), array([1617, 1652])), (array([ 96, 739]), array([1617, 2027])), (array([ 97, 247]), array([1618, 1535])), (array([ 97, 947]), array([1618, 2235])), (array([98, 57]), array([1619, 1345])), (array([98, 93]), array([1619, 1381])), (array([ 98, 776]), array([1619, 2064])), (array([ 98, 806]), array([1619, 2094])), (array([99, 80]), array([1620, 1368])), (array([ 99, 106]), array([1620, 1394])), (array([100,  18]), array([1621, 1306])), (array([100,  69]), array([1621, 1357])), (array([100, 416]), array([1621, 1704])), (array([101, 193]), array([1622, 1481])), (array([101, 675]), array([1622, 1963])), (array([102, 573]), array([1623, 1861])), (array([102, 853]), array([1623, 2141])), (array([103, 207]), array([1624, 1495])), (array([104, 141]), array([1625, 1428])), (array([104, 174]), array([1625, 1462])), (array([104, 658]), array([1625, 1946])), (array([104, 899]), array([1625, 2187])), (array([105, 471]), array([1626, 1759])), (array([105, 588]), array([1626, 1876])), (array([105, 840]), array([1626, 2128])), (array([106, 639]), array([1627, 1927])), (array([106, 749]), array([1627, 2037])), (array([106, 876]), array([1627, 2164])), (array([107, 159]), array([1628, 1447])), (array([107, 886]), array([1628, 2174])), (array([108, 728]), array([1629, 2016])), (array([109, 249]), array([1630, 1537])), (array([109, 319]), array([1630, 1607])), (array([109, 764]), array([1630, 2052])), (array([110, 944]), array([1631, 2232])), (array([111, 376]), array([1632, 1664])), (array([111, 546]), array([1632, 1834])), (array([111, 558]), array([1632, 1846])), (array([112,  58]), array([1633, 1346])), (array([112,  80]), array([1633, 1368])), (array([112, 104]), array([1633, 1392])), (array([112, 268]), array([1633, 1556])), (array([112, 656]), array([1633, 1944])), (array([114,  42]), array([1635, 1330])), (array([115,  31]), array([1636, 1319])), (array([115, 570]), array([1636, 1858])), (array([116,  10]), array([1637, 1298])), (array([116, 175]), array([1637, 1463])), (array([116, 831]), array([1637, 2119])), (array([117, 213]), array([1638, 1501])), (array([117, 842]), array([1638, 2130])), (array([120, 194]), array([1641, 1482])), (array([120, 531]), array([1641, 1819])), (array([120, 898]), array([1641, 2186])), (array([120, 944]), array([1641, 2232])), (array([121, 481]), array([1642, 1769])), (array([122, 335]), array([1643, 1623])), (array([122, 909]), array([1643, 2197])), (array([123, 319]), array([1644, 1607])), (array([123, 495]), array([1644, 1783])), (array([128, 632]), array([1649, 1920])), (array([128, 722]), array([1649, 2010])), (array([129,  67]), array([1650, 1355])), (array([129, 578]), array([1650, 1866])), (array([130,  50]), array([1651, 1338])), (array([130, 264]), array([1651, 1552])), (array([130, 794]), array([1651, 2082])), (array([131, 166]), array([1652, 1454])), (array([131, 177]), array([1652, 1465])), (array([132, 545]), array([1653, 1833])), (array([132, 733]), array([1653, 2021])), (array([132, 814]), array([1653, 2102])), (array([132, 860]), array([1653, 2148])), (array([132, 873]), array([1653, 2161])), (array([133,  27]), array([1654, 1315])), (array([133, 138]), array([1654, 1426])), (array([133, 152]), array([1654, 1440])), (array([133, 403]), array([1654, 1691])), (array([134, 197]), array([1655, 1485])), (array([135, 885]), array([1656, 2173])), (array([135, 944]), array([1656, 2232])), (array([136, 243]), array([1657, 1531])), (array([136, 318]), array([1657, 1606])), (array([136, 332]), array([1657, 1620])), (array([137, 518]), array([1658, 1806])), (array([138, 930]), array([1659, 2218])), (array([139,  91]), array([1660, 1379])), (array([141,  51]), array([1662, 1339])), (array([141, 370]), array([1662, 1658])), (array([142, 606]), array([1663, 1894])), (array([142, 680]), array([1663, 1968])), (array([143,  19]), array([1664, 1307])), (array([143, 505]), array([1664, 1793])), (array([144, 199]), array([1665, 1487])), (array([144, 383]), array([1665, 1671])), (array([145, 129]), array([1666, 1417])), (array([145, 210]), array([1666, 1498])), (array([145, 544]), array([1666, 1832])), (array([145, 795]), array([1666, 2083])), (array([145, 849]), array([1666, 2137])), (array([145, 871]), array([1666, 2159])), (array([146, 262]), array([1668, 1550])), (array([146, 584]), array([1667, 1872])), (array([147,  68]), array([1668, 1356])), (array([147, 176]), array([1668, 1464])), (array([147, 189]), array([1668, 1477])), (array([148, 141]), array([1669, 1429])), (array([148, 566]), array([1669, 1854])), (array([148, 930]), array([1669, 2218])), (array([149, 720]), array([1670, 2008])), (array([149, 919]), array([1670, 2207])), (array([151, 631]), array([1672, 1919])), (array([151, 942]), array([1672, 2230])), (array([153, 164]), array([1674, 1452])), (array([155, 682]), array([1676, 1970])), (array([156, 321]), array([1677, 1609])), (array([156, 774]), array([1677, 2062])), (array([156, 823]), array([1677, 2111])), (array([158,  50]), array([1679, 1338])), (array([158, 140]), array([1679, 1428])), (array([159,  20]), array([1680, 1308])), (array([159,  99]), array([1680, 1387])), (array([159, 489]), array([1680, 1777])), (array([160,  88]), array([1681, 1376])), (array([160, 870]), array([1681, 2158])), (array([161, 641]), array([1682, 1929])), (array([161, 857]), array([1682, 2145])), (array([162, 199]), array([1683, 1487])), (array([162, 705]), array([1683, 1993])), (array([162, 920]), array([1683, 2208])), (array([163, 910]), array([1684, 2198])), (array([163, 942]), array([1684, 2230])), (array([164, 345]), array([1685, 1633])), (array([164, 476]), array([1685, 1764])), (array([164, 892]), array([1685, 2180])), (array([167, 174]), array([1688, 1462])), (array([167, 185]), array([1688, 1473])), (array([167, 690]), array([1688, 1978])), (array([168, 101]), array([1689, 1389])), (array([169, 802]), array([1690, 2090])), (array([171, 449]), array([1692, 1737])), (array([171, 617]), array([1692, 1905])), (array([171, 858]), array([1692, 2146])), (array([172, 123]), array([1693, 1411])), (array([172, 214]), array([1693, 1502])), (array([172, 436]), array([1693, 1724])), (array([172, 698]), array([1693, 1986])), (array([173, 769]), array([1694, 2057])), (array([173, 870]), array([1694, 2158])), (array([173, 882]), array([1694, 2170])), (array([175,  25]), array([1696, 1313])), (array([176, 242]), array([1697, 1530])), (array([176, 626]), array([1697, 1914])), (array([177,  17]), array([1698, 1305])), (array([177, 170]), array([1698, 1458])), (array([177, 637]), array([1698, 1925])), (array([177, 928]), array([1698, 2216])), (array([179, 257]), array([1700, 1545])), (array([179, 903]), array([1700, 2191])), (array([180, 381]), array([1701, 1669])), (array([180, 579]), array([1700, 1867])), (array([181, 398]), array([1702, 1686])), (array([181, 498]), array([1702, 1786])), (array([181, 785]), array([1702, 2073])), (array([184, 338]), array([1705, 1626])), (array([185,  76]), array([1706, 1364])), (array([185, 664]), array([1706, 1952])), (array([185, 818]), array([1706, 2106])), (array([185, 864]), array([1706, 2152])), (array([187, 802]), array([1708, 2090])), (array([187, 834]), array([1708, 2122])), (array([188,  38]), array([1709, 1326])), (array([188, 472]), array([1709, 1760])), (array([189, 162]), array([1710, 1450])), (array([189, 359]), array([1710, 1647])), (array([189, 844]), array([1710, 2132])), (array([189, 902]), array([1710, 2190])), (array([190, 918]), array([1711, 2206])), (array([191, 577]), array([1712, 1865])), (array([191, 890]), array([1712, 2178])), (array([192, 621]), array([1713, 1909])), (array([193, 929]), array([1714, 2217])), (array([195, 397]), array([1716, 1685])), (array([196, 590]), array([1717, 1878])), (array([196, 948]), array([1717, 2236])), (array([197, 186]), array([1718, 1474])), (array([197, 326]), array([1718, 1614])), (array([198,  40]), array([1719, 1328])), (array([200, 831]), array([1721, 2119])), (array([201,  18]), array([1722, 1306])), (array([201, 379]), array([1722, 1667])), (array([201, 750]), array([1722, 2038])), (array([202, 809]), array([1723, 2097])), (array([203,   3]), array([1724, 1291])), (array([203, 163]), array([1724, 1451])), (array([203, 406]), array([1724, 1694])), (array([203, 650]), array([1724, 1938])), (array([203, 737]), array([1724, 2025])), (array([204, 121]), array([1725, 1409])), (array([204, 562]), array([1725, 1850])), (array([205, 686]), array([1726, 1974])), (array([207, 595]), array([1728, 1883])), (array([208, 176]), array([1729, 1464])), (array([208, 451]), array([1729, 1739])), (array([209, 947]), array([1730, 2235])), (array([211, 324]), array([1732, 1612])), (array([212, 362]), array([1733, 1650])), (array([213, 430]), array([1734, 1718])), (array([213, 620]), array([1734, 1908])), (array([214,  33]), array([1735, 1321])), (array([215, 467]), array([1736, 1755])), (array([215, 752]), array([1736, 2040])), (array([216, 737]), array([1737, 2025])), (array([216, 821]), array([1737, 2109])), (array([216, 839]), array([1737, 2127])), (array([216, 852]), array([1737, 2140])), (array([217,  81]), array([1738, 1369])), (array([217, 886]), array([1738, 2174])), (array([218, 131]), array([1739, 1419])), (array([218, 900]), array([1739, 2188])), (array([218, 914]), array([1739, 2202])), (array([219, 185]), array([1740, 1473])), (array([219, 521]), array([1740, 1809])), (array([220,  71]), array([1741, 1359])), (array([220, 646]), array([1741, 1934])), (array([220, 948]), array([1741, 2236])), (array([221, 174]), array([1742, 1462])), (array([221, 612]), array([1742, 1900])), (array([222, 242]), array([1743, 1530])), (array([222, 377]), array([1743, 1665])), (array([222, 626]), array([1743, 1914])), (array([222, 691]), array([1743, 1979])), (array([223, 327]), array([1744, 1615])), (array([223, 661]), array([1744, 1949])), (array([226, 406]), array([1747, 1694])), (array([226, 751]), array([1747, 2039])), (array([227,  90]), array([1748, 1378])), (array([227, 800]), array([1748, 2088])), (array([229,  17]), array([1750, 1305])), (array([229,  40]), array([1750, 1328])), (array([230, 176]), array([1751, 1464])), (array([230, 445]), array([1751, 1733])), (array([230, 828]), array([1751, 2116])), (array([231, 189]), array([1752, 1477])), (array([231, 898]), array([1752, 2186])), (array([232, 458]), array([1753, 1746])), (array([232, 908]), array([1753, 2196])), (array([233, 549]), array([1754, 1837])), (array([234, 882]), array([1755, 2170])), (array([235, 162]), array([1756, 1450])), (array([235, 871]), array([1756, 2159])), (array([236,  54]), array([1757, 1342])), (array([236, 669]), array([1757, 1957])), (array([236, 701]), array([1757, 1989])), (array([237, 854]), array([1758, 2142])), (array([238, 512]), array([1759, 1800])), (array([240,  32]), array([1761, 1320])), (array([241, 397]), array([1762, 1685])), (array([241, 624]), array([1762, 1912])), (array([241, 780]), array([1762, 2068])), (array([242, 188]), array([1763, 1476])), (array([242, 792]), array([1763, 2080])), (array([243,  17]), array([1764, 1305])), (array([243, 384]), array([1764, 1672])), (array([243, 409]), array([1764, 1697])), (array([243, 742]), array([1764, 2030])), (array([245, 351]), array([1766, 1639])), (array([245, 824]), array([1767, 2112])), (array([245, 832]), array([1766, 2120])), (array([247, 287]), array([1768, 1575])), (array([248, 947]), array([1769, 2235])), (array([250,  65]), array([1771, 1353])), (array([250, 340]), array([1771, 1628])), (array([251, 209]), array([1772, 1497])), (array([251, 536]), array([1772, 1824])), (array([251, 589]), array([1772, 1877])), (array([251, 608]), array([1772, 1896])), (array([252, 451]), array([1773, 1739])), (array([252, 461]), array([1773, 1749])), (array([253, 399]), array([1774, 1687])), (array([253, 753]), array([1774, 2041])), (array([257,  17]), array([1778, 1305])), (array([257, 101]), array([1778, 1389])), (array([257, 422]), array([1778, 1710])), (array([258, 834]), array([1779, 2122])), (array([258, 856]), array([1779, 2144])), (array([259, 510]), array([1780, 1798])), (array([260, 658]), array([1781, 1946])), (array([260, 825]), array([1781, 2113])), (array([261, 230]), array([1782, 1518])), (array([261, 270]), array([1782, 1558])), (array([261, 896]), array([1782, 2184])), (array([263, 926]), array([1784, 2214])), (array([264, 947]), array([1785, 2235])), (array([265,  82]), array([1786, 1370])), (array([265, 321]), array([1786, 1609])), (array([265, 542]), array([1786, 1830])), (array([266,  42]), array([1787, 1330])), (array([267, 388]), array([1788, 1676])), (array([267, 440]), array([1788, 1728])), (array([269,  70]), array([1790, 1358])), (array([269, 746]), array([1790, 2034])), (array([272, 113]), array([1793, 1401])), (array([274, 913]), array([1795, 2201])), (array([275, 232]), array([1796, 1520])), (array([275, 557]), array([1796, 1845])), (array([276, 566]), array([1797, 1854])), (array([277,  89]), array([1798, 1377])), (array([277, 437]), array([1798, 1725])), (array([277, 889]), array([1798, 2177])), (array([278, 877]), array([1799, 2165])), (array([279, 945]), array([1800, 2233])), (array([280, 758]), array([1801, 2046])), (array([281,  49]), array([1802, 1337])), (array([282,   9]), array([1803, 1297])), (array([282,  20]), array([1803, 1308])), (array([282, 450]), array([1803, 1738])), (array([285, 245]), array([1806, 1533])), (array([285, 290]), array([1806, 1578])), (array([285, 370]), array([1806, 1658])), (array([285, 721]), array([1806, 2009])), (array([287, 588]), array([1808, 1876])), (array([288, 878]), array([1809, 2166])), (array([289, 891]), array([1810, 2179])), (array([293, 912]), array([1814, 2200])), (array([294,  40]), array([1815, 1328])), (array([294, 670]), array([1815, 1958])), (array([295,  10]), array([1816, 1298])), (array([295, 308]), array([1816, 1596])), (array([296, 235]), array([1817, 1523])), (array([296, 800]), array([1817, 2088])), (array([297, 451]), array([1818, 1739])), (array([297, 778]), array([1818, 2066])), (array([297, 938]), array([1818, 2226])), (array([298,  23]), array([1819, 1311])), (array([298, 327]), array([1819, 1615])), (array([298, 730]), array([1819, 2018])), (array([298, 744]), array([1819, 2032])), (array([298, 767]), array([1819, 2055])), (array([300, 136]), array([1821, 1424])), (array([300, 176]), array([1821, 1464])), (array([301, 113]), array([1822, 1401])), (array([301, 206]), array([1822, 1494])), (array([301, 295]), array([1822, 1583])), (array([304,  97]), array([1825, 1385])), (array([304, 598]), array([1825, 1886])), (array([304, 859]), array([1825, 2147])), (array([305, 912]), array([1826, 2200])), (array([306,  70]), array([1827, 1358])), (array([306, 499]), array([1827, 1787])), (array([306, 709]), array([1827, 1997])), (array([306, 820]), array([1827, 2108])), (array([307, 343]), array([1828, 1631])), (array([307, 406]), array([1828, 1694])), (array([307, 452]), array([1828, 1740])), (array([307, 474]), array([1828, 1762])), (array([308, 163]), array([1829, 1451])), (array([308, 233]), array([1828, 1521])), (array([308, 442]), array([1829, 1730])), (array([309,  45]), array([1830, 1333])), (array([309, 146]), array([1830, 1434])), (array([309, 392]), array([1830, 1680])), (array([309, 743]), array([1830, 2031])), (array([310, 731]), array([1831, 2019])), (array([310, 756]), array([1831, 2044])), (array([310, 791]), array([1831, 2079])), (array([311, 430]), array([1832, 1718])), (array([312, 121]), array([1833, 1409])), (array([312, 203]), array([1833, 1491])), (array([315,  85]), array([1836, 1373])), (array([316, 214]), array([1837, 1502])), (array([316, 884]), array([1837, 2172])), (array([318,  62]), array([1839, 1350])), (array([318, 275]), array([1839, 1563])), (array([319,  74]), array([1840, 1362])), (array([319, 838]), array([1840, 2126])), (array([320, 324]), array([1841, 1612])), (array([320, 391]), array([1841, 1679])), (array([320, 922]), array([1841, 2210])), (array([321, 782]), array([1842, 2070])), (array([321, 813]), array([1842, 2101])), (array([322,  37]), array([1843, 1325])), (array([322, 365]), array([1843, 1653])), (array([322, 758]), array([1843, 2046])), (array([322, 904]), array([1843, 2192])), (array([322, 945]), array([1843, 2233])), (array([323, 792]), array([1844, 2080])), (array([324,  12]), array([1845, 1300])), (array([324, 179]), array([1845, 1467])), (array([326, 343]), array([1847, 1631])), (array([327, 261]), array([1848, 1549])), (array([327, 739]), array([1848, 2027])), (array([328, 131]), array([1849, 1419])), (array([329,  76]), array([1850, 1364])), (array([329,  94]), array([1850, 1382])), (array([329, 106]), array([1850, 1394])), (array([329, 142]), array([1850, 1430])), (array([329, 301]), array([1850, 1589])), (array([331, 359]), array([1852, 1647])), (array([331, 768]), array([1852, 2056])), (array([332,  65]), array([1853, 1353])), (array([332, 667]), array([1853, 1955])), (array([333, 805]), array([1854, 2093])), (array([334, 902]), array([1855, 2190])), (array([335, 785]), array([1856, 2073])), (array([337, 408]), array([1858, 1695])), (array([337, 625]), array([1857, 1913])), (array([338, 944]), array([1859, 2232])), (array([339,  23]), array([1860, 1311])), (array([339, 221]), array([1860, 1509])), (array([339, 270]), array([1860, 1558])), (array([340,  35]), array([1861, 1323])), (array([343,  95]), array([1864, 1383])), (array([343, 361]), array([1864, 1649])), (array([343, 712]), array([1864, 2000])), (array([344, 108]), array([1865, 1396])), (array([344, 137]), array([1865, 1425])), (array([344, 432]), array([1865, 1720])), (array([346,  83]), array([1867, 1371])), (array([346, 179]), array([1867, 1467])), (array([347, 831]), array([1868, 2119])), (array([347, 851]), array([1868, 2139])), (array([348, 611]), array([1869, 1899])), (array([349,  59]), array([1870, 1347])), (array([349,  74]), array([1870, 1362])), (array([349, 886]), array([1870, 2174])), (array([350, 817]), array([1871, 2105])), (array([350, 921]), array([1871, 2209])), (array([351, 909]), array([1872, 2197])), (array([351, 933]), array([1872, 2221])), (array([352,  22]), array([1873, 1310])), (array([354, 150]), array([1875, 1438])), (array([356, 308]), array([1877, 1596])), (array([356, 363]), array([1877, 1651])), (array([356, 472]), array([1877, 1760])), (array([357, 119]), array([1878, 1407])), (array([358, 260]), array([1879, 1548])), (array([358, 831]), array([1879, 2119])), (array([359, 851]), array([1880, 2139])), (array([360, 185]), array([1881, 1473])), (array([360, 886]), array([1881, 2174])), (array([361,  85]), array([1882, 1373])), (array([361, 208]), array([1882, 1496])), (array([362, 741]), array([1883, 2030])), (array([363, 374]), array([1884, 1662])), (array([363, 682]), array([1884, 1970])), (array([363, 709]), array([1884, 1997])), (array([363, 874]), array([1884, 2162])), (array([364,  50]), array([1885, 1338])), (array([364,  64]), array([1885, 1352])), (array([364, 336]), array([1885, 1624])), (array([364, 447]), array([1885, 1735])), (array([365,  28]), array([1886, 1316])), (array([365, 432]), array([1886, 1720])), (array([365, 923]), array([1886, 2211])), (array([366, 229]), array([1887, 1517])), (array([366, 936]), array([1887, 2224])), (array([367,  40]), array([1888, 1328])), (array([367, 120]), array([1888, 1408])), (array([367, 792]), array([1888, 2080])), (array([369, 220]), array([1890, 1508])), (array([371,  85]), array([1892, 1373])), (array([371, 839]), array([1892, 2127])), (array([372, 828]), array([1893, 2116])), (array([373, 851]), array([1894, 2139])), (array([374,  76]), array([1895, 1364])), (array([374, 775]), array([1895, 2063])), (array([375, 135]), array([1896, 1423])), (array([375, 564]), array([1896, 1852])), (array([375, 721]), array([1896, 2009])), (array([376,  63]), array([1897, 1351])), (array([376, 203]), array([1897, 1492])), (array([377, 359]), array([1898, 1647])), (array([378,  41]), array([1899, 1329])), (array([378, 450]), array([1899, 1738])), (array([378, 611]), array([1899, 1899])), (array([378, 625]), array([1899, 1913])), (array([379,   7]), array([1900, 1295])), (array([379,  52]), array([1900, 1340])), (array([379, 277]), array([1900, 1565])), (array([380, 349]), array([1902, 1637])), (array([380, 579]), array([1901, 1868])), (array([380, 704]), array([1901, 1992])), (array([380, 864]), array([1901, 2152])), (array([381, 935]), array([1902, 2223])), (array([383,  89]), array([1904, 1377])), (array([383, 787]), array([1904, 2075])), (array([383, 798]), array([1904, 2086])), (array([385, 553]), array([1906, 1840])), (array([386,  65]), array([1907, 1353])), (array([386, 625]), array([1907, 1913])), (array([386, 657]), array([1907, 1945])), (array([388, 263]), array([1909, 1551])), (array([389, 634]), array([1910, 1922])), (array([391, 587]), array([1912, 1875])), (array([392, 360]), array([1913, 1648])), (array([392, 715]), array([1913, 2003])), (array([393, 323]), array([1914, 1611])), (array([393, 735]), array([1914, 2023])), (array([394,  17]), array([1915, 1305])), (array([394, 777]), array([1915, 2065])), (array([395, 516]), array([1916, 1804])), (array([396, 576]), array([1917, 1864])), (array([396, 938]), array([1917, 2226])), (array([397, 746]), array([1918, 2034])), (array([397, 789]), array([1918, 2077])), (array([397, 913]), array([1918, 2201])), (array([398, 209]), array([1919, 1497])), (array([399, 296]), array([1920, 1584])), (array([399, 622]), array([1920, 1910])), (array([399, 665]), array([1920, 1953])), (array([399, 800]), array([1920, 2088])), (array([402, 166]), array([1923, 1454])), (array([402, 343]), array([1923, 1631])), (array([404, 639]), array([1925, 1927])), (array([404, 694]), array([1925, 1982])), (array([405,  43]), array([1926, 1331])), (array([405, 762]), array([1926, 2050])), (array([406, 513]), array([1927, 1801])), (array([407,  20]), array([1928, 1308])), (array([407, 537]), array([1928, 1825])), (array([407, 817]), array([1928, 2105])), (array([408, 911]), array([1929, 2199])), (array([409,  52]), array([1930, 1340])), (array([409, 385]), array([1930, 1673])), (array([409, 703]), array([1930, 1991])), (array([409, 788]), array([1930, 2076])), (array([410, 123]), array([1931, 1411])), (array([410, 313]), array([1931, 1601])), (array([410, 594]), array([1931, 1882])), (array([410, 827]), array([1931, 2115])), (array([411, 895]), array([1932, 2183])), (array([412, 236]), array([1933, 1524])), (array([413, 252]), array([1934, 1540])), (array([414, 392]), array([1935, 1680])), (array([414, 451]), array([1935, 1739])), (array([415, 300]), array([1936, 1588])), (array([416, 180]), array([1937, 1468])), (array([417, 109]), array([1938, 1397])), (array([418, 336]), array([1939, 1624])), (array([418, 626]), array([1939, 1914])), (array([418, 752]), array([1939, 2040])), (array([419, 635]), array([1940, 1923])), (array([420, 367]), array([1941, 1655])), (array([420, 827]), array([1941, 2115])), (array([421, 814]), array([1942, 2102])), (array([421, 849]), array([1942, 2137])), (array([422, 275]), array([1943, 1563])), (array([423, 787]), array([1944, 2075])), (array([423, 860]), array([1944, 2148])), (array([423, 932]), array([1944, 2220])), (array([425, 217]), array([1946, 1505])), (array([426, 895]), array([1947, 2183])), (array([426, 918]), array([1947, 2206])), (array([427, 132]), array([1948, 1420])), (array([428, 947]), array([1949, 2235])), (array([429, 197]), array([1950, 1485])), (array([429, 613]), array([1950, 1901])), (array([429, 716]), array([1950, 2004])), (array([430, 181]), array([1951, 1469])), (array([430, 671]), array([1951, 1959])), (array([431, 598]), array([1952, 1886])), (array([432, 472]), array([1953, 1760])), (array([432, 501]), array([1953, 1789])), (array([434,  48]), array([1955, 1336])), (array([434, 142]), array([1955, 1430])), (array([434, 838]), array([1955, 2126])), (array([435, 646]), array([1956, 1934])), (array([435, 744]), array([1956, 2032])), (array([436, 277]), array([1957, 1565])), (array([437, 222]), array([1958, 1510])), (array([437, 362]), array([1958, 1650])), (array([437, 729]), array([1958, 2017])), (array([437, 917]), array([1958, 2205])), (array([437, 944]), array([1958, 2232])), (array([438, 825]), array([1959, 2113])), (array([439,  75]), array([1960, 1363])), (array([439, 377]), array([1960, 1665])), (array([439, 814]), array([1960, 2102])), (array([439, 853]), array([1960, 2141])), (array([440,  25]), array([1961, 1313])), (array([440, 259]), array([1961, 1547])), (array([441, 632]), array([1962, 1920])), (array([442, 621]), array([1963, 1909])), (array([443,  96]), array([1964, 1384])), (array([444, 153]), array([1965, 1441])), (array([444, 412]), array([1965, 1700])), (array([444, 533]), array([1965, 1821])), (array([447, 719]), array([1968, 2007])), (array([449, 468]), array([1970, 1756])), (array([450, 700]), array([1971, 1988])), (array([450, 751]), array([1971, 2039])), (array([451, 666]), array([1972, 1954])), (array([452, 269]), array([1973, 1557])), (array([453,  99]), array([1974, 1387])), (array([453, 210]), array([1974, 1498])), (array([453, 545]), array([1974, 1833])), (array([453, 654]), array([1974, 1942])), (array([453, 862]), array([1974, 2150])), (array([453, 893]), array([1974, 2181])), (array([453, 905]), array([1974, 2193])), (array([454,  17]), array([1975, 1305])), (array([454, 835]), array([1975, 2123])), (array([454, 872]), array([1975, 2160])), (array([454, 917]), array([1975, 2205])), (array([454, 945]), array([1975, 2233])), (array([455, 371]), array([1976, 1659])), (array([456, 302]), array([1977, 1590])), (array([456, 423]), array([1977, 1711])), (array([457, 624]), array([1978, 1912])), (array([457, 762]), array([1978, 2050])), (array([457, 790]), array([1978, 2078])), (array([460,  52]), array([1981, 1340])), (array([460, 177]), array([1981, 1465])), (array([461, 236]), array([1982, 1524])), (array([462, 121]), array([1983, 1408])), (array([463, 496]), array([1984, 1783])), (array([464, 930]), array([1985, 2218])), (array([465, 655]), array([1986, 1943])), (array([465, 733]), array([1986, 2021])), (array([465, 847]), array([1986, 2135])), (array([467, 159]), array([1988, 1447])), (array([467, 775]), array([1988, 2063])), (array([467, 825]), array([1988, 2113])), (array([468, 272]), array([1989, 1560])), (array([469, 708]), array([1990, 1996])), (array([471, 543]), array([1992, 1831])), (array([472, 691]), array([1993, 1979])), (array([472, 722]), array([1993, 2010])), (array([473,  52]), array([1994, 1340])), (array([473, 467]), array([1994, 1755])), (array([474, 449]), array([1995, 1737])), (array([476, 316]), array([1997, 1604])), (array([476, 737]), array([1997, 2025])), (array([480, 238]), array([2001, 1526])), (array([480, 299]), array([2001, 1587])), (array([480, 908]), array([2001, 2196])), (array([480, 928]), array([2001, 2216])), (array([481, 510]), array([2002, 1798])), (array([481, 865]), array([2002, 2153])), (array([482, 384]), array([2003, 1672])), (array([482, 849]), array([2003, 2137])), (array([483,  39]), array([2004, 1327])), (array([483,  55]), array([2004, 1343])), (array([483, 160]), array([2004, 1448])), (array([484, 666]), array([2005, 1954])), (array([484, 748]), array([2005, 2036])), (array([485, 883]), array([2006, 2171])), (array([486, 212]), array([2007, 1500])), (array([487, 526]), array([2008, 1814])), (array([488,  73]), array([2009, 1361])), (array([488, 775]), array([2009, 2063])), (array([490, 540]), array([2011, 1828])), (array([492, 783]), array([2013, 2071])), (array([493, 105]), array([2014, 1393])), (array([494,  14]), array([2015, 1302])), (array([494, 274]), array([2015, 1562])), (array([494, 685]), array([2015, 1973])), (array([495, 922]), array([2016, 2210])), (array([496, 263]), array([2017, 1551])), (array([497, 900]), array([2018, 2188])), (array([499, 592]), array([2020, 1880])), (array([499, 796]), array([2020, 2084])), (array([500,  32]), array([2021, 1320])), (array([500, 864]), array([2021, 2152])), (array([501, 485]), array([2022, 1773])), (array([501, 813]), array([2022, 2101])), (array([501, 854]), array([2022, 2142])), (array([502, 534]), array([2023, 1822])), (array([502, 657]), array([2023, 1945])), (array([502, 840]), array([2023, 2128])), (array([503,  67]), array([2024, 1355])), (array([503, 146]), array([2024, 1434])), (array([503, 407]), array([2024, 1695])), (array([504, 288]), array([2025, 1576])), (array([505, 419]), array([2026, 1707])), (array([506, 164]), array([2027, 1452])), (array([507,  58]), array([2028, 1346])), (array([507, 901]), array([2028, 2189])), (array([507, 922]), array([2028, 2210])), (array([508, 116]), array([2029, 1404])), (array([508, 675]), array([2029, 1963])), (array([508, 943]), array([2029, 2231])), (array([509, 503]), array([2030, 1791])), (array([512,   7]), array([2033, 1295])), (array([512,  94]), array([2033, 1382])), (array([512, 430]), array([2033, 1718])), (array([513, 884]), array([2034, 2172])), (array([515, 195]), array([2036, 1483])), (array([515, 834]), array([2036, 2122])), (array([516, 441]), array([2037, 1729])), (array([516, 801]), array([2037, 2089])), (array([516, 817]), array([2037, 2105])), (array([517, 702]), array([2038, 1990])), (array([517, 789]), array([2038, 2077])), (array([518, 730]), array([2039, 2018])), (array([518, 945]), array([2039, 2233])), (array([519, 527]), array([2040, 1815])), (array([520, 142]), array([2041, 1430])), (array([520, 416]), array([2041, 1704])), (array([521, 775]), array([2042, 2063])), (array([522,  10]), array([2043, 1298])), (array([523,  46]), array([2044, 1334])), (array([523, 359]), array([2044, 1647])), (array([524, 672]), array([2045, 1960])), (array([524, 761]), array([2045, 2049])), (array([524, 896]), array([2045, 2184])), (array([525, 461]), array([2046, 1749])), (array([525, 885]), array([2046, 2173])), (array([526,  84]), array([2047, 1372])), (array([526, 751]), array([2047, 2039])), (array([527, 132]), array([2048, 1420])), (array([528, 382]), array([2049, 1670])), (array([528, 596]), array([2049, 1884])), (array([529, 434]), array([2050, 1722])), (array([529, 829]), array([2050, 2117])), (array([529, 837]), array([2050, 2125])), (array([531, 115]), array([2052, 1403])), (array([531, 239]), array([2052, 1527])), (array([532, 317]), array([2053, 1605])), (array([532, 534]), array([2053, 1822])), (array([532, 612]), array([2053, 1900])), (array([532, 794]), array([2053, 2082])), (array([533, 254]), array([2054, 1542])), (array([533, 362]), array([2054, 1650])), (array([533, 494]), array([2054, 1782])), (array([534, 348]), array([2055, 1636])), (array([534, 638]), array([2055, 1926])), (array([535,  52]), array([2056, 1340])), (array([535, 279]), array([2056, 1567])), (array([535, 375]), array([2057, 1663])), (array([535, 391]), array([2056, 1679])), (array([535, 671]), array([2056, 1959])), (array([536, 105]), array([2057, 1393])), (array([537, 151]), array([2058, 1439])), (array([537, 744]), array([2058, 2032])), (array([537, 919]), array([2058, 2207])), (array([538, 470]), array([2059, 1758])), (array([539, 129]), array([2061, 1417])), (array([539, 424]), array([2060, 1712])), (array([539, 504]), array([2060, 1792])), (array([539, 776]), array([2060, 2064])), (array([540, 941]), array([2061, 2229])), (array([541, 289]), array([2062, 1577])), (array([542, 699]), array([2063, 1987])), (array([544,  42]), array([2065, 1330])), (array([544, 437]), array([2065, 1725])), (array([545, 252]), array([2066, 1540])), (array([546, 381]), array([2067, 1669])), (array([546, 646]), array([2067, 1934])), (array([550, 371]), array([2071, 1659])), (array([550, 734]), array([2071, 2022])), (array([551,  99]), array([2072, 1387])), (array([551, 780]), array([2072, 2068])), (array([552, 928]), array([2073, 2216])), (array([553,   7]), array([2074, 1295])), (array([553,  25]), array([2074, 1313])), (array([553,  55]), array([2074, 1343])), (array([553, 277]), array([2074, 1565])), (array([553, 433]), array([2074, 1721])), (array([553, 760]), array([2074, 2048])), (array([553, 792]), array([2074, 2080])), (array([554, 712]), array([2075, 2000])), (array([554, 827]), array([2075, 2115])), (array([555, 600]), array([2076, 1888])), (array([555, 892]), array([2076, 2180])), (array([556, 213]), array([2077, 1501])), (array([556, 682]), array([2077, 1970])), (array([556, 860]), array([2077, 2148])), (array([558,  67]), array([2079, 1355])), (array([558,  76]), array([2079, 1364])), (array([558, 140]), array([2079, 1428])), (array([558, 175]), array([2079, 1463])), (array([558, 363]), array([2079, 1651])), (array([558, 466]), array([2079, 1754])), (array([559, 938]), array([2080, 2226])), (array([560, 251]), array([2081, 1539])), (array([561, 639]), array([2082, 1927])), (array([562,  32]), array([2083, 1320])), (array([563, 747]), array([2084, 2035])), (array([563, 821]), array([2084, 2109])), (array([564, 422]), array([2085, 1710])), (array([564, 774]), array([2085, 2062])), (array([565,  11]), array([2086, 1299])), (array([566, 786]), array([2087, 2074])), (array([566, 797]), array([2087, 2085])), (array([566, 913]), array([2087, 2201])), (array([567, 227]), array([2088, 1515])), (array([568, 621]), array([2089, 1909])), (array([568, 701]), array([2089, 1989])), (array([569,  95]), array([2090, 1383])), (array([569, 298]), array([2090, 1586])), (array([569, 837]), array([2090, 2125])), (array([570, 349]), array([2091, 1637])), (array([570, 901]), array([2091, 2189])), (array([571, 193]), array([2092, 1482])), (array([572,  68]), array([2093, 1356])), (array([572, 258]), array([2093, 1546])), (array([574,  52]), array([2095, 1340])), (array([574, 604]), array([2095, 1892])), (array([575, 763]), array([2096, 2051])), (array([575, 929]), array([2096, 2217])), (array([576, 405]), array([2097, 1693])), (array([576, 666]), array([2097, 1954])), (array([577, 711]), array([2098, 1999])), (array([577, 724]), array([2098, 2012])), (array([577, 738]), array([2098, 2026])), (array([578,  19]), array([2099, 1307])), (array([578, 445]), array([2099, 1733])), (array([579,  43]), array([2100, 1331])), (array([580, 416]), array([2101, 1704])), (array([580, 886]), array([2101, 2174])), (array([581, 300]), array([2102, 1588])), (array([581, 361]), array([2102, 1648])), (array([581, 837]), array([2102, 2125])), (array([581, 904]), array([2102, 2192])), (array([582,   7]), array([2103, 1295])), (array([582, 849]), array([2103, 2137])), (array([582, 866]), array([2103, 2154])), (array([583,  95]), array([2104, 1383])), (array([585, 813]), array([2106, 2101])), (array([586, 625]), array([2107, 1913])), (array([587, 174]), array([2108, 1462])), (array([588,  55]), array([2109, 1343])), (array([588,  67]), array([2109, 1355])), (array([590,  45]), array([2111, 1333])), (array([590, 452]), array([2111, 1740])), (array([590, 751]), array([2111, 2039])), (array([590, 788]), array([2111, 2076])), (array([591, 108]), array([2112, 1396])), (array([591, 723]), array([2112, 2011])), (array([591, 738]), array([2112, 2026])), (array([592, 388]), array([2113, 1676])), (array([592, 465]), array([2113, 1753])), (array([592, 664]), array([2113, 1952])), (array([593, 939]), array([2114, 2227])), (array([594,  33]), array([2115, 1321])), (array([594, 712]), array([2115, 2000])), (array([594, 903]), array([2115, 2191])), (array([594, 922]), array([2115, 2210])), (array([595, 699]), array([2116, 1987])), (array([596,   8]), array([2117, 1296])), (array([596,  23]), array([2117, 1311])), (array([596,  97]), array([2117, 1385])), (array([596, 293]), array([2117, 1581])), (array([596, 587]), array([2117, 1875])), (array([597, 613]), array([2117, 1901])), (array([598,  83]), array([2119, 1371])), (array([598, 831]), array([2119, 2119])), (array([599,  70]), array([2120, 1358])), (array([599, 631]), array([2120, 1919])), (array([600, 121]), array([2121, 1409])), (array([600, 862]), array([2121, 2150])), (array([601,  58]), array([2122, 1346])), (array([601, 801]), array([2122, 2089])), (array([603,  50]), array([2124, 1338])), (array([603, 650]), array([2124, 1938])), (array([604, 267]), array([2125, 1555])), (array([606, 722]), array([2127, 2010])), (array([606, 735]), array([2127, 2023])), (array([607,  24]), array([2128, 1312])), (array([607, 416]), array([2128, 1704])), (array([608, 304]), array([2129, 1592])), (array([608, 766]), array([2129, 2054])), (array([609,   9]), array([2130, 1297])), (array([609,  38]), array([2130, 1326])), (array([611, 625]), array([2132, 1913])), (array([611, 835]), array([2132, 2123])), (array([611, 888]), array([2132, 2176])), (array([613, 597]), array([2134, 1885])), (array([613, 804]), array([2134, 2092])), (array([613, 821]), array([2134, 2109])), (array([614, 133]), array([2135, 1421])), (array([615, 234]), array([2136, 1522])), (array([615, 264]), array([2136, 1552])), (array([615, 692]), array([2136, 1980])), (array([616, 439]), array([2137, 1727])), (array([617, 733]), array([2138, 2021])), (array([617, 778]), array([2138, 2066])), (array([618, 792]), array([2139, 2080])), (array([619,  51]), array([2140, 1339])), (array([620, 102]), array([2141, 1390])), (array([622, 710]), array([2143, 1998])), (array([622, 937]), array([2143, 2225])), (array([623, 189]), array([2145, 1477])), (array([623, 835]), array([2144, 2123])), (array([624, 360]), array([2145, 1648])), (array([625, 152]), array([2146, 1440])), (array([625, 163]), array([2146, 1451])), (array([625, 176]), array([2146, 1464])), (array([625, 201]), array([2146, 1489])), (array([625, 543]), array([2146, 1831])), (array([626, 301]), array([2147, 1589])), (array([627, 821]), array([2148, 2109])), (array([627, 884]), array([2148, 2172])), (array([628, 409]), array([2150, 1697])), (array([628, 899]), array([2149, 2187])), (array([629, 631]), array([2150, 1919])), (array([630,  82]), array([2151, 1370])), (array([630, 231]), array([2151, 1519])), (array([630, 726]), array([2151, 2014])), (array([631,  59]), array([2152, 1347])), (array([631, 249]), array([2152, 1537])), (array([633, 377]), array([2154, 1665])), (array([633, 751]), array([2154, 2039])), (array([633, 929]), array([2154, 2217])), (array([634, 138]), array([2155, 1426])), (array([634, 699]), array([2155, 1987])), (array([634, 772]), array([2155, 2060])), (array([634, 798]), array([2155, 2086])), (array([634, 914]), array([2155, 2202])), (array([635, 535]), array([2156, 1823])), (array([635, 759]), array([2156, 2047])), (array([636,  46]), array([2157, 1334])), (array([636, 271]), array([2157, 1559])), (array([636, 315]), array([2157, 1603])), (array([636, 850]), array([2157, 2138])), (array([636, 870]), array([2157, 2158])), (array([637,  34]), array([2158, 1322])), (array([637, 621]), array([2158, 1909])), (array([639,  22]), array([2160, 1310])), (array([639,  96]), array([2160, 1384])), (array([639, 111]), array([2160, 1399])), (array([639, 281]), array([2160, 1569])), (array([641,  11]), array([2162, 1299])), (array([641, 191]), array([2162, 1479])), (array([641, 738]), array([2162, 2026])), (array([642,  59]), array([2163, 1347])), (array([642, 157]), array([2163, 1445])), (array([642, 179]), array([2163, 1467])), (array([642, 810]), array([2163, 2098])), (array([643, 673]), array([2164, 1961])), (array([643, 725]), array([2164, 2013])), (array([644, 653]), array([2165, 1941])), (array([645,  50]), array([2166, 1338])), (array([646, 776]), array([2167, 2064])), (array([647, 796]), array([2168, 2084])), (array([649, 822]), array([2170, 2110])), (array([649, 850]), array([2170, 2138])), (array([650, 130]), array([2171, 1418])), (array([650, 839]), array([2171, 2127])), (array([650, 937]), array([2171, 2225])), (array([651,  69]), array([2172, 1357])), (array([651, 318]), array([2173, 1606])), (array([652,  11]), array([2173, 1299])), (array([653,  23]), array([2174, 1311])), (array([653, 308]), array([2174, 1596])), (array([653, 897]), array([2174, 2185])), (array([654,  31]), array([2175, 1319])), (array([654, 168]), array([2175, 1456])), (array([656,  95]), array([2177, 1383])), (array([656, 751]), array([2177, 2039])), (array([656, 771]), array([2177, 2059])), (array([657, 215]), array([2178, 1503])), (array([658, 229]), array([2179, 1517])), (array([658, 738]), array([2179, 2026])), (array([658, 799]), array([2179, 2087])), (array([659, 106]), array([2180, 1394])), (array([660, 619]), array([2181, 1907])), (array([661, 714]), array([2182, 2002])), (array([662, 811]), array([2183, 2099])), (array([663,  55]), array([2184, 1343])), (array([663, 576]), array([2184, 1864])), (array([664, 885]), array([2185, 2173])), (array([664, 896]), array([2185, 2184])), (array([664, 936]), array([2185, 2224])), (array([665, 387]), array([2186, 1675])), (array([666, 161]), array([2187, 1449])), (array([667,  39]), array([2188, 1327])), (array([668, 286]), array([2189, 1574])), (array([668, 665]), array([2189, 1953])), (array([669, 137]), array([2190, 1425])), (array([669, 185]), array([2190, 1473])), (array([669, 329]), array([2190, 1617])), (array([669, 748]), array([2190, 2036])), (array([670, 652]), array([2191, 1940])), (array([672, 311]), array([2193, 1599])), (array([672, 691]), array([2193, 1979])), (array([672, 706]), array([2193, 1994])), (array([672, 809]), array([2193, 2097])), (array([673, 223]), array([2194, 1511])), (array([674,  12]), array([2195, 1300])), (array([674, 622]), array([2195, 1910])), (array([674, 635]), array([2196, 1923])), (array([675, 798]), array([2196, 2086])), (array([675, 923]), array([2196, 2211])), (array([676, 246]), array([2197, 1534])), (array([677, 321]), array([2198, 1609])), (array([677, 570]), array([2198, 1858])), (array([677, 832]), array([2198, 2120])), (array([678,  30]), array([2199, 1318])), (array([678,  52]), array([2199, 1340])), (array([679,  38]), array([2200, 1326])), (array([679,  62]), array([2200, 1350])), (array([679, 107]), array([2200, 1395])), (array([680, 732]), array([2201, 2020])), (array([680, 902]), array([2201, 2190])), (array([681,  87]), array([2202, 1375])), (array([681, 126]), array([2202, 1414])), (array([681, 611]), array([2202, 1899])), (array([682, 209]), array([2203, 1497])), (array([682, 222]), array([2203, 1510])), (array([684, 851]), array([2205, 2139])), (array([686, 722]), array([2207, 2010])), (array([686, 837]), array([2207, 2125])), (array([687, 310]), array([2208, 1598])), (array([687, 753]), array([2208, 2041])), (array([689, 379]), array([2210, 1667])), (array([690,  54]), array([2211, 1342])), (array([690,  87]), array([2211, 1375])), (array([690, 813]), array([2211, 2101])), (array([691, 168]), array([2212, 1456])), (array([691, 593]), array([2212, 1881])), (array([692, 103]), array([2213, 1391])), (array([692, 774]), array([2213, 2062])), (array([693,  43]), array([2214, 1331])), (array([693,  64]), array([2214, 1352])), (array([693, 278]), array([2214, 1566])), (array([693, 822]), array([2214, 2110])), (array([694, 624]), array([2214, 1912])), (array([695,  30]), array([2216, 1318])), (array([696,  18]), array([2217, 1306])), (array([696, 881]), array([2217, 2169])), (array([697, 134]), array([2218, 1422])), (array([698, 225]), array([2219, 1513])), (array([698, 754]), array([2219, 2042])), (array([699, 192]), array([2220, 1480])), (array([700, 668]), array([2221, 1956])), (array([700, 720]), array([2221, 2008])), (array([701, 394]), array([2222, 1682])), (array([701, 844]), array([2222, 2132])), (array([702, 240]), array([2223, 1528])), (array([704, 110]), array([2225, 1398])), (array([705,  49]), array([2226, 1337])), (array([705, 645]), array([2226, 1933])), (array([705, 895]), array([2226, 2183])), (array([706,  72]), array([2227, 1360])), (array([707,  96]), array([2228, 1384])), (array([707, 147]), array([2228, 1435])), (array([707, 812]), array([2228, 2100])), (array([707, 825]), array([2228, 2113])), (array([708, 310]), array([2229, 1598])), (array([708, 336]), array([2229, 1624])), (array([709, 125]), array([2230, 1413])), (array([709, 757]), array([2230, 2045])), (array([710,  19]), array([2231, 1307])), (array([711, 158]), array([2232, 1446])), (array([711, 209]), array([2232, 1497])), (array([711, 722]), array([2232, 2010])), (array([712, 172]), array([2233, 1460])), (array([712, 221]), array([2233, 1509])), (array([713, 252]), array([2234, 1540])), (array([713, 563]), array([2234, 1851])), (array([713, 693]), array([2234, 1981])), (array([713, 925]), array([2234, 2213])), (array([713, 939]), array([2234, 2227])), (array([715, 295]), array([2236, 1583])), (array([716, 778]), array([2236, 2066])), (array([716, 797]), array([2237, 2085])), (array([716, 826]), array([2237, 2114])), (array([717, 115]), array([2238, 1403])), (array([719,  62]), array([2240, 1350])), (array([720,  51]), array([2241, 1339])), (array([720,  74]), array([2241, 1362])), (array([720, 133]), array([2241, 1421])), (array([720, 854]), array([2241, 2142])), (array([721, 911]), array([2242, 2199])), (array([724, 160]), array([2245, 1448])), (array([724, 212]), array([2245, 1500])), (array([724, 253]), array([2245, 1541])), (array([724, 567]), array([2245, 1855])), (array([726, 235]), array([2247, 1523])), (array([726, 600]), array([2247, 1888])), (array([726, 633]), array([2247, 1921])), (array([728, 299]), array([2249, 1587])), (array([728, 817]), array([2249, 2105])), (array([730, 723]), array([2251, 2011])), (array([730, 833]), array([2251, 2120])), (array([731, 925]), array([2252, 2213])), (array([732, 107]), array([2253, 1395])), (array([732, 910]), array([2253, 2198])), (array([733,  40]), array([2254, 1328])), (array([733,  51]), array([2254, 1339])), (array([733,  93]), array([2254, 1381])), (array([733, 126]), array([2254, 1414])), (array([734, 147]), array([2255, 1435])), (array([735, 882]), array([2256, 2170])), (array([736, 169]), array([2257, 1457])), (array([736, 368]), array([2257, 1656])), (array([737, 264]), array([2258, 1552])), (array([737, 627]), array([2258, 1915])), (array([738,  12]), array([2259, 1300])), (array([738, 193]), array([2259, 1481])), (array([738, 218]), array([2259, 1506])), (array([738, 340]), array([2259, 1628])), (array([738, 679]), array([2259, 1967])), (array([739, 204]), array([2260, 1492])), (array([741, 240]), array([2262, 1528])), (array([742, 578]), array([2263, 1866])), (array([743,  59]), array([2264, 1347])), (array([743, 815]), array([2264, 2103])), (array([743, 941]), array([2264, 2229])), (array([744, 117]), array([2265, 1405])), (array([744, 773]), array([2265, 2061])), (array([744, 831]), array([2265, 2119])), (array([745,  73]), array([2266, 1361])), (array([745, 925]), array([2266, 2213])), (array([746, 515]), array([2267, 1803])), (array([746, 875]), array([2267, 2163])), (array([747,  95]), array([2268, 1383])), (array([747, 912]), array([2268, 2200])), (array([748, 129]), array([2269, 1417])), (array([748, 274]), array([2269, 1562])), (array([748, 549]), array([2269, 1837])), (array([749, 160]), array([2270, 1448])), (array([749, 356]), array([2270, 1644])), (array([750, 336]), array([2271, 1624])), (array([750, 718]), array([2271, 2006])), (array([750, 897]), array([2271, 2185])), (array([751, 174]), array([2272, 1462])), (array([752, 195]), array([2273, 1483])), (array([752, 604]), array([2273, 1892])), (array([753, 288]), array([2274, 1576])), (array([753, 565]), array([2274, 1853])), (array([754, 226]), array([2275, 1514])), (array([754, 252]), array([2275, 1540])), (array([755, 239]), array([2276, 1527])), (array([755, 926]), array([2276, 2214])), (array([756,  16]), array([2277, 1304])), (array([756, 813]), array([2277, 2101])), (array([756, 940]), array([2277, 2228])), (array([757,  33]), array([2278, 1321])), (array([757,  54]), array([2278, 1342])), (array([759, 362]), array([2280, 1650])), (array([759, 589]), array([2280, 1877])), (array([759, 829]), array([2280, 2117])), (array([760, 623]), array([2281, 1911])), (array([761,  89]), array([2282, 1377])), (array([761, 129]), array([2282, 1417])), (array([761, 266]), array([2282, 1554])), (array([761, 333]), array([2282, 1621])), (array([762, 160]), array([2283, 1448])), (array([764, 253]), array([2285, 1541])), (array([764, 659]), array([2285, 1947])), (array([766, 177]), array([2287, 1465])), (array([767, 763]), array([2289, 2051])), (array([767, 814]), array([2288, 2102])), (array([768, 295]), array([2289, 1583])), (array([768, 858]), array([2289, 2146])), (array([768, 901]), array([2289, 2189])), (array([768, 942]), array([2289, 2230])), (array([769, 887]), array([2290, 2175])), (array([770,  57]), array([2291, 1345])), (array([770, 841]), array([2291, 2129])), (array([771,  32]), array([2292, 1320])), (array([771, 103]), array([2292, 1391])), (array([771, 225]), array([2292, 1513])), (array([771, 927]), array([2292, 2215])), (array([772,  15]), array([2293, 1303])), (array([772, 352]), array([2293, 1640])), (array([772, 363]), array([2293, 1651])), (array([773, 159]), array([2294, 1447])), (array([773, 317]), array([2294, 1605])), (array([773, 617]), array([2295, 1905])), (array([773, 744]), array([2294, 2032])), (array([775, 235]), array([2296, 1523])), (array([776, 177]), array([2297, 1465])), (array([776, 562]), array([2297, 1850])), (array([776, 801]), array([2297, 2089])), (array([777, 134]), array([2298, 1422])), (array([781, 207]), array([2303, 1495])), (array([781, 294]), array([2302, 1582])), (array([781, 728]), array([2302, 2016])), (array([781, 892]), array([2302, 2180])), (array([782, 918]), array([2303, 2206])), (array([783, 322]), array([2304, 1610])), (array([783, 333]), array([2304, 1621])), (array([783, 412]), array([2304, 1700])), (array([784,  16]), array([2305, 1304])), (array([784,  29]), array([2305, 1317])), (array([784, 677]), array([2305, 1965])), (array([785,  98]), array([2306, 1386])), (array([786, 109]), array([2307, 1397])), (array([786, 426]), array([2307, 1714])), (array([786, 688]), array([2307, 1976])), (array([787,  62]), array([2308, 1350])), (array([787,  72]), array([2308, 1360])), (array([787,  83]), array([2308, 1371])), (array([788, 642]), array([2309, 1930])), (array([789, 143]), array([2310, 1431])), (array([790, 158]), array([2311, 1446])), (array([790, 905]), array([2311, 2193])), (array([791, 573]), array([2312, 1861])), (array([791, 770]), array([2312, 2058])), (array([792, 168]), array([2313, 1456])), (array([792, 553]), array([2313, 1841])), (array([792, 714]), array([2313, 2002])), (array([794, 522]), array([2315, 1810])), (array([795, 650]), array([2316, 1938])), (array([796, 331]), array([2317, 1619])), (array([797,   5]), array([2318, 1293])), (array([797,  41]), array([2318, 1329])), (array([798, 364]), array([2319, 1652])), (array([799, 315]), array([2320, 1603])), (array([799, 391]), array([2320, 1679])), (array([800,  60]), array([2321, 1348])), (array([800,  84]), array([2321, 1372])), (array([800, 106]), array([2321, 1394])), (array([801, 121]), array([2322, 1409])), (array([801, 884]), array([2322, 2172])), (array([802, 134]), array([2323, 1422])), (array([802, 802]), array([2323, 2090])), (array([802, 923]), array([2323, 2211])), (array([803, 157]), array([2324, 1445])), (array([803, 543]), array([2324, 1831])), (array([803, 859]), array([2324, 2147])), (array([804, 142]), array([2325, 1430])), (array([804, 870]), array([2325, 2158])), (array([805, 244]), array([2326, 1532])), (array([805, 408]), array([2326, 1696])), (array([805, 434]), array([2326, 1723])), (array([806, 586]), array([2327, 1874])), (array([807, 266]), array([2328, 1554])), (array([807, 288]), array([2328, 1576])), (array([807, 483]), array([2328, 1771])), (array([808, 785]), array([2329, 2073])), (array([809, 447]), array([2330, 1735])), (array([809, 716]), array([2330, 2004])), (array([811,  21]), array([2332, 1309])), (array([811, 500]), array([2332, 1788])), (array([811, 612]), array([2332, 1900])), (array([811, 755]), array([2332, 2043])), (array([812,  73]), array([2333, 1361])), (array([812, 120]), array([2333, 1408])), (array([813,  83]), array([2334, 1371])), (array([813,  97]), array([2334, 1385])), (array([813, 207]), array([2334, 1495])), (array([813, 641]), array([2334, 1929])), (array([813, 656]), array([2334, 1944])), (array([813, 724]), array([2334, 2012])), (array([813, 801]), array([2334, 2089])), (array([813, 942]), array([2334, 2230])), (array([814,  53]), array([2335, 1341])), (array([814, 840]), array([2335, 2128])), (array([816, 697]), array([2337, 1985])), (array([818, 163]), array([2339, 1451])), (array([818, 309]), array([2339, 1597])), (array([818, 430]), array([2339, 1718])), (array([819, 183]), array([2340, 1471])), (array([820, 358]), array([2341, 1646])), (array([821, 588]), array([2341, 1876])), (array([821, 778]), array([2342, 2066])), (array([821, 815]), array([2342, 2103])), (array([823, 287]), array([2344, 1575])), (array([825,  13]), array([2346, 1301])), (array([825,  36]), array([2346, 1324])), (array([825, 653]), array([2346, 1941])), (array([825, 726]), array([2346, 2014])), (array([827, 103]), array([2348, 1391])), (array([827, 204]), array([2348, 1492])), (array([827, 668]), array([2348, 1956])), (array([829,  26]), array([2350, 1314])), (array([829, 800]), array([2350, 2089])), (array([830,  66]), array([2351, 1354])), (array([830, 116]), array([2351, 1404])), (array([830, 139]), array([2351, 1427])), (array([831,  81]), array([2352, 1369])), (array([832, 385]), array([2353, 1673])), (array([832, 844]), array([2353, 2132])), (array([832, 907]), array([2353, 2195])), (array([832, 940]), array([2353, 2228])), (array([833, 155]), array([2354, 1443])), (array([833, 258]), array([2354, 1546])), (array([834, 352]), array([2355, 1640])), (array([835, 525]), array([2356, 1813])), (array([836, 207]), array([2357, 1495])), (array([836, 587]), array([2357, 1875])), (array([839, 824]), array([2360, 2112])), (array([840, 678]), array([2361, 1966])), (array([841,  12]), array([2362, 1300])), (array([841, 409]), array([2362, 1697])), (array([841, 689]), array([2362, 1977])), (array([842,  25]), array([2363, 1313])), (array([842,  82]), array([2363, 1370])), (array([842, 103]), array([2363, 1391])), (array([842, 163]), array([2363, 1451])), (array([842, 569]), array([2363, 1857])), (array([843,  46]), array([2364, 1334])), (array([843, 770]), array([2364, 2058])), (array([844, 125]), array([2365, 1413])), (array([844, 149]), array([2365, 1437])), (array([844, 706]), array([2365, 1994])), (array([845,  68]), array([2366, 1356])), (array([845, 601]), array([2366, 1889])), (array([846, 173]), array([2367, 1461])), (array([847, 185]), array([2368, 1473])), (array([847, 287]), array([2368, 1575])), (array([849, 791]), array([2370, 2079])), (array([850, 538]), array([2371, 1826])), (array([851, 588]), array([2372, 1876])), (array([853, 226]), array([2374, 1514])), (array([853, 333]), array([2374, 1621])), (array([854,  36]), array([2375, 1324])), (array([854, 651]), array([2375, 1940])), (array([854, 667]), array([2375, 1955])), (array([854, 948]), array([2375, 2236])), (array([855,  58]), array([2376, 1346])), (array([856,  10]), array([2377, 1298])), (array([856,  29]), array([2377, 1317])), (array([856,  91]), array([2377, 1379])), (array([857,  48]), array([2378, 1336])), (array([857, 105]), array([2378, 1393])), (array([859, 134]), array([2380, 1422])), (array([859, 177]), array([2380, 1465])), (array([859, 890]), array([2380, 2178])), (array([860, 156]), array([2381, 1444])), (array([860, 570]), array([2381, 1858])), (array([860, 780]), array([2381, 2068])), (array([862, 311]), array([2383, 1599])), (array([863, 452]), array([2384, 1740])), (array([865, 670]), array([2386, 1958])), (array([865, 692]), array([2386, 1980])), (array([865, 865]), array([2386, 2153])), (array([866, 237]), array([2387, 1525])), (array([867, 682]), array([2388, 1970])), (array([868, 297]), array([2389, 1585])), (array([870,   4]), array([2391, 1292])), (array([870,  94]), array([2391, 1382])), (array([870, 106]), array([2391, 1394])), (array([870, 116]), array([2391, 1404])), (array([870, 546]), array([2391, 1834])), (array([871,  19]), array([2392, 1307])), (array([871,  51]), array([2392, 1339])), (array([871, 405]), array([2392, 1693])), (array([871, 756]), array([2392, 2044])), (array([872, 267]), array([2393, 1555])), (array([872, 348]), array([2393, 1636])), (array([872, 767]), array([2393, 2055])), (array([873,  33]), array([2394, 1321])), (array([873, 216]), array([2394, 1504])), (array([874, 881]), array([2395, 2169])), (array([877, 694]), array([2398, 1982])), (array([877, 744]), array([2398, 2032])), (array([879, 794]), array([2400, 2082])), (array([880, 387]), array([2401, 1675])), (array([880, 597]), array([2401, 1885])), (array([881, 519]), array([2402, 1807])), (array([881, 636]), array([2402, 1924])), (array([883, 139]), array([2404, 1427])), (array([883, 149]), array([2404, 1437])), (array([883, 926]), array([2404, 2214])), (array([884, 108]), array([2405, 1396])), (array([884, 331]), array([2405, 1619])), (array([884, 754]), array([2405, 2042])), (array([885,  10]), array([2406, 1298])), (array([885,  31]), array([2406, 1319])), (array([885,  45]), array([2406, 1333])), (array([885,  83]), array([2406, 1371])), (array([885, 252]), array([2406, 1540])), (array([885, 874]), array([2406, 2162])), (array([886,  70]), array([2407, 1358])), (array([886,  97]), array([2407, 1385])), (array([886, 175]), array([2407, 1463])), (array([886, 238]), array([2407, 1526])), (array([886, 309]), array([2408, 1597])), (array([886, 435]), array([2407, 1723])), (array([888, 411]), array([2409, 1699])), (array([890, 196]), array([2411, 1484])), (array([891, 645]), array([2412, 1933])), (array([891, 679]), array([2412, 1967])), (array([892, 549]), array([2413, 1837])), (array([893, 388]), array([2414, 1676])), (array([893, 765]), array([2414, 2053])), (array([894, 567]), array([2416, 1855])), (array([894, 841]), array([2415, 2129])), (array([895, 362]), array([2416, 1650])), (array([896, 716]), array([2417, 2004])), (array([897, 460]), array([2418, 1748])), (array([898,  83]), array([2419, 1371])), (array([898, 500]), array([2419, 1788])), (array([898, 728]), array([2419, 2016])), (array([899, 853]), array([2420, 2141])), (array([900,  63]), array([2421, 1351])), (array([900,  97]), array([2421, 1385])), (array([900, 276]), array([2421, 1564])), (array([900, 298]), array([2421, 1586])), (array([900, 698]), array([2421, 1986])), (array([900, 789]), array([2421, 2077])), (array([901,  31]), array([2422, 1319])), (array([901,  43]), array([2422, 1331])), (array([901, 909]), array([2422, 2197])), (array([902, 330]), array([2423, 1618])), (array([902, 626]), array([2422, 1914])), (array([903, 108]), array([2424, 1396])), (array([904, 415]), array([2425, 1703])), (array([904, 584]), array([2425, 1872])), (array([904, 666]), array([2426, 1954])), (array([904, 877]), array([2425, 2165])), (array([906, 173]), array([2427, 1462])), (array([907, 441]), array([2428, 1729])), (array([909, 374]), array([2430, 1662])), (array([909, 504]), array([2430, 1792])), (array([910, 549]), array([2431, 1837])), (array([910, 854]), array([2431, 2142])), (array([911,   5]), array([2432, 1293])), (array([911, 403]), array([2432, 1691])), (array([911, 488]), array([2432, 1776])), (array([912,  29]), array([2433, 1317])), (array([913,  95]), array([2434, 1383])), (array([914, 591]), array([2435, 1879])), (array([916,  45]), array([2437, 1333])), (array([916,  77]), array([2437, 1365])), (array([916, 812]), array([2437, 2100])), (array([917, 225]), array([2438, 1513])), (array([917, 295]), array([2438, 1583])), (array([918, 871]), array([2439, 2159])), (array([919, 265]), array([2440, 1553])), (array([919, 351]), array([2440, 1640])), (array([920, 781]), array([2441, 2069])), (array([920, 840]), array([2441, 2128])), (array([921, 236]), array([2442, 1524])), (array([923, 170]), array([2444, 1458])), (array([925,  23]), array([2446, 1311])), (array([925, 145]), array([2446, 1433])), (array([925, 675]), array([2446, 1963])), (array([925, 753]), array([2446, 2041])), (array([926,  46]), array([2447, 1334])), (array([926, 250]), array([2447, 1538])), (array([927, 814]), array([2448, 2102])), (array([928,  32]), array([2449, 1320])), (array([929, 448]), array([2450, 1736])), (array([930, 870]), array([2451, 2158])), (array([931,  83]), array([2452, 1371])), (array([931, 634]), array([2452, 1922])), (array([931, 830]), array([2452, 2118])), (array([932,  96]), array([2453, 1384])), (array([932, 289]), array([2453, 1576])), (array([932, 371]), array([2453, 1659])), (array([932, 565]), array([2453, 1853])), (array([933, 735]), array([2454, 2023])), (array([934,  60]), array([2455, 1348])), (array([934, 209]), array([2455, 1497])), (array([934, 473]), array([2455, 1761])), (array([936, 396]), array([2457, 1684])), (array([936, 909]), array([2457, 2197])), (array([937, 246]), array([2458, 1534])), (array([937, 409]), array([2458, 1697])), (array([937, 504]), array([2458, 1792])), (array([937, 783]), array([2458, 2071])), (array([938, 226]), array([2459, 1514])), (array([939, 270]), array([2459, 1558])), (array([940, 819]), array([2461, 2107])), (array([940, 839]), array([2461, 2127])), (array([940, 883]), array([2461, 2171])), (array([940, 937]), array([2461, 2225])), (array([941, 640]), array([2462, 1928])), (array([941, 859]), array([2462, 2147])), (array([942, 832]), array([2463, 2120])), (array([942, 896]), array([2463, 2184])), (array([943,  35]), array([2464, 1323])), (array([943, 341]), array([2464, 1629])), (array([943, 442]), array([2464, 1730])), (array([944,  82]), array([2465, 1370])), (array([947, 545]), array([2468, 1833])), (array([948, 255]), array([2469, 1543])), (array([948, 288]), array([2469, 1576])), (array([948, 431]), array([2469, 1719])), (array([948, 913]), array([2470, 2201])), (array([949, 199]), array([2471, 1487])), (array([949, 517]), array([2470, 1805])), (array([949, 870]), array([2470, 2158])), (array([950, 170]), array([2471, 1458])), (array([950, 818]), array([2471, 2106])), (array([951, 221]), array([2472, 1509])), (array([951, 697]), array([2472, 1985])), (array([952, 493]), array([2474, 1781])), (array([952, 925]), array([2473, 2213])), (array([953, 301]), array([2474, 1588])), (array([953, 660]), array([2474, 1948])), (array([954, 730]), array([2475, 2018])), (array([955, 320]), array([2476, 1608])), (array([955, 468]), array([2476, 1756])), (array([956,   4]), array([2477, 1292])), (array([956,  40]), array([2477, 1328])), (array([957, 348]), array([2478, 1636])), (array([957, 454]), array([2478, 1742])), (array([958,  17]), array([2479, 1305])), (array([958,  61]), array([2479, 1349])), (array([958, 574]), array([2479, 1862])), (array([958, 648]), array([2479, 1936])), (array([960,  88]), array([2481, 1376])), (array([960, 899]), array([2481, 2187])), (array([961, 597]), array([2481, 1885])), (array([961, 670]), array([2482, 1958])), (array([962, 281]), array([2483, 1569])), (array([962, 559]), array([2483, 1847])), (array([962, 818]), array([2483, 2106])), (array([962, 885]), array([2483, 2173])), (array([964, 710]), array([2485, 1998])), (array([964, 794]), array([2485, 2082])), (array([967, 340]), array([2488, 1628])), (array([967, 359]), array([2488, 1647])), (array([968, 921]), array([2489, 2209])), (array([969, 217]), array([2490, 1505])), (array([969, 871]), array([2490, 2159])), (array([970,   4]), array([2491, 1292])), (array([970, 369]), array([2491, 1657])), (array([970, 695]), array([2491, 1983])), (array([971,  29]), array([2492, 1317])), (array([971,  75]), array([2492, 1363])), (array([971, 111]), array([2492, 1399])), (array([972,  44]), array([2493, 1332])), (array([972, 409]), array([2493, 1697])), (array([972, 498]), array([2493, 1786])), (array([973, 239]), array([2494, 1528])), (array([973, 558]), array([2494, 1846])), (array([974, 281]), array([2495, 1569])), (array([974, 721]), array([2495, 2009])), (array([974, 819]), array([2495, 2107])), (array([975, 570]), array([2496, 1858])), (array([975, 642]), array([2496, 1930])), (array([976, 859]), array([2497, 2147])), (array([976, 905]), array([2497, 2193])), (array([977, 887]), array([2498, 2175])), (array([978, 424]), array([2499, 1712])), (array([978, 586]), array([2499, 1874])), (array([978, 665]), array([2499, 1953])), (array([979, 155]), array([2501, 1443])), (array([979, 266]), array([2500, 1554])), (array([979, 632]), array([2500, 1920])), (array([980, 295]), array([2501, 1583])), (array([981,  45]), array([2502, 1333])), (array([981, 382]), array([2502, 1670])), (array([981, 468]), array([2502, 1756])), (array([983, 285]), array([2504, 1573])), (array([984, 177]), array([2506, 1465])), (array([984, 329]), array([2505, 1617])), (array([985,  19]), array([2506, 1307])), (array([985, 820]), array([2506, 2108])), (array([986, 313]), array([2507, 1601])), (array([986, 483]), array([2507, 1771])), (array([986, 705]), array([2507, 1993])), (array([987, 445]), array([2508, 1734])), (array([987, 644]), array([2508, 1932])), (array([987, 871]), array([2508, 2159])), (array([988, 410]), array([2509, 1698])), (array([988, 885]), array([2509, 2173])), (array([990, 799]), array([2511, 2087])), (array([991, 631]), array([2512, 1919])), (array([991, 834]), array([2512, 2122])), (array([992, 532]), array([2513, 1820])), (array([994, 371]), array([2515, 1659])), (array([994, 469]), array([2515, 1757])), (array([994, 512]), array([2515, 1800])), (array([996, 119]), array([2517, 1407])), (array([996, 912]), array([2517, 2200])), (array([997,   6]), array([2518, 1294])), (array([997, 328]), array([2518, 1616])), (array([997, 922]), array([2518, 2210])), (array([997, 939]), array([2518, 2227])), (array([998, 252]), array([2519, 1540])), (array([998, 477]), array([2519, 1765])), (array([998, 818]), array([2519, 2106])), (array([998, 847]), array([2519, 2135])), (array([998, 857]), array([2519, 2145])), (array([999,  71]), array([2520, 1359])), (array([999,  83]), array([2520, 1371])), (array([999, 240]), array([2520, 1528])), (array([999, 592]), array([2520, 1881])), (array([999, 695]), array([2520, 1983])), (array([999, 707]), array([2520, 1995])), (array([1000,  307]), array([2521, 1595])), (array([1000,  643]), array([2521, 1931])), (array([1000,  658]), array([2521, 1946])), (array([1000,  867]), array([2521, 2155])), (array([1001,  387]), array([2522, 1675])), (array([1003,  681]), array([2524, 1969])), (array([1004,   39]), array([2525, 1327])), (array([1004,  211]), array([2525, 1499])), (array([1005,  795]), array([2526, 2083])), (array([1006,  195]), array([2527, 1483])), (array([1006,  398]), array([2527, 1686])), (array([1007,  341]), array([2528, 1630])), (array([1007,  364]), array([2528, 1652])), (array([1007,  733]), array([2528, 2021])), (array([1007,  782]), array([2528, 2070])), (array([1007,  880]), array([2528, 2168])), (array([1007,  913]), array([2528, 2201])), (array([1008,  102]), array([2529, 1390])), (array([1008,  220]), array([2529, 1508])), (array([1008,  249]), array([2529, 1537])), (array([1008,  352]), array([2529, 1640])), (array([1008,  444]), array([2529, 1732])), (array([1009,  869]), array([2530, 2157])), (array([1010,  419]), array([2531, 1707])), (array([1010,  549]), array([2531, 1837])), (array([1010,  660]), array([2531, 1948])), (array([1012,  846]), array([2533, 2134])), (array([1013,  649]), array([2534, 1937]))]
No description has been provided for this image

📖 Theory Q: What are potential weaknesses of SSD-based matching compared to modern descriptors like SIFT/ORB?
Ans. Potential Weaknesses of SSD-Based Matching Compared to SIFT/ORB

  1. Sensitivity to Illumination Changes

    • SSD (Sum of Squared Differences) directly compares intensity values.
    • Even small changes in lighting or contrast can cause large SSD differences.
    • SIFT and ORB use gradient-based or normalized descriptors, making them more robust to illumination variations.
  2. Lack of Scale Invariance

    • SSD compares patches at a fixed size.
    • Objects appearing at different scales between images can lead to poor matches.
    • SIFT inherently handles scale changes via keypoint scale-space detection.
  3. Lack of Rotation Invariance

    • SSD is sensitive to rotation; rotated patches have high SSD even if they correspond to the same point.
    • SIFT and ORB compute orientation for keypoints to achieve rotation invariance.
  4. Poor Robustness to Noise

    • SSD directly compares pixel intensities, so noise in the image can drastically affect matching.
    • Modern descriptors are more robust due to gradient-based or binary descriptors.
  5. High Computational Cost for Large Search

    • SSD requires exhaustive search over all possible patch locations.
    • Descriptors like ORB allow fast matching using compact binary representations and approximate nearest neighbor search.
  6. Low Distinctiveness

    • Simple intensity patches may not be unique, causing ambiguous matches in textured or repetitive regions.
    • SIFT and ORB descriptors are designed to be distinctive, reducing false matches.