Priprema za Computer Vision intervju

Pitanja za Computer Vision Engineer intervju

15 često postavljanih pitanja za Computer Vision intervju. Pitanja pokrivaju različite nivoe, a odgovore možete vežbati naglas u našem treneru za intervjue.

Započni Computer Vision AI intervjuKreditna kartica nije potrebna. Dostupna je 1 besplatna sesija.
Vežba tehničkog intervjua na engleskomRežim u kome kandidati kojima engleski nije maternji mogu da vežbaju tehničke intervjue.

Pitanja za početni nivo

1Šta je diskretna 2D (dvodimenzionalna) konvolucija na slici i kako je povezana sa kernelima, filterima i unakrsnom korelacijom?

Diskretna 2D konvolucija na slici predstavlja linearnu operaciju prostornog filtriranja u kojoj matrica težina (kernel) klizi preko ulazne slike. Na svakoj prostornoj lokaciji računa se proizvod po elementima između težina kernela i preklopljenog lokalnog isečka slike (receptivnog polja), a zatim se rezultati sabiraju (često uz dodavanje člana pomeraja ili biasa) kako bi se dobila jedna vrednost piksela u izlaznoj mapi karakteristika (feature map). U klasičnoj matematici i obradi signala, prava konvolucija podrazumeva okretanje (rotaciju za 180 stepeni) kernela horizontalno i vertikalno pre računanja klizećeg unutrašnjeg proizvoda: $(I * K)(i, j) = \sum_m \sum_n I(i - m, j - n) K(m, n)$. Nasuprot tome, unakrsna korelacija (cross-correlation) računa klizeći skalarni proizvod direktno, bez okretanja kernela: $(I \star K)(i, j) = \sum_m \sum_n I(i + m, j + n) K(m, n)$. U radnim okvirima za duboko učenje kao što su PyTorch i TensorFlow, operacija implementirana pod nazivom „convolution“ zapravo je unakrsna korelacija. Budući da su težine kernela parametri koji se uče i optimizuju direktno kroz propagaciju unazad (backpropagation), mreža jednostavno uči odgovarajuće orijentisane težine, pa matematičko okretanje kernela postaje računarski suvišno i tokom treniranja i tokom inferencije.

import numpy as np
from scipy.signal import convolve2d, correlate2d

image = np.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]], dtype=float)

# Asymmetric directional kernel
kernel = np.array([[1, 0],
                   [0, -1]], dtype=float)

# Convolve flips kernel by 180 degrees: kernel[::-1, ::-1]
conv_res = convolve2d(image, kernel, mode='valid')
corr_res = correlate2d(image, kernel, mode='valid')

print("Convolve output:\n", conv_res)
print("Correlate output:\n", corr_res)
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

2Kada biste koristili RGB (Red, Green, Blue), HSV (Hue, Saturation, Value), Lab, YCbCr ili grayscale reprezentacije u pipeline-u računarskog vida?

Različiti prostori boja razdvajaju specifična fizička, perceptivna i statistička svojstva vizuelnih podataka, što ih čini pogodnim za specifične zadatke računarskog vida: 1. **RGB / BGR**: Standardni format za senzore kamera i ekrane koji predstavlja aditivne primarne boje (crvena, zelena, plava). Kanali boja su u jakoj korelaciji sa osvetljenjem (promene osvetljenja utiču na sva tri kanala istovremeno). Ovo je standardni ulaz za duboke neuronske mreže (CNN, Vision Transformers). Glavni problem u produkciji jeste zamena RGB i BGR kanala (npr. OpenCV učitava BGR, dok PIL/PyTorch očekuju RGB), što neprimetno narušava tačnost modela. 2. **HSV / HSL**: Eksplicitno razdvaja hromatičnost (Hue = nijansa boje, Saturation = zasićenost boje) od intenziteta (Value/Lightness = svetlina). Idealan je za klasično segmentiranje pragom (thresholding), praćenje objekata na osnovu boje i segmentaciju boja pri promenljivom osvetljenju, jer je nijansa (Hue) relativno neosetljiva na senke i promene svetline. 3. **CIE Lab**: Perceptivno uniforman prostor boja gde Euklidsko rastojanje između dve tačke ($\Delta E$) direktno odražava ljudsku percepciju razlike. Razdvaja svetlinu ($L^*$) od oponentnih osa boja ($a^*$ zeleno-crvena, $b^*$ plavo-žuta). Koristi se u inspekciji razlika u boji, korekciji boja, proceni kvaliteta slike i zadacima kolorizacije. 4. **YCbCr**: Razdvaja luminansu ($Y$) od hromatskih komponenti razlike plave ($Cb$) i crvene ($Cr$). Predstavlja osnovu standarda za kompresiju videa i slika (JPEG, MPEG, H.264/H.265) jer je ljudski vizuelni sistem manje osetljiv na detalje u boji, što omogućava hromatsko poduzorkovanje (chroma subsampling, npr. 4:2:0) radi uštede propusnog opsega i računarskih resursa. 5. **Grayscale (sivi tonovi)**: Jednokanalna reprezentacija intenziteta ($Y \approx 0.299R + 0.587G + 0.114B$). Idealna je za zadatke zasnovane na geometriji i teksturi gde boja nije relevantna (npr. optički protok, SLAM, klasična ekstrakcija karakteristika poput SIFT/ORB, detekcija ivica) čime se štedi 66% memorije i računanja. Ipak, ne treba je koristiti kada je boja ključni diskriminativni faktor (npr. klasifikacija stanja na semaforu).

import cv2
import numpy as np

# Sample image: saturated red under normal and shaded lighting
img_bgr = np.zeros((100, 100, 3), dtype=np.uint8)
img_bgr[:, :50] = [0, 0, 255]    # Bright Red in BGR
img_bgr[:, 50:] = [0, 0, 120]    # Shaded/Dark Red in BGR

