# Image Restoration

*English translation by SOTA – AI Community of the Russian original. Licensed MIT, like the original. Organisers who would like this translation removed can email sota.ai.community@gmail.com.*

*Contest 1 (25 June 2025) of the Kazakhstan IOAI Team Selection Test (Отборочные на IOAI), 2025. This is the Overview tab of the Kaggle competition "Upsolving TST Day 1" (subtitle: "Up Solving for TST Day 1"), the host's public upsolving copy of the contest, open from 25 June to 1 September 2025. Original: [kaggle.com/competitions/up-solving-tst-day-1](https://www.kaggle.com/competitions/up-solving-tst-day-1). The Data tab is translated in a separate file.*

## Overview

### Statement

You have an image of size **128×128** in **RGB** format (three channels). However, one of **12 colour filters** of size **2×2** has been applied to it.

Each filter determines which channel (**R**, **G** or **B**) is kept in each of the 4 cells of a 2×2 block, and the other channels are zeroed. All the other pixels at these positions in the other channels are set to zero (become 0).

### Task

You are given an image **after the filter has been applied**. It is known that **the same filter** was used over the whole image, but **which one is unknown**.

Your task is to:

* Determine **which of the 12 possible filters** was applied.
* Reconstruct an **approximation of the original image**.

💻 The starter notebook is available here: https://www.kaggle.com/code/akhanov/tst-day1-starter

## Description

#### Filter properties:

* A filter is a list of four symbols: `['R', 'G', 'B', 'R']`.
* These symbols determine which channel is kept in the:

  * top-left (0, 0),
  * top-right (0, 1),
  * bottom-left (1, 0),
  * bottom-right (1, 1) pixels of a 2×2 block.
* It is guaranteed that:

  * The filter contains all three channels (R, G, B) at least once.
  * Identical letters lie on a diagonal (either the main diagonal or the anti-diagonal).
  * There are 12 possible filters in total that satisfy these conditions.

#### Filter example:

```
['R', 'G',
 'B', 'R']
```

This means:

* Pixel (0,0) keeps only the red (R) channel.
* Pixel (0,1) keeps green (G).
* Pixel (1,0) keeps blue (B).
* Pixel (1,1) keeps red (R).

### Applying the filter

The filter is applied **to the whole image** in 2×2 blocks, that is:

* (0,0)-(1,1), (0,2)-(1,3), ..., (126,126)-(127,127)
* The filter is applied with the same rules on every 2×2 block.

#### Example filtering code:

```python
def apply_fast_filter(img, pattern):
    """Applies a 2x2 filter to an image."""
    # Create a new image with the same dimensions
    filtered_img = np.zeros_like(img)
    
    # For each pixel in the 2x2 block, keep only the required channel
    # Top left
    filtered_img[0::2, 0::2, pattern[0]] = img[0::2, 0::2, pattern[0]]
    # Top right
    filtered_img[0::2, 1::2, pattern[1]] = img[0::2, 1::2, pattern[1]]
    # Bottom left
    filtered_img[1::2, 0::2, pattern[2]] = img[1::2, 0::2, pattern[2]]
    # Bottom right
    filtered_img[1::2, 1::2, pattern[3]] = img[1::2, 1::2, pattern[3]]
    
    return filtered_img
```

Here `pattern` is a list of channel indices (0 — R, 1 — G, 2 — B), for example `[0, 1, 1, 0]` instead of `['R', 'G', 'G', 'R']`.

## Evaluation

### 📏 Metric

The metric in this task is **PSNR (Peak Signal-to-Noise Ratio)** between the reconstructed image and the original.

$$
\text{PSNR}(I, \hat{I}) = 10 \cdot \log_{10} \left( \frac{255^2}{\text{MSE}(I, \hat{I})} \right)
$$

where:

* `I` is the original image (before the filter was applied),
* `Î` is the image reconstructed by the participant,
* `H, W, C` are the height, width and number of channels (in this task: 128×128×3),
* All pixel values are from `0` to `255` (type `uint8`).

$$
\text{MSE}(I, \hat{I}) = \frac{1}{H \cdot W \cdot C} \sum_{x=1}^{H} \sum_{y=1}^{W} \sum_{c=1}^{C} \left( I_{x,y,c} - \hat{I}_{x,y,c} \right)^2
$$

* All image values lie in the range from 0 to 255 (type `uint8`).

The higher the PSNR value, the **better the reconstruction quality**.
