Discord

Checklist IOAI TST 2025 IOAI Team Selection Test · Task 1

Image Restoration

Identify which of 12 2x2 colour-channel filters was applied to an RGB image and reconstruct the original image.

  • Vision
  • Image restoration (demosaicing-like reconstruction)
  • Russian original · English translation

The task

Each 128x128 RGB image has been passed through one of 12 colour filters of size 2x2. A filter is a list of four channel letters (for example ['R', 'G', 'B', 'R']) stating which single channel is kept at the top-left, top-right, bottom-left and bottom-right pixel of every 2x2 block; the other channels are set to 0. Every filter contains all three channels at least once and its repeated letter lies on a diagonal, which gives exactly 12 possible filters. The same filter is used over the whole image, and the statement includes reference code for applying it.

The contestant must determine which filter was applied and recover an approximation of the original image. Training data give filtered and original versions of the same images; the test set contains filtered images only.

Abridged and translated by SOTA from the official Russian materials. The official statement has the exact rules, and it wins wherever this summary differs.

In English

This task was published in Russian. SOTA translated its 2 files into English on 17 September 2026.

Read the competition overview in English 701 words

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 [email protected].

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. 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:
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.

PSNR(I,I^)=10log10(2552MSE(I,I^))\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).

MSE(I,I^)=1HWCx=1Hy=1Wc=1C(Ix,y,cI^x,y,c)2\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.

Translated by SOTA. The Russian original is the official version and wins wherever the two differ. This translates the Overview and Data tabs of the host's public upsolving copy on Kaggle; the Rules tab (code of conduct, allowed websites and libraries) is not included. The host's starter notebook (in English) writes integer ids and columns named pixel_0, pixel_1, …, which differs from the sample_submission.csv layout described on the Data tab (ids such as img_01 and columns 0 to 49151). The competition data on Kaggle are licensed MIT. If you organise this olympiad and would like the translation removed, email [email protected] and we will take it down.

At a glance

You get
train/filtered/ and train/original/ (matching PNG file names); test/ with filtered PNG images only; sample_submission.csv.
You submit
submission.csv with one row per test image: id (file name without .png) and columns 0-49151 holding the restored pixel values (0-255) in the order of .reshape((128, 128, 3)).flatten(), channels in BGR order.
Scoring
PSNR between the restored and original images: PSNR = 10 log10(255^2 / MSE), MSE over 128x128x3 uint8 values; higher is better. Contest scoring (hub page): each task is worth at most 100 points; Norm_Score = (Submission_Score - Min_Score) / (Max_Score - Min_Score) x 100, where Min_Score is the lower of 0.9 x baseline score and the lowest participant score, and Max_Score is the higher of 0.9 x the Scientific Committee solution score and the best participant score.
Rules
  • Read-only access to stackoverflow.com, scikit-learn.org, pytorch.org, huggingface.co, numpy.org, github.com, python.org, pypi.org, a search engine restricted to these sites and a translation site.
  • GPT-4o (or a newer version announced before the contest) is allowed through the platform integration; other LLMs, chats, Copilot tools and APIs are forbidden unless the task says otherwise.
  • Allowed libraries include torch, scikit-learn, xgboost, catboost, lightgbm, transformers, spacy, nltk, gensim, fasttext, pandas, numpy, scipy, opencv-python, Pillow, torchvision, scikit-image, matplotlib, seaborn, plotly and common utilities; TensorFlow and Keras are not available.
  • Pre-trained models and external data are forbidden unless the task allows them; no extra training time after the contest ends; contestants may be asked to upload code, models and/or predictions.
Format
Kazakhstan IOAI Team Selection Test 2025, contest 1 of 4 (25 June 2025), run as a private Kaggle competition; the public Kaggle copy is an upsolving clone of it.

Details

Year
2025
Round
IOAI Team Selection Test · Task 1
Language
Russian; English translation by SOTA
License
MIT (hub and Day 1 copy); CC BY-NC-SA 4.0 (Day 2–4 copies), as stated by the source