# Convert to HSV (OpenCV H: 0-179, S: 0-255, V: 0-255)
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)

# Red Hue wraps around 0/180; track red with single Hue range [0, 10] & high saturation
lower_red = np.array([0, 100, 50])
upper_red = np.array([10, 255, 255])
mask_hsv = cv2.inRange(img_hsv, lower_red, upper_red)

print("HSV segmented pixels:", np.count_nonzero(mask_hsv), "out of", mask_hsv.size)
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

3Zašto su normalizacija slike po kanalima, normalizacija po pojedinačnoj slici i dosledno skaliranje piksela važni u sistemima računarskog vida?

Normalizacija slika je ključna u obradi računarskog vida radi očuvanja numeričke stabilnosti, ubrzavanja konvergencije gradijentnog spusta i sprečavanja odstupanja u distribuciji podataka između treniranja i produkcije (train-serving distribution shift): 1. **Skaliranje piksela ([0, 1] ili [-1, 1])**: Sirove vrednosti piksela se čuvaju kao neoznačeni 8-bitni celi brojevi (`uint8` $\in [0, 255]$). Prosleđivanje sirovih vrednosti $[0, 255]$ u neuronske mreže izaziva izuzetno velike rane aktivacije i eksploziju ili zasićenje gradijenata. Skaliranje na $[0.0, 1.0]$ (deljenjem sa 255.0) ili $[-1.0, 1.0]$ centrira ulaze oko nule, što je usklađeno sa standardnim metodama inicijalizacije težina (He, Xavier). 2. **Normalizacija po kanalima na nivou skupa podataka (standardizacija pomoću srednje vrednosti i standardne devijacije)**: Standardizuje ulaze formulom $x_{norm} = \frac{x - \mu_c}{\sigma_c}$ koristeći unapred izračunate globalne statistike po kanalima (npr. ImageNet srednja vrednost `[0.485, 0.456, 0.406]` i standardna devijacija `[0.229, 0.224, 0.225]`). Time se svaki kanal centrira oko nulte srednje vrednosti sa jediničnom varijansom na nivou celog skupa podataka, obezbeđujući uravnotežen protok gradijenata kroz kanale. Kritičan operativni problem je **odstupanje između treniranja i produkcije (train-serving skew)**: ako se pri zakljucivanju (inference) izostavi deljenje sa 255, upotrebe pogrešne vrednosti za srednju vrednost i standardnu devijaciju ili se one primene u pogrešnom redosledu kanala (RGB naspram BGR), performanse modela drastično opadaju. 3. **Normalizacija po pojedinačnoj slici (Instance Normalization / Min-Max / Z-score)**: Računa srednju vrednost i standardnu devijaciju za svaku pojedinačnu sliku: $x_{norm} = \frac{x - \mu_{img}}{\sigma_{img}}$. Time se uklanjaju globalne varijacije u kontrastu i osvetljenju nastale pod različitim uslovima snimanja. Iako je efikasna u prenosu stila (style transfer), medicinskom snimanju (MRI/CT) ili satelitskim snimcima, može biti štetna kada apsolutni intenzitet piksela nosi fizičko značenje (npr. klasifikacija dan/noć, refleksija materijala ili detekcija defekata pod kalibrisanim osvetljenjem).

import torch
import torchvision.transforms as T
from PIL import Image
import numpy as np

# Create a mock uint8 RGB image
raw_img = Image.fromarray(np.random.randint(0, 256, (224, 224, 3), dtype=np.uint8))

# Standard transform pipeline:
# 1. ToTensor scales uint8 [0, 255] -> float32 [0.0, 1.0] and permutes HWC -> CHW
# 2. Normalize standardizes per-channel using dataset mean and std
preprocess = T.Compose([
    T.ToTensor(),
    T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])

tensor_img = preprocess(raw_img)
print("Tensor shape:", tensor_img.shape)
print("Tensor dtype:", tensor_img.dtype)
print("Channel 0 min/max:", round(tensor_img[0].min().item(), 2), round(tensor_img[0].max().item(), 2))
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

4Kako geometrijske i fotometrijske augmentacije podstiču invarijantnost i kako odlučujete da li augmentacija čuva labele?

Geometrijske augmentacije (kao što su rotacija, translacija, skaliranje i preslikavanje) menjaju prostorno mapiranje koordinata piksela, dok fotometrijske augmentacije (kao što su osvetljenje, kontrast, podrhtavanje nijanse odnosno hue jitter i zamućenje) menjaju intenzitet piksela i kanale boja bez modifikovanja prostornih koordinata. U klasifikaciji, obe kategorije izlažu model realističnim varijacijama, podstičući ga da nauči invarijantne reprezentacije kod kojih predikcije ostaju stabilne uprkos promenama u pozi, tački posmatranja ili uslovima osvetljenja. U zadacima prostornog predviđanja (detekcija i segmentacija), geometrijske transformacije zahtevaju odgovarajuće transformacije referentnih okvira (ground-truth boxes) ili maski kako bi se očuvala ekvivarijantnost. Odluka o tome da li augmentacija čuva labele zahteva procenu semantike domena i fizičkih predznanja (priors). Transformacija čuva labele ako rezultujuća slika ostaje verodostojna instanca originalne ciljne klase bez promene njenog semantičkog identiteta. Na primer, horizontalno preslikavanje čuva identitet za opšte objekte (poput automobila ili životinja), ali menja identitet ili poništava karaktere u optičkom prepoznavanju znakova (OCR – Optical Character Recognition) i klasifikaciji cifara. Slično tome, puna rotacija od 360 stepeni je validna u histologiji ili na satelitskim snimcima gde ne postoji kanonska orijentacija, ali je neprirodna u autonomnoj vožnji gde objekti okrenuti naopačke krše fizička ograničenja realnog sveta.

