Геометрия съёмки: GSD, footprint, перекрытия, шаг¶
Это самый простой слой задачи и одновременно фундамент всего остального: из четырёх параметров камеры и требуемого разрешения однозначно, без всякой оптимизации, следуют высота полёта, ширина захвата, шаг галсов и интервал съёмки. Ошибки здесь тихие и отравляют всё выше, поэтому слой должен быть покрыт юнит-тестами с точными числами.
Обозначения¶
| Символ | Что | Единицы |
|---|---|---|
H |
высота полёта над поверхностью (AGL) | м |
f |
фокусное расстояние | мм |
Sw, Sh |
ширина и высота матрицы | мм |
ImW, ImH |
размер кадра в пикселях | пикс |
p |
шаг пикселя (Sw / ImW) |
мм |
GSD |
размер пикселя на земле | м/пикс |
Dw, Dh |
наземный отпечаток кадра (footprint) | м |
q |
поперечное перекрытие (side overlap) | доля 0…1 |
p_fwd |
продольное перекрытие (forward overlap) | доля 0…1 |
By |
межмаршрутное расстояние = шаг галсов | м |
Bx |
базис фотографирования = шаг съёмки вдоль галса | м |
V_g |
путевая скорость | м/с |
Основные формулы¶
GSD из высоты¶
GSD = H · Sw / (f · ImW) [м/пикс]
Эквивалентно через шаг пикселя: GSD = H · p / f.
Формула — стандартное подобие треугольников в центральной проекции; выражена ровно так же у Pix4D,
Inertial Labs, JOUAV и в QGroundControl (ImageDensity / DistanceToSurface).
Высота из GSD (обратная задача — то, что нужно нам)¶
H = GSD · f · ImW / Sw
Пользователь задаёт требуемое разрешение, сервис считает высоту. Именно так работает QGC («задать наземное разрешение → рассчитывается требуемая высота»), и так же должен работать наш UI.
Проверка допустимости обязательна. Полученная H должна укладываться в:
H ≥ altitude_agl_minборта (у 201 — 100 м);H ≤ altitude_agl_maxборта (у Gemini — 500 м);H+ рельеф ≤altitude_asl_max;Hвнутри разрешённого воздушного пространства (R-IN-5), с учётом порога 150 м из ФП-138 — см.06-airspace-ru.md.
Если требуемый GSD недостижим ни одним бортом парка, сервис обязан сказать это явной ошибкой валидации входа, а не молча выдать план. Это отдельный тестовый сценарий.
Наземный отпечаток кадра¶
Dw = GSD · ImW = H · Sw / f [м]
Dh = GSD · ImH = H · Sh / f [м]
Заметьте: footprint не зависит от числа пикселей — только от геометрии оптики и матрицы. Число пикселей влияет только на GSD.
Ориентация камеры¶
Какой из размеров идёт поперёк маршрута, зависит от установки камеры. В QGC это флаг Landscape.
| Ориентация | Поперёк маршрута | Вдоль маршрута |
|---|---|---|
| Landscape (длинная сторона поперёк) | Dw |
Dh |
| Portrait | Dh |
Dw |
Дальше обозначаем: W_across — поперечный размер, W_along — продольный.
Landscape выгоднее для покрытия площади: шире захват → меньше галсов → меньше разворотов. Portrait даёт больше кадров на ту же площадь при том же продольном перекрытии. Дефолт — landscape.
Шаг галсов и шаг съёмки¶
By = W_across · (1 − q) [м] межмаршрутное расстояние
Bx = W_along · (1 − p_fwd) [м] базис фотографирования
Интервал срабатывания затвора¶
Δt = Bx / V_g [с]
Ограничение сверху на скорость: если у камеры минимальный интервал срабатывания Δt_min
(в QGC — MinTriggerInterval), то
V_g ≤ Bx / Δt_min
Борт с быстрым крейсером и медленной камерой вынужден лететь медленнее расчётного. У Riebo заявлена скорость затвора 1/100–1/2000 с, но это выдержка, а не интервал между кадрами — интервал в выданных материалах не указан. В «известные ограничения».
Смаз изображения¶
smear = V_g · t_exp [м]
Правило практики: smear ≤ GSD (иначе теряется заявленное разрешение). При V_g = 28 м/с и выдержке
1/1000 с смаз 2,8 см — на грани при GSD 3 см. Для мультиспектра и ИК с длинными выдержками это
реальное ограничение скорости. Опционально, но на защите смотрится сильно.
Количество галсов и кадров¶
Для прямоугольника L_across × L_along:
N_transects = ceil(L_across / By) (иногда +1 для гарантии краёв)
L_total = N_transects · L_along длина съёмочной части
N_photos = N_transects · (ceil(L_along / Bx) + 1)
N_turns = N_transects − 1
N_turns — то, что надо минимизировать выбором угла галсов, потому что каждый разворот стоит времени
и энергии. См. 03-coverage-path-planning.md.
Время съёмочной части (наивно и честно)¶
наивно: T = L_total / V_g
честно: T = L_total / V_g + N_turns · t_turn + T_climb + T_transit
Наивная оценка систематически оптимистична. На полигоне 1×1 км с шагом галсов 100 м это 9 разворотов; для самолёта с радиусом разворота 136 м каждый стоит 15–25 с — то есть 2,5–4 минуты сверху к расчётным ~6 минутам съёмки. Ошибка под 50 %.
Проверочные числа для тестов¶
Считано по данным из 10-hardware (../10-hardware/), должно воспроизводиться юнит-тестами.
Geoscan PF1B на Gemini (Sw = 23,5, ImW = 6000, f = 20)¶
Коэффициент: GSD = H · 1,9583·10⁻⁴
| H, м | GSD, см/пикс | Dw × Dh, м | By @ q=60% | Bx @ p=70% |
|---|---|---|---|---|
| 100 | 1,96 | 117 × 78 | 47,0 | 23,5 |
| 150 | 2,94 | 176 × 117 | 70,5 | 35,2 |
| 200 | 3,92 | 235 × 157 | 94,0 | 47,0 |
| 255 | 5,00 | 300 × 200 | 120,0 | 60,0 |
| 500 (потолок) | 9,79 | 587 × 392 | 235,0 | 117,5 |
При V_g = 10 м/с и H = 150 м интервал съёмки Δt = 35,2 / 10 = 3,5 с.
Pollux (Sw = 4,968, ImW = 1440, f = 8)¶
Коэффициент: GSD = H · 4,3125·10⁻⁴ — в 2,2 раза грубее PF1B.
| H, м | GSD, см/пикс | Dw × Dh, м | By @ q=75% |
|---|---|---|---|
| 100 | 4,31 | 62,1 × 46,6 | 15,5 |
| 150 | 6,47 | 93,2 × 69,9 | 23,3 |
| 200 | 8,63 | 124,2 × 93,2 | 31,1 |
Сравнение при одинаковом GSD = 4,31 см: PF1B летит на 220 м с By (при q=60%) = 103 м, Pollux на
100 м с By (при q=75%) = 15,5 м. Разница в шаге галсов — 6,6 раза, то есть мультиспектральный
проход над тем же полигоном требует в 6,6 раза больше галсов. Это и есть ответ, почему нельзя сводить
задание к абстрактной «площади».
Тепловизор 801 (Sw = 7,68 ᵃ, ImW = 640, f = 9,1)¶
Коэффициент: GSD = H · 1,3187·10⁻³ (опирается на допущение о шаге пикселя 12 мкм).
| H, м | GSD, см/пикс | Dw × Dh, м | By @ q=75% |
|---|---|---|---|
| 50 | 6,59 | 42,2 × 33,8 | 10,6 |
| 100 | 13,19 | 84,4 × 67,5 | 21,1 |
| 150 | 19,78 | 126,6 × 101,2 | 31,6 |
Контракт модуля¶
def gsd(payload, altitude_m) -> float: # м/пикс
def altitude_for_gsd(payload, gsd_m) -> float: # м, + проверка допустимости для борта
def footprint(payload, altitude_m) -> (across, along)
def swath_spacing(payload, altitude_m, survey_type, side_overlap) -> float
def trigger_interval(payload, altitude_m, ground_speed, fwd_overlap) -> float
Для LiDAR и геофизики swath_spacing считается по-другому (не через footprint кадра) —
см. 02-survey-types.md. Поэтому survey_type в сигнатуре есть с самого начала.
Источники¶
- Формула GSD и её обратная: Pix4D — GSD in photogrammetry, Inertial Labs, JOUAV, Wikipedia — Ground sample distance
- Параметры Survey и двусторонний расчёт «высота ↔ разрешение»: QGC — Survey Pattern
MinTriggerInterval,AdjustedFootprintFrontal/Side: QGC — Plan File Format- Термины «базис фотографирования», «межмаршрутное расстояние», расчёт числа снимков: Аэрофотосъёмочные работы