$$ \newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} \newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} \renewcommand{\mod}{\,\mathrm{mod}\,} \renewcommand{\div}{\,\mathrm{div}\,} \newcommand{\metar}{\,\mathrm{m}} \newcommand{\cm}{\,\mathrm{cm}} \newcommand{\dm}{\,\mathrm{dm}} \newcommand{\litar}{\,\mathrm{l}} \newcommand{\km}{\,\mathrm{km}} \newcommand{\s}{\,\mathrm{s}} \newcommand{\h}{\,\mathrm{h}} \newcommand{\minut}{\,\mathrm{min}} \newcommand{\kmh}{\,\mathrm{\frac{km}{h}}} \newcommand{\ms}{\,\mathrm{\frac{m}{s}}} \newcommand{\mss}{\,\mathrm{\frac{m}{s^2}}} \newcommand{\mmin}{\,\mathrm{\frac{m}{min}}} \newcommand{\smin}{\,\mathrm{\frac{s}{min}}} $$

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.

Припрема из претходних свезака

Све свеске се међусобно надограђују, тако да нам је неопходно да поновимо неке делове из претходних свески, што без додатног објашњења чинимо у овој секцији.

Овде нам је неопходно само учитавање библиотеки

In [1]:
from os import environ
environ["OPENCV_IO_ENABLE_JASPER"] = "true"
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision

import cv2

import numpy as np

from skimage import exposure
from sklearn import metrics

from matplotlib import pyplot as plt

Учитавање података за Србију са сателита Сентинел 2

Сада ћемо наш модел за класификацију намене земљишта применити на подацима из Србије. Као и за базу на којој је модел трениран, користићемо Сентинел 2 податке али регије која одговара Србији. У овом примеру смо изабрали Сентинел 2 снимке шире околине Шапца од 30. јуна 2021. године.

Учитавање једног Сентинел 2 производа у RGB домену

Сами подаци који представљају Сентинел 2 производе када се распакују садрже велики број снимака и метаподатака. У овој вежбанци ћемо се превасходно фокусирати на слике у видљивом спектру боја (практично стандардне слике какве свакодневно гледамо). Сам сателит има инструмент који снима у више спектралних опсега (енг. spectral bands), а нама су од интереса они који снимају на таласним дужинама црвене зелене и плаве боје који су довољни за формирање слике у боји. У питању су спектрални опсези са индексима b02, b03 i b04.

In [2]:
img_path_b02 = r"mldata\S2A_MSIL2A_20210630T093041_N0301_R136_T34TCQ_20210630T122807.SAFE\GRANULE\L2A_T34TCQ_A031450_20210630T093134\IMG_DATA\R10m\T34TCQ_20210630T093041_B02_10m.jp2"
img_path_b03 = r"mldata\S2A_MSIL2A_20210630T093041_N0301_R136_T34TCQ_20210630T122807.SAFE\GRANULE\L2A_T34TCQ_A031450_20210630T093134\IMG_DATA\R10m\T34TCQ_20210630T093041_B03_10m.jp2"
img_path_b04 = r"mldata\S2A_MSIL2A_20210630T093041_N0301_R136_T34TCQ_20210630T122807.SAFE\GRANULE\L2A_T34TCQ_A031450_20210630T093134\IMG_DATA\R10m\T34TCQ_20210630T093041_B04_10m.jp2"

Функција испод учитава сваки од снимака за појединачну боју и онда их комбинује у једну слику. Када је позовемо над путањама за сваку од слика имаћемо учитан целокупан снимак у боји. Слике су јако велике, па овај корак може потрајати који минут.

In [3]:
def load_sentinel_2_image_rgb(img_path_b02, img_path_b03, img_path_b04):
    img_b02 = cv2.imread(img_path_b02, cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)
    img_b03 = cv2.imread(img_path_b03, cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)
    img_b04 = cv2.imread(img_path_b04, cv2.IMREAD_ANYCOLOR | cv2.IMREAD_ANYDEPTH)

    rgb = np.zeros((img_b02.shape[0], img_b02.shape[1], 3))
    rgb[:, :, 0] = img_b04
    rgb[:, :, 1] = img_b03
    rgb[:, :, 2] = img_b02

    rgb = rgb.astype(np.uint16)

    return rgb
In [4]:
image = load_sentinel_2_image_rgb(img_path_b02, img_path_b03, img_path_b04)

Припрема исечка Сентинел 2 снимка за процесирање

Најпре је неопходно припремити учитану слику за обраду путем наше неуралне мреже. Јасно је да је слика веома велика, па ћемо процесирати њене исечке. Поред тога, иако се база на којој је модел трениран састоји од Сентинел 2 снимака, ипак осветљеност, сенке и угао снимања није скроз исти па постоје одређене перциптивне разлике између тих података и података за Србију. Када постоји разлика у подацима на којима је модел трениран и на којима се извршава кажемо да постоји доменска различитост (енг. domain discrapancy). Наравно пожељно је да домен на којем се тренира буде што сличнији домену на коме се модел тестира, што и овде јесте случај.

Доменска различитост је један од фундаменталних проблема са којим се сусрећемо када примењујемо машинско учење у пракси. Самим тим, постоји читава лепеза техника које се користе да се преброди доменска различитост и да се модел прилагоди новом домену - оне се здружено називају доменска адаптација (енг. domain adaptation).

Ми ћемо ради доменске адаптације применити најједноставнију варијанту где ћемо улазним сликама мало променити контраст и осветљеност тако да боље одговарају обсервацијама за Србију. То је поента функције испод. Сами параметри модификације су ручно изабрани посматрајући оба домена слика, мада је потпуно могуће и пожељно у пракси ово урадити на систематичан начин. Такође у зависности од примене, потребно је применити и сложеније технике доменске адаптације.

In [5]:
def prepare_rgb(image):
    p_low, p_high = np.percentile(image, (1, 99))
    image = exposure.rescale_intensity(image, in_range=(p_low, p_high))
    image = image / image.max()
    
    image = exposure.adjust_gamma(image, 0.9)
    image += 0.05
    image = np.clip(image, 0.0, 1.0)

    return image

Сада ћемо изабрати исечак снимка Србије са којим ћемо радити. У питању је исечак величине 512x512 пиксела, а ми ћемо за почетак узети севернији део Шапца са делом реке Саве и обрадивим равничарским пределом са друге стране реке.

Можете се и сами играти и мењати прозор исечка који узимамо. Неки од предлога су дати у коментару испод, а можете и пробати неки свој.

In [6]:
# Шабац - севернији део и река Сава
CROP_START_COL = 9584
CROP_START_ROW = 4060
CROP_SIZE = 512

# Шабац - јужнији део
# CROP_START_COL = 9423
# CROP_START_ROW = 4329
# CROP_SIZE = 512

# Рума - јужни део
# CROP_START_COL = 10383
# CROP_START_ROW = 1626
# CROP_SIZE = 512

# Јарак - цело место и меандар Саве
# CROP_START_COL = 9929
# CROP_START_ROW = 2348
# CROP_SIZE = 512

# Вештачко језеро Ровни
# CROP_START_COL = 9721
# CROP_START_ROW = 9908
# CROP_SIZE = 512

sample_image_1 = image[CROP_START_ROW:CROP_START_ROW+CROP_SIZE, CROP_START_COL:CROP_START_COL+CROP_SIZE, :]

Прикажимо сада издвојени исечак.

In [7]:
plt.figure(figsize=(10, 10))
plt.imshow(prepare_rgb(sample_image_1))
Out[7]:
<matplotlib.image.AxesImage at 0x1a8ac8f4a00>