import albumentations as A

# Natural scene classification / object detection: horizontal flip is valid
natural_scene_transform = A.Compose([
    A.HorizontalFlip(p=0.5),
    A.RandomBrightnessContrast(p=0.2),
], bbox_params=A.BboxParams(format='pascal_voc', label_fields=['category_ids']))

# OCR / Digit classification: horizontal flip corrupts semantics
ocr_transform = A.Compose([
    A.Affine(scale=(0.9, 1.1), rotate=(-10, 10), p=0.5),
    A.ColorJitter(brightness=0.2, contrast=0.2, p=0.5),
])
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

5Šta su interpolacija najbližim susedom, bilinearna, bikubna i površinska (area) interpolacija, i kako promena veličine može uneti alijasovanje ili zamućenje?

Metode interpolacije procenjuju intenzitete piksela na kontinualnim koordinatama pri ponovnom uzorkovanju na novu diskretnu mrežu: - **Najbliži sused (Nearest-Neighbor):** Dodeljuje intenzitet najbližeg diskretnog piksela. Računski je složenosti $O(1)$ i čuva tačne originalne vrednosti, ali stvara blokaste artefakte pri uvećanju (upsampling) i grube nazubljene ivice pri smanjenju (downsampling). - **Bilinearna interpolacija:** Izračunava prosek $2 \times 2$ (4 najbliža) susedna piksela ponderisan rastojanjem koristeći linearnu interpolaciju duž obe ose, dajući glatke prelaze uz umereno zamućenje. - **Bikubna interpolacija:** Uzorkuje okolinu dimenzija $4 \times 4$ (16 najbližih piksela) koristeći kubne polinomske kernele. Ona hvata lokalne gradijente intenziteta, proizvodeći oštrije ivice i glatkije krive u odnosu na bilinearnu, ali može izazvati artefakte prebačaja/oscilacija (ringing) oko oštrih prelaza. - **Površinska interpolacija (Area / Box):** Izračunava frakcioni preklop površine ciljnih piksela projektovanih na izvorne piksele i prosečnu vrednost osnovnih izvornih intenziteta. Posebno je efikasna za smanjenje rezolucije bez pojave moare efekta. **Mehanika alijasovanja i zamućenja:** - **Alijasovanje (Aliasing)** se javlja tokom smanjenja rezolucije kada sadržaj visoke frekvencije premaši Najkvistovu frekvenciju ($f_s / 2$) nove brzine uzorkovanja bez odgovarajućeg niskopropusnog filtriranja. Visoke frekvencije se preslikavaju u opsege nižih frekvencija, stvarajući lažne šare, moare i nazubljene ivice. - **Zamućenje (Blur)** nastaje kada interpolacioni kerneli deluju kao niskopropusni filteri za izglađivanje koji ublažavaju legitimne visoke frekvencije (npr. bilinearno izglađivanje) ili kada se detalji visoke frekvencije uproseče tokom smanjenja rezolucije.

import cv2

# Severe downsampling: area downsampling prevents aliasing
img = cv2.imread('high_res_pattern.jpg')
downscaled_area = cv2.resize(img, (400, 300), interpolation=cv2.INTER_AREA)
downscaled_nn = cv2.resize(img, (400, 300), interpolation=cv2.INTER_NEAREST)  # heavy aliasing/moiré

# Upscaling: bicubic preserves edge sharpness
upscaled_cubic = cv2.resize(downscaled_area, (400, 400), interpolation=cv2.INTER_CUBIC)
upscaled_linear = cv2.resize(downscaled_area, (400, 400), interpolation=cv2.INTER_LINEAR)
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

6U odnosu na koje vizuelne režime otkaza iz stvarnog sveta treba evaluirati sistem računarskog vida i kako oni menjaju distribuciju ulaznih podataka?

Vizuelni režimi otkaza iz stvarnog sveta dele se u nekoliko širokih kategorija: uslovi okruženja (slabo osvetljenje, direktan odsjaj, kiša, sneg, magla), senzorski i optički efekti (zamućenje usled pokreta, defokusirano zamućenje, šum senzora pri visokim ISO vrednostima, distorzija usled rolling shutter mehanizma), degradacija usled kompresije i prenosa (blok-artefakti kod JPEG kompresije, smanjenje protoka video signala, poduzorkovanje), kao i semantička/prostorna pomeranja (delimično zaklanjanje, odsecanje, poze objekata van očekivane distribucije). Ovi režimi otkaza pomeraju ulaznu distribuciju u odnosu na nominalne domene obuke na više nivoa. Na nivou piksela menjaju histograme osvetljenja i hrominanse, uništavaju lokalni kontrast, smanjuju odnos signal-šum (SNR) i uvode veštačke visokofrekventne artefakte ili jezgra zamućenja. Na strukturnom i semantičkom nivou ublažavaju gradijente ivica, zaklanjaju ključne vizuelne karakteristike, izobličuju siluete i skrivaju kritične dijagnostičke regione. Kada se modeli obučeni na čistim podacima susretnu sa ovako promenjenim ulazima, niskonivojski konvolucioni ekstraktori obeležja ili mehanizmi pažnje ne aktiviraju se ispravno, što dovodi do propuštenih detekcija, haluciniranih lažno pozitivnih ishoda na obrascima šuma i grešaka sa neopravdano visokim nivoom pouzdanosti.

