How to mirror a vector of subpixels?

Viewed 123

I have a flat image buffer of subpixels (every 3 elements is a pixel so this is a 3x3 image)

let width = 3;
let input = vec![
     1,  2,  3,  4,  5,  6,  7,  8,  9,
    11, 12, 13, 14, 15, 16, 17, 18, 19,
    21, 22, 23, 24, 25, 26, 27, 28, 29,
];

I want to mirror it horizontally and vertically (by pixel not subpixel) to get this output

let output = vec![
     1,  2,  3,  4,  5,  6,  7,  8,  9,  7,  8,  9,  4,  5,  6,  1,  2,  3,
    11, 12, 13, 14, 15, 16, 17, 18, 19, 17, 18, 19, 14, 15, 16, 11, 12, 13,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 27, 28, 29, 24, 25, 26, 21, 22, 23,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 27, 28, 29, 24, 25, 26, 21, 22, 23,
    11, 12, 13, 14, 15, 16, 17, 18, 19, 17, 18, 19, 14, 15, 16, 11, 12, 13,
     1,  2,  3,  4,  5,  6,  7,  8,  9,  7,  8,  9,  4,  5,  6,  1,  2,  3,
];

As you can see the first input pixel will always be in the corners (in this case 1, 2, 3) and the last input pixel will be the 4 central pixels (in this case 27, 28, 29)

I have a some code that will produce the horizontal mirror that may be helpful but I haven't been able to chain it together to produce then entire output.

Here is a minimal example with my code so far

fn main() {
    let width = 3;

    let input = vec![
        1,  2,  3,  4,  5,  6,  7,  8,  9,
       11, 12, 13, 14, 15, 16, 17, 18, 19,
       21, 22, 23, 24, 25, 26, 27, 28, 29,
    ];

    let output = vec![
        1,  2,  3,  4,  5,  6,  7,  8,  9,  7,  8,  9,  4,  5,  6,  1,  2,  3,
       11, 12, 13, 14, 15, 16, 17, 18, 19, 17, 18, 19, 14, 15, 16, 11, 12, 13,
       21, 22, 23, 24, 25, 26, 27, 28, 29, 27, 28, 29, 24, 25, 26, 21, 22, 23,
       21, 22, 23, 24, 25, 26, 27, 28, 29, 27, 28, 29, 24, 25, 26, 21, 22, 23,
       11, 12, 13, 14, 15, 16, 17, 18, 19, 17, 18, 19, 14, 15, 16, 11, 12, 13,
        1,  2,  3,  4,  5,  6,  7,  8,  9,  7,  8,  9,  4,  5,  6,  1,  2,  3,
   ];


   // This code is only able to output the horizonal mirror of the pixels
    let mirror = input
        .chunks_exact(width * 3)
        .flat_map(|chunk| chunk.rchunks_exact(3))
        .flatten()
        .copied()
        .collect::<Vec<_>>();

    assert_eq!(mirror, output);
}
1 Answers

The following could be a solution, but there might be a more optimal way:

const WIDTH: usize = 3;
const HEIGHT: usize = 3;
const CHANNELS: usize = 3;

// Mirror image in the vertical and horizontal direction   
fn mirror(source: &[u8]) -> Vec<u8> {
    let mut output: Vec<u8> = Vec::with_capacity(source.len() * 4);
    
    for data in source.chunks_exact(WIDTH * CHANNELS) {
        // Add source pixels
        output.extend(data);
        // Vertical mirror
        output.extend(data.rchunks(CHANNELS).flatten());
    }
    
    // Horizontal mirror
    for row in (0..HEIGHT).rev() {
        let start = row * (WIDTH * 2 * CHANNELS);
        let end = start + (WIDTH * 2 * CHANNELS);
        
        output.extend_from_within(start..end);
    }
    
    output
}

fn main() {
    let source = vec![
        1,  2,  3,  4,  5,  6,  7,  8,  9,
        11, 12, 13, 14, 15, 16, 17, 18, 19,
        21, 22, 23, 24, 25, 26, 27, 28, 29,
    ];
    
    let result = mirror(&source);

    // Print rows
    for row in result.chunks_exact(WIDTH * 2 * CHANNELS) {
        println!("{:?}", row);    
    }
}

Playground

The above should print out the following:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 7, 8, 9, 4, 5, 6, 1, 2, 3]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 17, 18, 19, 14, 15, 16, 11, 12, 13]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 27, 28, 29, 24, 25, 26, 21, 22, 23]
[21, 22, 23, 24, 25, 26, 27, 28, 29, 27, 28, 29, 24, 25, 26, 21, 22, 23]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 17, 18, 19, 14, 15, 16, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 7, 8, 9, 4, 5, 6, 1, 2, 3]
Related