Report Lab2
Report Lab2
ОТЧЕТ
ПО ЛАБОРАТОРНОЙ РАБОТЕ №2
ГЕОМЕТРИЧЕСКИЕ ПРЕОБРАЗОВАНИЯ
ИЗОБРАЖЕНИЙ
16 марта 2026 г.
Содержание
1 Введение 2
2 Теоретическая часть 2
2.1 Геометрические преобразования изображений . . . . . . . . . . . . . . . . . . 2
2.1.1 Однородные координаты . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.2 Аффинные преобразования . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.3 Матрица преобразования в OpenCV . . . . . . . . . . . . . . . . . . . . 2
2.2 Линейные преобразования . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2.1 Сдвиг изображения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2.2 Отражение изображения . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2.3 Масштабирование . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2.4 Поворот изображения . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2.5 Скос изображения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3 Нелинейные преобразования . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3.1 Перспективное преобразование . . . . . . . . . . . . . . . . . . . . . . . 3
2.3.2 Полиномиальное преобразование . . . . . . . . . . . . . . . . . . . . . 3
2.3.3 Синусоидальные искажения . . . . . . . . . . . . . . . . . . . . . . . . 4
2.4 Коррекция дисторсии . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.5 Сшивка изображений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 Практическая реализация 5
3.1 Задание 1. Простейшие геометрические преобразования . . . . . . . . . . . . 5
3.1.1 Self-work [Link] - Сдвиг изображения . . . . . . . . . . . . . . . . . . . 5
3.1.2 Self-work [Link] - Отражение изображения по обеим осям . . . . . . . 6
3.1.3 Self-work [Link] - Масштабирование изображения . . . . . . . . . . . . 8
3.1.4 Self-work [Link] - Поворот изображения . . . . . . . . . . . . . . . . . 10
3.1.5 Self-work [Link] - Обратное аффинное преобразование . . . . . . . . . 12
3.1.6 Self-work [Link] - Скос изображения . . . . . . . . . . . . . . . . . . . 13
3.1.7 Self-work [Link] - Кусочно-линейное отображение . . . . . . . . . . . . 14
3.2 Задание 1.4 - Нелинейные преобразования . . . . . . . . . . . . . . . . . . . . 15
3.2.1 Self-work [Link] - Обратное перспективное преобразование . . . . . . 15
3.2.2 Self-work [Link] - Полиномиальное отображение . . . . . . . . . . . . . 16
3.2.3 Self-work [Link] - Полиномиальное отображение с интерполяцией (Оп-
ционально) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.2.4 Self-work [Link] - Синусоидальное искажение по оси Oy . . . . . . . . 19
3.3 Задание 2. Коррекция дисторсии . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.3.1 Self-work 2.1.1 - Бочкообразная дисторсия и коррекция . . . . . . . . . 20
3.3.2 Self-work 2.2.1 - Подушкообразная дисторсия и коррекция . . . . . . . 22
3.4 Задание 3. Сшивка изображений . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.4.1 Self-work 3.1.1 - Ручная сшивка изображений . . . . . . . . . . . . . . 24
5 Заключение 26
1
1 Введение
В данной практической работе изучаются основные методы геометрических преобра-
зований изображений. Рассматриваются линейные и нелинейные преобразования, а также
их применение для коррекции искажений и создания панорамных изображений.
2 Теоретическая часть
2.1 Геометрические преобразования изображений
Геометрические преобразования изображений подразумевают пространственное изме-
нение положения пикселей с целочисленными координатами (x, y) в другое множество с
координатами (x′ , y ′ ), при этом интенсивность пикселей не изменяется.
2
2.2.2 Отражение изображения
Отражение вокруг оси Ox: A = 1, E = −1:
1 0 0
T =
0 −1 0
2.2.3 Масштабирование
Масштабирование с коэффициентами α и β:
(
x′ = αx, α > 0
y ′ = βy, β > 0
α 0 0
T =
0 β 0
3
2.3.3 Синусоидальные искажения
Гармонические искажения, например, вдоль оси Ox:
x′ = x + A sin(2πy/λ)
4
3 Практическая реализация
3.1 Задание 1. Простейшие геометрические преобразования
3.1.1 Self-work [Link] - Сдвиг изображения
Условие: Выполнить сдвиг изображения влево и вверх на вектор (−40, −80). Изменить
разрешение изображения в соответствии со сдвигом.
1 # TODO Place your solution for part 1 here
2 # TODO : Shift an image to the left and up by ( -40 , -80)
3 shift_x , shift_y = ( -40 , -80)
4
5 # Create transformation matrix
6 T = np . float32 ([[1 , 0 , shift_x ] ,
7 [0 , 1 , shift_y ]])
8
9 # Calculate new image dimensions ( decreased by shift values )
10 new_width = I . shape [1] + shift_x
11 new_height = I . shape [0] + shift_y
12
13 # Apply transformation
14 Ishift_left_up = cv . warpAffine (I , T , ( new_width , new_height ) )
15
16 # Display result
17 ShowImages ([( " Original Image " , I ) ,
18 ( " Shifted Left and Up ( -40 , -80) " , Ishift_left_up ) ])
5
Краткий вывод: В результате преобразования изображение было сдвинуто влево и
вверх на заданный вектор. После изменения размера выходного изображения потеря дан-
ных не наблюдается.
6
Рис. 4: Оригинал Рис. 5: Через матрицу Рис. 6: Через [Link]()
Краткий вывод: Оба способа отражения изображения по двум осям дали одинаковый
результат. Это подтверждает корректность как ручного задания матрицы преобразования,
так и использования встроенной функции [Link]().
7
3.1.3 Self-work [Link] - Масштабирование изображения
Условие: Увеличить изображение в 1.4 раза по обеим осям. Реализовать два решения.
1 # TODO Place your solution for part 1 here
2 # Create matrix for scale
3 # Apply transformation with cv2 . warpAffine () function
4 # Display the result
5 # Scale factor
6 scale_factor = 1.4
7
8 # Create transformation matrix for scaling
9 # T = [ sx , 0 , 0; 0 , sy , 0] where sx = sy = scale_factor
10 T_scale = np . float32 ([[ scale_factor , 0 , 0] ,
11 [0 , scale_factor , 0]])
12
13 # Calculate new image dimensions
14 new_width = int ( I . shape [1] * scale_factor )
15 new_height = int ( I . shape [0] * scale_factor )
16
17 # Apply affine transformation
18 Iscale15 = cv . warpAffine (I , T_scale , ( new_width , new_height ) )
19
20 print ( f " Original dimensions : { I . shape [1]} x { I . shape [0]} " )
21 print ( f " Scaled dimensions : { new_width } x { new_height } " )
22
23 # Display the result
24 ShowImages ([( " Original Image " , I ) ,
25 ( " Scaled 1.4 x ( warpAffine ) " , Iscale15 ) ] , hide_axes = False )
8
Рис. 8: Оригинал Рис. 9: Через матрицу Рис. 10: Через [Link]()
9
3.1.4 Self-work [Link] - Поворот изображения
Условие: Повернуть изображение вокруг центра правой верхней четверти с коорди-
3 1
натами ( · width, · height) на 30◦ по часовой стрелке. Реализовать два решения.
4 4
10
Рис. 12: Ручной расчет матрицы Рис. 13: Через getRotationMatrix2D()
11
3.1.5 Self-work [Link] - Обратное аффинное преобразование
Условие: Выполнить обратное преобразование изображения ‘Iaffine‘, используя точки
‘Pdst‘ как исходные и ‘Psrc‘ как целевые.
1 # TODO Place your solution here
2 # Backward affine transformation
3
4 Psrc = np . float32 ([[50 , 300] , [150 , 200] , [50 , 50]])
5 Pdst = np . float32 ([[50 , 200] , [250 , 200] , [50 , 100]])
6
7 # Forward transform
8 T_forward = cv . get Af fi neT ra ns for m ( Psrc , Pdst )
9 Iaffine = cv . warpAffine (I , T_forward , I . shape [:2][:: -1])
10
11 # Backward transform
12 T_backward = cv . get Af fi neT ra ns for m ( Pdst , Psrc )
13 Iaffine_back = cv . warpAffine ( Iaffine , T_backward , I . shape [:2][:: -1])
14
15 ShowImages ([( " Source image " , I ) ,
16 ( " Affine transform " , Iaffine ) ,
17 ( " Backward transform " , Iaffine_back ) ] , 3)
12
3.1.6 Self-work [Link] - Скос изображения
Условие: Реализовать преобразование скоса изображения с параметром s = 0.4.
1 # TODO Place your solution here
2 # Bevel transform with s = 0.4
3
4 s = 0.4
5 T_bevel = np . float32 ([[1 , 0 , 0] ,
6 [s , 1 , 0]])
7
8 new_width = int ( I . shape [1] + s * I . shape [0])
9 Ibevel = cv . warpAffine (I , T_bevel , ( new_width , I . shape [0]) )
10
11 ShowImages ([( " Source image " , I ) ,
12 ( " Bevel transform " , Ibevel ) ] , 2)
13
3.1.7 Self-work [Link] - Кусочно-линейное отображение
Условие: Масштабировать правую часть изображения с коэффициентом 0.4.
1 # TODO Place your solution here
2 # Fill the transformation matrix
3 # Split and display image parts
4 # Transform right part and stitch
5 # Display the result
6 # Piecewise linear mapping : scale right half by 0.4
7
8 stretch = 0.4
9 split_x = I . shape [1] // 2
10
11 T = np . float32 ([[ stretch , 0 , 0] ,
12 [0 , 1 , 0]])
13
14 Ileft = I [: , : split_x , :]
15 Iright = I [: , split_x : , :]
16
17 Iright_scaled = cv . warpAffine ( Iright , T , ( int ( Iright . shape [1] * stretch ) ,
Iright . shape [0]) )
18 Iplm2 = np . concatenate (( Ileft , Iright_scaled ) , axis =1)
19
20 ShowImages ([( " Source image " , I ) ,
21 ( " Piecewise linear mapping " , Iplm2 ) ] , 2 , hide_axes = False )
Краткий вывод: Правая часть изображения была сжата с коэффициентом 0.4, тогда
как левая часть осталась без изменений. В результате наблюдается локальное геометри-
ческое преобразование только выбранной области изображения.
14
3.2 Задание 1.4 - Нелинейные преобразования
3.2.1 Self-work [Link] - Обратное перспективное преобразование
Условие: Выполнить обратное перспективное преобразование изображения ‘Ipersp2‘,
используя точки ‘Pdst‘ как исходные и ‘Psrc‘ как целевые.
1 # TODO Place your solution here
2 # Calculate the perspective transformation matrix for transformation from
Pdst to Psrc
3 # Apply the perspective transformation with cv2 . warpPerspective () function
4 # Display the result
5 # Backward perspective transformation
6
7 Psrc = np . float32 ([[50 , 461] , [461 , 461] , [461 , 50] , [50 , 50]])
8 Pdst = np . float32 ([[50 , 461] , [461 , 440] , [450 , 10] , [100 , 50]])
9
10 # Forward transformation
11 T_forward = cv . g e t P e r s p e c t i v e T r a n s f o r m ( Psrc , Pdst )
12 Ipersp2 = cv . warpPerspective (I , T_forward , I . shape [:2][:: -1])
13
14 # Backward transformation
15 T_backward = cv . g e t P e r s p e c t i v e T r a n s f o r m ( Pdst , Psrc )
16 Ipersp3 = cv . warpPerspective ( Ipersp2 , T_backward , I . shape [:2][:: -1])
17
18 ShowImages ([( " Source image " , I ) ,
19 ( " Perspective transformation " , Ipersp2 ) ,
20 ( " Backward transformation " , Ipersp3 ) ] , 3)
15
3.2.2 Self-work [Link] - Полиномиальное отображение
Условие: Реализовать полиномиальное отображение по формулам:
x′ = 0 + 1 · x + 0 · y + 0 · x2 + 0 · xy + 0 · y 2
y ′ = 0 + 0 · x + 1 · y + 0.001 · x2 + 0.002 · xy + 0.00001 · y 2
1
2 # TODO Place your solution here
3 # Fill the polynomial mapping parameters array
4 # Create mesh grid for X , Y coordinates
5 # Calculate new coordinates for X , Y according to formula
6 # Create a mask where new coordinates are valid
7 # Apply new coordinates
8 # Display the result
9 Ipoly2 = np . zeros_like ( I )
10 # Polynomial mapping parameters for y - axis distortion
11 # x ’ = 0 + 1* x + 0* y + 0* x ^2 + 0* x * y + 0* y ^2
12 # y ’ = 0 + 0* x + 1* y + 0.001* x ^2 + 0.002* x * y + 0.00001* y ^2
13 T = np . array ([[0 , 0] , # constant terms
14 [1 , 0] , # x terms
15 [0 , 1] , # y terms
16 [0 , 0.001] , # x ^2 terms
17 [0 , 0.002] , # x * y terms
18 [0 , 0.00001]]) # y ^2 terms
19
20 # Create mesh grid
21 x , y = np . meshgrid ( np . arange ( I . shape [1]) , np . arange ( I . shape [0]) )
22
33 # Apply mapping
34 Ipoly2 = np . zeros ( I . shape , I . dtype )
35 Ipoly2 [ y_new [ mask ]. astype ( int ) , x_new [ mask ]. astype ( int ) , :] = I [ y [ mask ] , x [
mask ] , :]
36
37 ShowImages ([( " Original Image " , I ) ,
38 ( " Polynomial Mapping ( Y distortion ) " , Ipoly2 ) ])
16
Рис. 23: Результат полиномиального отображения
17
3.2.3 Self-work [Link] - Полиномиальное отображение с интерполяцией (Оп-
ционально)
Условие: Доработать алгоритм для заполнения пикселей с неопределенными значе-
ниями.
1 # TODO Place your solution for optional task here
2 # Fill undefined intensity values ( holes ) in the polynomial mapped image
3 # Fill holes after polynomial mapping
4
5 gray = cv . cvtColor ( Ipoly2 , cv . COLOR_BGR2GRAY )
6 hole_mask = ( gray == 0) . astype ( np . uint8 ) * 255
7
8 Ipoly2_filled = cv . inpaint ( Ipoly2 , hole_mask , 3 , cv . INPAINT_TELEA )
9
10 ShowImages ([( " Polynomial mapping " , Ipoly2 ) ,
11 ( " Filled result " , Ipoly2_filled ) ] , 2)
18
3.2.4 Self-work [Link] - Синусоидальное искажение по оси Oy
Условие: Реализовать синусоидальное искажение вдоль оси Oy с теми же параметра-
ми.
1 # TODO Place your solution here
2 # Create mesh grid for X , Y coordinates
3 # Distort the Y coordinate depending on X
4 # Remap with new coordinates
5 # Sinusoidal distortion along Oy
6
7 x , y = np . meshgrid ( np . arange ( I . shape [1]) , np . arange ( I . shape [0]) )
8 y_new = y + 20 * np . sin (2 * math . pi * x / 90)
9
10 Isin_y = cv . remap (I , x . astype ( np . float32 ) , y_new . astype ( np . float32 ) , cv .
INTER_LINEAR )
11
12 ShowImages ([( " Source image " , I ) ,
13 ( " Sinusoidal distortion Oy " , Isin_y ) ] , 2)
19
3.3 Задание 2. Коррекция дисторсии
3.3.1 Self-work 2.1.1 - Бочкообразная дисторсия и коррекция
Условие: Создать искажение по формуле R
⃗ = ⃗r − 0.2 · r2⃗r + 0.32 · r4⃗r и выполнить
коррекцию.
1 # Barrel distortion : R = r - 0.2* r ^3 + 0.32* r ^5
2
3 x , y = np . meshgrid ( np . arange ( I . shape [1]) , np . arange ( I . shape [0]) )
4
11 b0 = 1.0
12 F3 = -0.2
13 F5 = 0.32
14
15 # Distortion
16 r_dist = b0 * r + F3 * r **3 + F5 * r **5
17 u , v = cv . polarToCart ( r_dist , theta )
18 u = u * mid [0] + mid [0]
19 v = v * mid [1] + mid [1]
20
21 Ibarrel_self = cv . remap (I , u . astype ( np . float32 ) , v . astype ( np . float32 ) , cv .
INTER_LINEAR )
22
23 # Correction
24 d = 5
25 max_r = 1.5
26 Psrc = ( np . arange (d , dtype = np . float32 ) + 1) / d * max_r
27 Pdst = b0 * Psrc + F3 * Psrc **3 + F5 * Psrc **5
28
29 T = np . zeros (( d , d ) )
30 for i in range ( d ) :
31 T [: , i ] = Pdst ** ( i + 1)
32
33 F = np . matmul ( np . linalg . inv ( T ) , Psrc )
34
35 r_corr = np . zeros_like ( r )
36 for i in range ( d ) :
37 r_corr += F [ i ] * r_dist ** ( i + 1)
38
39 u_corr , v_corr = cv . polarToCart ( r_corr , theta )
40 u_corr = u_corr * mid [0] + mid [0]
41 v_corr = v_corr * mid [1] + mid [1]
42
43 Iba rrel_corr _self = cv . remap ( Ibarrel_self ,
44 u_corr . astype ( np . float32 ) ,
45 v_corr . astype ( np . float32 ) ,
46 cv . INTER_LINEAR )
47
48 ShowImages ([
49 ( " Source image " , I ) ,
50 ( " Barrel distortion " , Ibarrel_self ) ,
51 ( " Distortion correction " , Iba rrel_cor r_self )
52 ] , 3)
20
Листинг 14: Бочкообразная дисторсия и коррекция (Self-work 2.1.1)
21
3.3.2 Self-work 2.2.1 - Подушкообразная дисторсия и коррекция
Условие: Создать искажение по формуле R
⃗ = 1.3 · ⃗r − 0.2 · r2⃗r + 0.05 · r4⃗r и выполнить
коррекцию.
1 # Pincushion distortion : R = 1.3* r - 0.2* r ^3 + 0.05* r ^5
2
3 x , y = np . meshgrid ( np . arange ( I . shape [1]) , np . arange ( I . shape [0]) )
4
11 b0 = 1.3
12 F3 = -0.2
13 F5 = 0.05
14
15 # Distortion
16 r_dist = b0 * r + F3 * r **3 + F5 * r **5
17 u , v = cv . polarToCart ( r_dist , theta )
18 u = u * mid [0] + mid [0]
19 v = v * mid [1] + mid [1]
20
21 Ipincushion_self = cv . remap (I , u . astype ( np . float32 ) , v . astype ( np . float32 ) ,
cv . INTER_LINEAR )
22
23 # Correction
24 d = 5
25 max_r = 1.8
26 Psrc = ( np . arange (d , dtype = np . float32 ) + 1) / d * max_r
27 Pdst = b0 * Psrc + F3 * Psrc **3 + F5 * Psrc **5
28
29 T = np . zeros (( d , d ) )
30 for i in range ( d ) :
31 T [: , i ] = Pdst ** ( i + 1)
32
33 F = np . matmul ( np . linalg . inv ( T ) , Psrc )
34
35 r_corr = np . zeros_like ( r )
36 for i in range ( d ) :
37 r_corr += F [ i ] * r_dist ** ( i + 1)
38
39 u_corr , v_corr = cv . polarToCart ( r_corr , theta )
40 u_corr = u_corr * mid [0] + mid [0]
41 v_corr = v_corr * mid [1] + mid [1]
42
43 Ip i n c u s h i o n _ c o r r _ s e l f = cv . remap ( Ipincushion_self ,
44 u_corr . astype ( np . float32 ) ,
45 v_corr . astype ( np . float32 ) ,
46 cv . INTER_LINEAR )
47
48 ShowImages ([
49 ( " Source image " , I ) ,
50 ( " Pincushion distortion " , Ipincushion_self ) ,
51 ( " Distortion correction " , I p i n c u s h i o n _ c o r r _ s e l f )
52 ] , 3)
22
Рис. 27: Подушкообразная дисторсия и её коррекция
23
3.4 Задание 3. Сшивка изображений
3.4.1 Self-work 3.1.1 - Ручная сшивка изображений
Условие: Разделить изображение на две части и выполнить их сшивку.
1 # TODO Place your solution here
2 # Split image into two overlapping parts
3 split_point = int ( I . shape [0] / 2) + 20
4 Itop_self = I [0: split_point , : , :]
5 Ibottom_self = I [ split_point -20: , : , :] # Overlap of 20 pixels
6
7 ShowImages ([( " Top Part " , Itop_self ) ,
8 ( " Bottom Part " , Ibottom_self ) ])
9
10 # Match template from bottom of top image
11 templ_size = 20
12 templ = Itop_self [ - templ_size : , : , :]
13 res = cv . matchTemplate ( Ibottom_self , templ , cv . TM_CCOEFF )
14 min_val , max_val , min_loc , max_loc = cv . minMaxLoc ( res )
15
16 # Stitch images
17 Istitch_self = np . zeros (( Itop_self . shape [0] + Ibottom_self . shape [0] -
max_loc [1] - templ_size ,
18 I . shape [1] , I . shape [2]) , dtype = np . uint8 )
19 Istitch_self [0: Itop_self . shape [0] , : , :] = Itop_self
20 Istitch_self [ Itop_self . shape [0]: , : , :] = Ibottom_self [ max_loc [1] +
templ_size : , : , :]
21
24
4 Ответы на контрольные вопросы
1. Как можно повернуть изображение без использования матрицы поворота?
Ответ:
25
5 Заключение
В ходе выполнения данной практической работы были изучены основные методы гео-
метрических преобразований изображений и их практическое применение в задачах циф-
ровой обработки изображений. Были рассмотрены как линейные преобразования, включая
сдвиг, отражение, масштабирование, поворот, скос и кусочно-линейное отображение, так и
нелинейные преобразования, такие как перспективное, полиномиальное и синусоидальное
искажения.
В практической части были реализованы алгоритмы прямого и обратного аффинного
и перспективного преобразования, выполнено моделирование полиномиальных и синусо-
идальных искажений, а также исследованы методы коррекции бочкообразной и подушко-
образной дисторсии. Кроме того, была выполнена простая ручная сшивка изображения
на основе поиска перекрывающейся области.
Выводы:
26