Category              | Physical Mechanism             | Input Shift & Feature Impact
-----------------------------------------------------------------------------------------
Low Light / Noise     | Low photon flux, high sensor gain | Drops SNR, suppresses gradient edges, fires spurious texture filters
Motion / Defocus Blur | Scene/camera motion, out-of-focus| Attenuates high spatial frequencies, smears object boundaries
Adverse Weather/Glare | Fog/rain scattering, lens flare  | Compresses dynamic range, lowers contrast, masks semantic regions
Occlusion / Cutoff    | Physical foreground obstructions | Masks critical keypoints/parts, breaks holistic spatial priors
Compression Artifacts | Block DCT quantization, subsampling| Introduces 8x8 grid boundaries, removes fine textural details
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

7Kako klasični deskriptori kao što je HOG (Histogram of Oriented Gradients) predstavljaju strukturu slike i koja ograničenja imaju u poređenju sa naučenim obeležjima CNN (Convolutional Neural Network) mreža?

HOG (Histogram of Oriented Gradients) je klasični ručno projektovani deskriptor obeležja namenjen za beleženje lokalnog oblika i izgleda objekta kroz distribuciju orijentacija gradijenta intenziteta. Tok obrade HOG-a obuhvata: (1) računanje horizontalnih i vertikalnih gradijenata slike (npr. pomoću 1D filtara za izvod [-1, 0, 1]) radi dobijanja magnitude i orijentacije gradijenta; (2) podelu slike na male prostorne regione zvane „ćelije“ (kao što su 8x8 piksela) i akumuliranje 1D histograma orijentacija gradijenata ponderisanih magnitudom gradijenta; (3) grupisanje susednih ćelija u veće preklapajuće „blokove“ (kao što su 2x2 ćelije) i normalizaciju vektora obeležja bloka (korišćenjem L2-norme ili L1-sqrt) radi postizanja otpornosti na lokalne promene osvetljenja, kontrasta i senki; i (4) ulančavanje normalizovanih vektora blokova u konačnu 1D reprezentaciju obeležja, koja se istorijski koristila sa linearnim SVM modelima za detekciju pešaka i objekata. U poređenju sa naučenim obeležjima konvolucionih neuronskih mreža (CNN), HOG ima krupna ograničenja: Prvo, obeležja HOG-a su fiksna i ručno projektovana, te beleže samo statistiku lokalnih ivica niskog nivoa bez mogućnosti učenja hijerarhijskih reprezentacija specifičnih za zadatak (kao što su teksture, delovi objekata i semantički koncepti). Drugo, HOG pruža veoma ograničenu geometrijsku invarijantnost: iako normalizacija blokova rešava monotone promene osvetljenja i male prostorne pomake unutar ćelija, HOG je osetljiv na 3D rotacije van ravni, značajne promene skale, nekrute artikulacije poza i složenu pozadinu. Nasuprot tome, CNN uči višeslojne nelinearne apstrakcije optimizovane od početka do kraja (end-to-end) za ciljni zadatak.

Input Image Patch (e.g., 64x128)
  │
  ▼
[ 1. Compute Gradients ] ──> Gx, Gy -> Mag = sqrt(Gx^2 + Gy^2), Angle = atan2(Gy, Gx)
  │
  ▼
[ 2. Cell Histograms   ] ──> 8x8 pixel cells accumulate 9-bin orientation histograms (0°-180°)
  │
  ▼
[ 3. Block Normalization] ──> Overlapping 2x2 cell blocks normalized (e.g., v / sqrt(||v||_2^2 + eps^2))
  │
  ▼
[ 4. Feature Vector    ] ──> Concatenate block vectors -> Feed to Linear SVM / Classifier
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

Pitanja za srednji nivo

8Kako korak (stride), popunjavanje (padding), dilatacija (dilation) i veličina jezgra (kernel size) određuju izlaznu veličinu konvolucije i receptivno polje?

