Processamento de Sinais Geoespaciais: Convolução 2D em Rust para Sensoriamento Remoto Massivo

Implementação matemática baseada em B.P. Lathi para imagens de satélite. Foco em otimização de cache, alocação zero e processamento determinístico para arrays massivos.
Autor

Principal Software Engineer

Data de Publicação

24 de junho de 2026

Neste artigo, exploramos a formulação clássica de processamento de sinais digitais (DSP) estabelecida por B.P. Lathi, expandida para o domínio bidimensional espacial. A convolução discreta 2D entre um sinal \(f[m, n]\) e um kernel \(h[m, n]\) é dada por:

\[ y[m, n] = f[m, n] * h[m, n] = \sum_{j=-\infty}^{\infty} \sum_{i=-\infty}^{\infty} f[i, j] \cdot h[m - i, n - j] \]

Representação Visual

Abaixo, a demonstração da janela deslizante do kernel de convolução sobre o grid espacial.

<video controls width="100%">
  <source src="../../videos/convolution.mp4" type="video/mp4">
</video>

Implementação Determinística em Rust

Focando em Cache-Locality e abstração de custo zero, implementamos o kernel operando em arrays flat estáticos, evitando completamente alocações dinâmicas na heap (como Vec ou Box).

// Convolução 2D determinística (Zero-Heap Allocation)

const WIDTH: usize = 5;
const HEIGHT: usize = 5;
const K_SIZE: usize = 3;

type ImageGrid = [f64; WIDTH * HEIGHT];
type Kernel = [f64; K_SIZE * K_SIZE];

fn convolve_2d(input: &ImageGrid, kernel: &Kernel) -> ImageGrid {
    let mut output = [0.0; WIDTH * HEIGHT];
    let offset = (K_SIZE / 2) as isize;

    for y in 0..HEIGHT as isize {
        for x in 0..WIDTH as isize {
            let mut sum = 0.0;

            for ky in 0..K_SIZE as isize {
                for kx in 0..K_SIZE as isize {
                    let img_y = y + ky - offset;
                    let img_x = x + kx - offset;

                    if img_y >= 0 && img_y < HEIGHT as isize && img_x >= 0 && img_x < WIDTH as isize {
                        let img_idx = (img_y as usize) * WIDTH + (img_x as usize);
                        let kernel_idx = (ky as usize) * K_SIZE + (kx as usize);
                        sum += input[img_idx] * kernel[kernel_idx];
                    }
                }
            }
            output[(y as usize) * WIDTH + (x as usize)] = sum;
        }
    }
    output
}

fn main() {
    let image: ImageGrid = [1.0; 25]; // Exemplo flat
    let edge_kernel: Kernel = [
        -1.0, -1.0, -1.0,
        -1.0,  8.0, -1.0,
        -1.0, -1.0, -1.0,
    ];

    let result = convolve_2d(&image, &edge_kernel);
    println!("Valor central filtrado: {}", result[12]);
}

Visualização do Kernel com Jupyter / Python

Para validar a intuição matemática, podemos visualizar a topologia tridimensional de um kernel (como o filtro passa-altas de borda usado acima) utilizando o ecossistema Python com Plotly. O Quarto suporta a execução nativa destas células:

Figura 1: Representação de Superfície 3D do Kernel de Filtro Espacial (Interativo)