Rust 2D итератор подокна - PullRequest
       22

Rust 2D итератор подокна

0 голосов
/ 28 января 2020

Я использую Vec для хранения 2D (основной ряд) матрицы значений. Я хотел бы перебрать эту матрицу со скользящим 2D-подокном, чтобы применить фильтр (который, к сожалению, нельзя разделить).

Я видел в документации по срезу, что существует функция windows, которая это то, что я хочу, но в двух измерениях.

Я думал о реализации этого как:

fn main() {
    // 4 rows 3 columns
    let dim: (usize, usize) = (4, 3);
    // Place-holder matrix
    #[rustfmt::skip]
    let mat = vec![0,  1,  2,
                   3,  4,  5,
                   6,  7,  8,
                   9, 10, 11];

    // 2D index to 1D index
    let linearize = |r, c| r * dim.1 + c;
    // The dimensions of my sub-window
    let win_size: usize = 2;
    // Calculate the bounds for which the top left corner of each window may exist
    let bounds: (usize, usize) = (dim.0 - win_size + 1, dim.1 - win_size + 1);
    // Convert window 1D index into a 2D index
    let split = |i| (i / win_size, i % win_size);

    // Iterate over all the top left corners
    let window_2d = (0..bounds.0 * bounds.1).map(|i| {
        // Get the 2D index of the top left corner
        let (r, c) = (i / bounds.1, i % bounds.1);
        // Borrow the matrix, so our closure may own the reference
        let bmat = &mat;
        // Return an iterator for this window
        return (0..win_size * win_size).map(move |x| {
            let (wr, wc) = split(x);
            return bmat[linearize(wr + r, wc + c)];
        });
    });

    // Print the windows out
    window_2d.for_each(|it| {
        print!("[ ");
        it.for_each(|x| print!("{} ", x));
        println!("]");
    });
}

По сути, создание итератора для диапазона индексов, а затем сопоставление с оператором квадратной скобки матрица. Насколько я знаю, это будет иметь накладные расходы на проверку границ для каждой разыменования итератора.

Мне интересно, есть ли альтернатива, которая исключила бы проверки границ? Может быть, используя комбинацию chunks, windows и zip, чтобы разделить матрицу на строки, каждая со скользящим окном, затем сжать строку windows и сгладить результат?

Спасибо!

Редактировать : Я не хочу просто перебирать 2D-массив, я хочу скользить 2D-окном по массиву, подобно тому, как работает функция std::slice::windows.

1 Ответ

0 голосов
/ 29 января 2020

Лучшее, что у меня есть на данный момент, - это обернуть доступ к матрице в небезопасный блок, чтобы исключить проверку границ.

С некоторыми другими изменениями в c, теперь это полный пример:

fn split_factory(cols: usize) -> impl Fn(usize) -> (usize, usize) {
    // Declaring that cols must be positive allows more aggressive optimisation of div and mod.
    if cols < 1 {
        unreachable!()
    }
    move |i| (i / cols, i % cols)
}

fn main() {
    // 4 rows 3 columns
    let dim: (usize, usize) = (4, 3);
    // Place-holder matrix
    #[rustfmt::skip]
    let mat = vec![0,  1,  2,
                   3,  4,  5,
                   6,  7,  8,
                   9, 10, 11];

    // The dimensions of my sub-window
    let win_dim = (3usize, 2usize);
    // Calculate the bounds for which the top left corner of each window may exist
    let bounds = (dim.0 - win_dim.0 + 1, dim.1 - win_dim.1 + 1);
    // Iterate over all the top left corners
    let convolution_iter = (0..bounds.0 * bounds.1)
        .map(split_factory(bounds.1))
        .map(|(r, c)| {
            // Borrow the matrix, so our closure may own the reference
            let bmat = &mat;
            // Return an iterator for this window
            return (0..win_dim.0 * win_dim.1)
                .map(split_factory(win_dim.1))
                .map(move |(wr, wc)| {
                    let px = (wr + r) * dim.1 + (wc + c);
                    (px, unsafe { *bmat.get_unchecked(px) })
                });
        });

    // Print the windows out (badly...)
    convolution_iter.for_each(|it| println!("{:?}", it.collect::<Vec<(usize, i32)>>()));
}

Было бы еще лучше избегать unsafe и косвенного просмотра матрицы с индексами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...