Prostorne dimenzije izlaza konvolucionog sloja i njegovo kumulativno receptivno polje određeni su veličinom jezgra $k$, korakom $s$, popunjavanjem $p$ i dilatacijom $d$: 1. **Prostorna veličina izlaza**: Dilatacija uvodi $(d - 1)$ praznina između elemenata jezgra, dajući efektivnu veličinu jezgra $k' = d(k - 1) + 1$. Dimenzija izlaza duž jedne ose data je formulom: $$O = \left\lfloor \frac{I + 2p - k'}{s} \right\rfloor + 1 = \left\lfloor \frac{I + 2p - d(k - 1) - 1}{s} \right\rfloor + 1$$ Ovde korak smanjuje rezoluciju (downsampling) pomeranjem jezgra za $s$ piksela po koraku, popunjavanje dodaje virtuelne ivične piksele kako bi se očuvale ili prilagodile prostorne dimenzije, a dilatacija proširuje obuhvat filtera bez dodavanja dodatnih parametara. 2. **Receptivno polje (RF)**: Teoretsko receptivno polje opisuje prostorni obuhvat na ulaznoj slici koji utiče na određenu aktivaciju. Kroz naslagane slojeve, receptivno polje $RF_l$ i kumulativni korak (skok $j_l$) ažuriraju se rekurzivno: - Skok: $j_l = j_{l-1} \cdot s_l$, pri čemu je $j_0 = 1$ - Receptivno polje: $RF_l = RF_{l-1} + (k'_l - 1) \cdot j_{l-1}$, pri čemu je $RF_0 = 1$ Koraci i pooling multiplikativno proširuju receptivno polje kroz dubinu jer koraci jezgra u narednim slojevima odgovaraju većim skokovima piksela u koordinatnom prostoru originalnog ulaza. Dilatacija aditivno proširuje receptivno polje unutar jednog sloja povećavanjem $k'_l$ bez prostornog smanjenja rezolucije.

def compute_conv_output_and_rf(layers, input_size=224):
    current_size = input_size
    rf = 1
    jump = 1
    
    for idx, layer in enumerate(layers, 1):
        k, s, p, d = layer['k'], layer['s'], layer['p'], layer['d']
        k_eff = d * (k - 1) + 1
        current_size = ((current_size + 2 * p - k_eff) // s) + 1
        rf = rf + (k_eff - 1) * jump
        jump = jump * s
        print(f"Layer {idx}: Out={current_size}x{current_size}, RF={rf}x{rf}, Jump={jump}")

layers = [
    {'k': 3, 's': 1, 'p': 1, 'd': 1},  # Conv1: 3x3 standard
    {'k': 3, 's': 2, 'p': 1, 'd': 1},  # Conv2: 3x3 strided
    {'k': 3, 's': 1, 'p': 2, 'd': 2},  # Conv3: 3x3 dilated (d=2)
]
compute_conv_output_and_rf(layers, 224)
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

9Kako konvoluciono jezgro odgovara klasičnom linearnom filteru slike i kada 2D (dvodimenzionalni) filter može biti separabilan?

U klasičnoj linearnoj obradi signala i slika, konvoluciono jezgro predstavlja prostorni impulsni odziv (point spread function) LSI (Linear Shift-Invariant) sistema. Primenjivanje jezgra je operacija linearnog filtriranja u prostornom domenu koja oblikuje frekvencijski odziv slike (njenu 2D Furijeovu transformaciju). Niskopropusna jezgra (npr. Gausov filter, box blur) potiskuju visoke prostorne frekvencije kako bi uklonila šum i izgladila teksture, dok visokopropusna ili pojasnopropusna jezgra (npr. Sobel, Laplacian, Prewitt) pojačavaju visoke frekvencije radi detekcije ivica i gradijenata. Jezgro 2D filtera $K \in \mathbb{R}^{M \times N}$ je prostorno separabilno ako se može razložiti na spoljašnji proizvod dva 1D filtera: $K = u \cdot v^T$, gde je $u \in \mathbb{R}^{M \times 1}$ i $v \in \mathbb{R}^{N \times 1}$. U terminima linearne algebre, 2D matrica je separabilna ako i samo ako je njen rang jednak 1. Ovo se može verifikovati putem dekompozicije na singularne vrednosti (SVD - Singular Value Decomposition), gde je tačno jedna singularna vrednost različita od nule ($\sigma_1 > 0, \sigma_2 = \dots = 0$). Separabilnost značajno smanjuje računsku složenost. Primena neseparabilnog jezgra dimenzija $K \times K$ na sliku dimenzija $H \times W$ zahteva $O(H \cdot W \cdot K^2)$ množenja i sabiranja. Kada se razloži na dva uzastopna 1D prolaza (horizontalni, pa vertikalni), složenost opada na $O(H \cdot W \cdot 2K)$. Za jezgro dimenzija $15 \times 15$, ovo obezbeđuje ubrzanje od približno $7.5\times$.

import numpy as np

# Gaussian kernel is rank-1 (separable)
gaussian_1d = np.array([1, 2, 1], dtype=float)[:, None]
gaussian_2d = gaussian_1d @ gaussian_1d.T
gaussian_2d /= gaussian_2d.sum()

# Sobel-X kernel is rank-1 (separable)
sobel_x = np.array([[-1, 0, 1],
                    [-2, 0, 2],
                    [-1, 0, 1]], dtype=float)

# Diagonal kernel is rank-2 (non-separable)
non_sep = np.array([[1, 0],
                    [0, 1]], dtype=float)

print("Gaussian rank:", np.linalg.matrix_rank(gaussian_2d))
print("Sobel-X rank:", np.linalg.matrix_rank(sobel_x))
print("Diagonal rank:", np.linalg.matrix_rank(non_sep))

# SVD decomposition for Sobel-X
U, S, Vt = np.linalg.svd(sobel_x)
print("Sobel-X singular values:", np.round(S, 4))
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

10Kako promena veličine (resizing), centralno isecanje (center cropping), nasumično isecanje sa promenom veličine (random-resized cropping), rastezanje i letterboxing menjaju distribuciju ulaznih podataka?

Različite strategije promene veličine i isecanja menjaju distribuciju ulaznih podataka u pogledu geometrije, razmere, pokrivenosti sadržaja i prostornih granica: 1. **Direktna promena veličine (rastezanje/sabijanje):** Neizotropno menja razmeru slike na ciljnu dimenziju $(H, W)$, narušavajući originalne proporcije slike. Ovo primorava model da obrađuje deformisane oblike objekata (npr. kružni objekti postaju izdužene elipse). 2. **Centralno isecanje (Center Cropping):** Izdvaja centralni isečak fiksne veličine ili proporcije. Čuva izvorni odnos stranica i lokalnu razmeru, ali uvodi snažnu pristrasnost ka centru (pod pretpostavkom da su ciljni objekti u središtu kadra) i odbacuje periferni kontekst ili odseca objekte pozicionirane na ivicama. 3. **Nasumično isecanje sa promenom veličine (Random-Resized Cropping - RRC):** Izdvaja nasumične podregione različitih površina i odnosa stranica, a zatim im menja veličinu na fiksnu dimenziju. Ovo proširuje distribuciju razmera tokom obuke i podstiče učenje karakteristika zasnovanih na delovima, ali ekstremna isecanja mogu u potpunosti izostaviti ciljni objekat. 4. **Letterboxing (izotropna promena veličine sa dopunom):** Uniformno skalira sliku sve dok njena najduža dimenzija ne dostigne ciljnu veličinu, a zatim popunjava preostale ivice konstantnom vrednošću. Zadržava stvarne proporcije objekata i odnos stranica, ali uvodi veštačke ivice visokog kontrasta i neinformativne piksele dopune.

import cv2
import numpy as np

def letterbox_image(image, target_size=(640, 640), pad_color=(114, 114, 114)):
    h, w = image.shape[:2]
    target_w, target_h = target_size
    scale = min(target_w / w, target_h / h)
    new_w, new_h = int(w * scale), int(h * scale)
    
    resized = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    canvas = np.full((target_h, target_w, 3), pad_color, dtype=np.uint8)
    
    top = (target_h - new_h) // 2
    left = (target_w - new_w) // 2
    canvas[top:top+new_h, left:left+new_w] = resized
    return canvas, scale, (left, top)
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

11Koji tipovi šuma u anotacijama se javljaju u skupovima podataka za računarski vid i kako biste ih detektovali ili ublažili?

U skupovima podataka za računarski vid obično se javljaju četiri osnovna tipa šuma u anotacijama: 1. **Šum u kategoričkim labelama:** Slici ili objektu je dodeljena pogrešna klasna labela (npr. pogrešno klasifikovanje mačke kao psa ili mešanje suptilnih, srodnih klasa). 2. **Nedostajuće anotacije (šum izostavljanja):** Validni objekti u prvom planu ostaju neoznačeni. U detekciji objekata, izostavljene mete se tretiraju kao negativni primeri u pozadini, što direktno kažnjava ispravne detekcije modela tokom obuke. 3. **Podrhtavanje graničnih pravougaonika / ključnih tačaka (šum lokalizacije):** Neprecizne, labave ili pomerene koordinate graničnih pravougaonika i lokacije ključnih tačaka uzrokovane nedoslednošću ljudskih anotatora. 4. **Nejasnoća granica maske:** Nedosledne ili grube konture segmentacije duž složenih ili zamućenih granica (npr. kosa, poluprovidne površine, zamućenje usled pokreta). **Strategije detekcije i ublažavanja:** - **Praćenje ekstremnih vrednosti funkcije gubitka i pouzdano učenje (Confident Learning):** Praćenje gubitka po uzorku kroz epohe obuke identifikuje perzistentne uzorke sa visokim gubitkom, koji često ukazuju na pogrešno označene ili izostavljene instance. Algoritmi poput pouzdanog učenja procenjuju raspodelu šuma radi uklanjanja ili ispravljanja grešaka. - **Neslaganja u predviđanjima van preklopa (Out-of-Fold / OOF):** Obučavanje modela unakrsnom validacijom i poređenje predviđanja na izdvojenom skupu sa stvarnim stanjem (ground truth) naglašava pogrešno označene slike i nedostajuće granične pravougaonike. - **Slaganje među anotatorima (IAA - Inter-Annotator Agreement) i arbitraža:** Merenje metrika kao što su Koenov kapa koeficijent (za klasifikaciju) ili srednji presek preko unije (mIoU - mean Intersection-over-Union za lokalizaciju) između više anotatora označava uzorke sa niskim slaganjem za konsenzusnu proveru. - **Robusne formulacije funkcije gubitka:** Korišćenje izglađivanja labela (label smoothing), funkcija gubitka klasifikacije otpornih na šum ili robusnih regresionih gubitaka zasnovanih na IoU smanjuje osetljivost na podrhtavanje i pogrešno označavanje.

import torch
import torch.nn.functional as F

def find_label_noise_candidates(model, dataloader, device, top_k=50):
    model.eval()
    sample_losses = []
    
    with torch.no_grad():
        for batch_idx, (images, targets, sample_ids) in enumerate(dataloader):
            images, targets = images.to(device), targets.to(device)
            logits = model(images)
            loss_per_sample = F.cross_entropy(logits, targets, reduction='none')
            
            for sid, l, target, pred in zip(sample_ids, loss_per_sample.cpu(), targets.cpu(), logits.argmax(dim=-1).cpu()):
                sample_losses.append({'id': sid, 'loss': l.item(), 'target': target.item(), 'pred': pred.item()})
                
    sample_losses.sort(key=lambda x: x['loss'], reverse=True)
    return sample_losses[:top_k]
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

12Kako neuravnoteženost klasa utiče na treniranje klasifikacije slika, detekcije objekata i guste predikcije (dense prediction)?

Neuravnoteženost klasa utiče na dinamiku optimizacije i prostor funkcije gubitka (loss landscape) u različitim zadacima računarskog vida: 1. **Klasifikacija slika:** Kada većinske klase znatno nadmašuju manjinske, minimizacija empirijskog rizika dovodi do toga da ažuriranjima parametara dominiraju gradijenti većinskih klasa. Model uči empirijsku apriornu raspodelu klasa $P(Y)$ i pomera granicu odlučivanja na štetu retkih klasa. Ovo rezultira visokom ukupnom top-1 tačnošću uz dramatičan pad odziva (recall) za manjinske klase. 2. **Detekcija objekata:** - *Neuravnoteženost prednjeg plana i pozadine (Foreground-Background Imbalance):* Kod gustih jednostepenih detektora i onih zasnovanih na ankerima (anchors), po slici se evaluira na stotine hiljada kandidata, od kojih je >99% pozadina. Čak i ako pojedinačni jednostavni ankeri pozadine generišu male gubitke, njihov ogroman zbirni gradijent nadjačava informativne signale gradijenta koji potiču od malobrojnih objekata u prednjem planu. - *Neuravnoteženost među klasama prednjeg plana:* Uobičajene kategorije objekata pojavljuju se višestruko češće od retkih, što smanjuje efektivan broj uzoraka i signal za učenje retkih klasa. 3. **Gusta predikcija (segmentacija):** Neuravnoteženost na nivou piksela je izražena jer velike pozadinske i amorfne klase (npr. put, nebo) zauzimaju milione piksela, dok male klase pojedinačnih objekata (npr. saobraćajni znakovi, pešaci) mogu zauzimati manje od 0,1% piksela slike. Standardni cross-entropy gubitak po pikselu biva potčinjen klasama sa velikom površinom, što dovodi do nedovoljne segmentacije ili potpunog nestanka malih, tankih struktura.

# Illustrating cumulative gradient dominance by background anchors
import torch

num_bg_anchors = 100_000
num_fg_anchors = 10

bg_loss_per_sample = torch.tensor(0.001, requires_grad=True)
fg_loss_per_sample = torch.tensor(1.5, requires_grad=True)

total_loss = (num_bg_anchors * bg_loss_per_sample) + (num_fg_anchors * fg_loss_per_sample)
total_loss.backward()

print(f'Total BG gradient contribution: {num_bg_anchors * bg_loss_per_sample.grad.item():.1f}')
print(f'Total FG gradient contribution: {num_fg_anchors * fg_loss_per_sample.grad.item():.1f}')
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

Pitanja za napredni nivo

13Kako biste otklanjali pojavu NaN vrednosti ili nestabilnog gubitka tokom distribuiranog treniranja modela računarskog vida velikih razmera?

Otklanjanje NaN vrednosti ili nestabilnosti funkcije gubitka tokom distribuiranog treniranja modela računarskog vida velikih razmera pomoću DDP (Distributed Data Parallel) pristupa zahteva izolovanje uzroka: da li potiče od neispravnih ulaznih podataka, numeričkog prekoračenja/potkoračenja u mešovitoj preciznosti (AMP - Automatic Mixed Precision) ili optimizacionih nestabilnosti između radnih čvorova. Prvo, uspostavite determinizam i bezbednosne kuke: omogućite detekciju anomalija (`torch.autograd.set_detect_anomaly(True)`), registrujte kuke za gradijente/aktivacije kako biste uhvatili tačan sloj gde se NaN pojavljuje i dodajte striktnu validaciju podataka u DataLoader (provera konačnih vrednosti, provera oštećenih slika od 0 bajtova, praznih graničnih pravougaonika ili delilaca za normalizaciju sa nultom varijansom). Evidentiranje na nivou mini-batch-a treba da prati gubitak po rangu, URI identifikatore ulaznih podataka, normu gradijenta pre odsecanja i faktore skaliranja za GradScaler. Drugo, proverite AMP i dinamičko skaliranje gubitka: u FP16 formatu, veliki gradijenti lako prekoračuju opseg (`> 65504`), što dovodi do toga da skaler gubitka preskače korake i uzastopno prepolovljava svoj faktor skaliranja dok skala ne dostigne nulu; prebacivanje nestabilnih operacija (npr. softmax, LayerNorm, eksponenti u focal loss funkciji ili imenioci IoU za granične pravougaonike) na FP32 ili usvajanje BF16 formata (koji odgovara dinamičkom opsegu formata FP32) obično stabilizuje treniranje. Na kraju, proverite specifične zamke u DDP-u kao što su all-reduce operacije koje propagiraju NaN vrednosti sa jednog radnog čvora na sve rangove, skaliranje stope učenja tokom zagrevanja (npr. pravilo linearnog skaliranja sa velikim globalnim veličinama batch-a) i odsecanje gradijenata.

import torch
from torch.cuda.amp import autocast, GradScaler

scaler = GradScaler()
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)

for step, (images, targets, uris) in enumerate(dataloader):
    # 1. Input sanitization
    if not torch.isfinite(images).all():
        print(f"Corrupt input detected from URIs: {uris}")
        continue
        
    optimizer.zero_grad(set_to_none=True)
    
    with autocast(dtype=torch.float16):
        outputs = model(images)
        loss = criterion(outputs, targets)
    
    if not torch.isfinite(loss):
        print(f"NaN/Inf loss at step {step} on rank {torch.distributed.get_rank()}; skipping step.")
        continue
        
    scaler.scale(loss).backward()
    
    # Unscale before clipping to inspect true gradient norms
    scaler.unscale_(optimizer)
    grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    
    if torch.isnan(grad_norm) or torch.isinf(grad_norm):
        print(f"Warning: Grad norm is {grad_norm}. Scaler will adjust.")
        
    scaler.step(optimizer)
    scaler.update()
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

14Kako biste projektovali komponentu za digitalnu stabilizaciju videa u realnom vremenu za kameru sa podrhtavanjem kadrova?

Projektovanje protočne obrade (pipeline) za digitalnu stabilizaciju videa u realnom vremenu za podrhtavanje kamere obuhvata četiri primarne faze: procenu kretanja, uglađivanje kretanja, kompenzaciju kretanja (iskrivljavanje/warping) i obradu ivica. 1. **Procena kretanja između kadrova:** Izdvojite 2D retke ključne tačke kroz uzastopne kadrove koristeći brze detektore karakteristika (npr. ORB, FAST ili Shi-Tomasi uglove) i izračunajte korespondencije koristeći Lucas-Kanade optički protok ili uparivanje deskriptora karakteristika. Procenite geometrijsku transformaciju između kadrova (kao što je afini model ili model homografije) koristeći RANSAC za odbacivanje netačnih uparivanja (outliers) izazvanih objektima u prvom planu koji se nezavisno kreću. 2. **Akumulacija putanje kretanja i uglađivanje u realnom vremenu:** Integrišite transformacije iz kadra u kadar tokom vremena kako biste održavali kumulativnu putanju kamere $P_t = P_{t-1} \cdot H_t$. Primenite filtar za uglađivanje u realnom vremenu — kao što je 1D/2D Kalmanov filtar ili kauzalni pokretni prosek sa kratkim vremenskim prozorom — kako biste razdvojili neželjeno visokofrekventno podrhtavanje od niskofrekventnog namernog pomeranja kamere (panning). 3. **Kompenzacija i iskrivljavanje slike:** Izračunajte korektivnu transformaciju $C_t = S_t \cdot P_t^{-1}$ (gde je $S_t$ uglađena putanja) i preslikajte (warp) trenutni kadar koristeći bilinearnu ili bikubnu interpolaciju. 4. **Obrada ivica i ograničenja kašnjenja:** Preslikavanje stvara piksele koji nedostaju na ivicama / crne okvire; rešite ovo primenom fiksnog faktora dinamičkog isecanja (npr. 5–10% uvećanja) uz ekstrapolaciju ivica ili adaptivno skaliranje. U režimu rada u realnom vremenu, održavajte minimalno baferovanje (1–3 unapred učitana kadra) kako bi se ograničilo kašnjenje obrade.

import cv2
import numpy as np

class OnlineStabilizer:
    def __init__(self, crop_ratio=0.9):
        self.prev_gray = None
        self.smoothed_x = 0.0
        self.smoothed_y = 0.0
        self.smoothed_a = 0.0
        self.alpha = 0.85  # Low-pass filter smoothing coefficient
        self.crop_ratio = crop_ratio

    def process_frame(self, frame):
        curr_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        h, w = curr_gray.shape
        
        if self.prev_gray is None:
            self.prev_gray = curr_gray
            return frame
            
        # 1. Feature detection & tracking
        p0 = cv2.goodFeaturesToTrack(self.prev_gray, maxCorners=200, qualityLevel=0.01, minDistance=30)
        p1, status, _ = cv2.calcOpticalFlowPyrLK(self.prev_gray, curr_gray, p0, None)
        
        good_p0 = p0[status == 1]
        good_p1 = p1[status == 1]
        
        # 2. Estimate rigid motion (dx, dy, da) with RANSAC
        T, inliers = cv2.estimateAffinePartial2D(good_p0, good_p1, method=cv2.RANSAC)
        if T is None: 
            return frame
            
        dx = T[0, 2]
        dy = T[1, 2]
        da = np.arctan2(T[1, 0], T[0, 0])
        
        # 3. Online low-pass filtering of jitter
        self.smoothed_x = self.alpha * self.smoothed_x + (1 - self.alpha) * dx
        self.smoothed_y = self.alpha * self.smoothed_y + (1 - self.alpha) * dy
        self.smoothed_a = self.alpha * self.smoothed_a + (1 - self.alpha) * da
        
        diff_x = self.smoothed_x - dx
        diff_y = self.smoothed_y - dy
        diff_a = self.smoothed_a - da
        
        # 4. Warp and crop frame
        M = np.array([
            [np.cos(diff_a), -np.sin(diff_a), diff_x],
            [np.sin(diff_a),  np.cos(diff_a), diff_y]
        ])
        stabilized = cv2.warpAffine(frame, M, (w, h))
        
        # Center-crop to remove boundary artifacts
        cw, ch = int(w * self.crop_ratio), int(h * self.crop_ratio)
        x1, y1 = (w - cw) // 2, (h - ch) // 2
        stabilized = cv2.resize(stabilized[y1:y1+ch, x1:x1+cw], (w, h))
        
        self.prev_gray = curr_gray
        return stabilized
Pokušajte da odgovorite na ovo pitanje sa AI trenerom

15Kako biste optimizovali protočnu obradu računarskog vida u realnom vremenu kada je detektor sporiji od ciljane brzine kadrova?

Kada detektor objekata ne može da održi ciljanu brzinu kadrova (npr. radi na 15–20 FPS na video toku od 60 FPS), robusna produkciona arhitektura razdvaja detekciju od petlje za prikaz u realnom vremenu koristeći asinhronu višenitnu protočnu obradu koja kombinuje zahtevnu detekciju sa laganim praćenjem. U ovoj hibridnoj arhitekturi, nit za unos neprekidno prihvata video kadrove. Zahtevan detektor se izvršava asinhrono kao detektor ključnih kadrova na pozadinskoj radnoj niti. U međuvremenu, lagani sistem za praćenje (kao što su Lucas-Kanade optički protok, ByteTrack/BoT-SORT ili brzi korelacioni filtar/Kalmanov filtar) izvršava se sinhrono na svakom kadru u punih 60 FPS, održavajući stanje objekta, identifikator i glatke putanje graničnih pravougaonika. Da bi se upravljalo kašnjenjem i povratnim pritiskom bez uvođenja neograničene latencije ili zastarelih kadrova, koriste se ograničeni kružni baferi i politike odbacivanja starijih kadrova u korist najnovijeg. Kada detektor završi obradu kadra T_0 u trenutku T_curr, njegov izlaz je već zastareo. Protočna obrada vrši ponovno poravnanje koordinata / povratnu projekciju: povezuje odložene rezultate detekcije sa istorijskim stanjem praćenja u T_0, ažurira identifikatore i propuštene putanje, i propagira ispravke unapred do T_curr putem vektora kretanja praćenja ili prediktivnih koraka Kalmanovog filtra.

import queue
import threading

frame_queue = queue.Queue(maxsize=1)  # Drop stale frames, keep latest
det_result_queue = queue.Queue()

def detector_worker():
    while True:
        frame, frame_id, timestamp = frame_queue.get()
        boxes, scores, classes = heavy_detector.infer(frame)
        det_result_queue.put({'frame_id': frame_id, 'boxes': boxes, 'timestamp': timestamp})

def realtime_pipeline(video_stream):
    tracker = FastTracker()  # e.g. Optical flow or Kalman tracker
    
    for frame, frame_id, timestamp in video_stream:
        if frame_queue.empty():
            frame_queue.put((frame, frame_id, timestamp))
            
        if not det_result_queue.empty():
            det_result = det_result_queue.get()
            tracker.reconcile_and_correct(det_result, current_frame_id=frame_id)
            
        active_tracks = tracker.update(frame)
        display_or_downstream(frame, active_tracks)
Pokušajte da odgovorite na ovo pitanje sa AI trenerom