3

Right now I'm trying to write some Halide code that subsamples an image. Basically I want every 2 by 2 square of the image to be reduced to one pixel that contains the maximum. A simple example would be transforming

1 2 3 4
5 6 7 8
9 0 1 2
4 3 5 6

into

6 8
9 6

Right now I'm trying something along the lines of (I'm aware that this would give the sum instead of the maximum, but it's a toy example of the same process):

Halide::Image<uint8_t> input = load<uint8_t>("test.png");        
Halide::Image<uint8_t> output(input.width() / 2, input.height() / 2, input.channels());

 Halide::Func subsample;
 Halide::Var c;

 for (int i = 0; i < input.height(); i += 2) {
     for (int j = 0; j < input.width(); j += 2) {
         Halide::RDom r = Halide::RDom(i, 2, j, 2);
         subsample(i, j, c) += input(r.x, r.y, c);
     }
 }

 subsample.realize(output);
 save(output, "test.png");

However, this code runs infinitely. (I'm not sure why). I know I can use Halide::RDom to represent a reduce operation over some range. However, in no example I find can you pass a variable into a random domain object.

EDIT:

After playing around with Halide some more, I was able to construct this:

subsample(x, y, c) = Halide::max(input(2*x,2*y,c),input(2*x+1,2*y,c));
subsample(x, y, c) = Halide::max(subsample(x,y,c),input(2*x,2*y+1,c));
subsample(x, y, c) = Halide::max(subsample(x,y,c),input(2*x+1,2*y+1,c));

To get a 2x2 max reduction. However, when I put this in a loop, it won't call because it cannot be defined. Is there anyway to put this in terms of a domain reduction?

Alnitak
  • 334,560
  • 70
  • 407
  • 495
Philip Massey
  • 1,401
  • 3
  • 14
  • 24

3 Answers3

2

I think argmax (which is embedded Halide function) can be used for what you want :)

#include "Halide.h"
#include <stdio.h>

uint8_t data[16] = {
    1, 2, 3, 4,
    5, 6, 7, 8,
    9, 0, 1, 2,
    3, 4, 5, 6
};

using namespace Halide;

int main(int argc, char** argv) {
    Halide::Image<uint8_t> input(4, 4); 
    for(int j = 0; j < 4; j++) {
        for(int i = 0; i < 4; i++) {
            input(j, i) = data[j*4 + i];
        }
    }

    Halide::Func f, max2x2;
    Halide::Var x, y, dx, dy;
    Halide::Expr x_ = x * 2;
    Halide::Expr y_ = y * 2;

    f(x, y, dx, dy) = input(x_ + dx, y_ + dy);

    RDom r(0, 2, 0, 2);
    max2x2(x, y) = argmax(f(x, y, r.x, r.y))[2];

    Halide::Image<uint8_t> output(2, 2);
    max2x2.realize(output);

    for(int j = 0; j < 2; j++) {
        for(int i = 0; i < 2; i++) {
            printf("%d ", output(j, i));
        }
        printf("\n");
    }
    return 0;
}
GreatAS
  • 21
  • 1
1

After looking more into Halide, I realized I could get what I wanted with this:

Halide::Func subsample;
Halide::Var x, y, c;

Halide::RDom r(0, size, 0, size);

subsample(x, y, c) = input(size * x, size * y, c);
subsample(x, y, c) = Halide::max(input(size*x + r.x, size*y + r.y, c), 
    subsample(x,y,c));
Philip Massey
  • 1,401
  • 3
  • 14
  • 24
0

I think you just want a much simpler pure function definition (no C++ loops, which don't do what I think you are expecting them to do…; no RDoms):

// using Halide::max
subsample(x,y,c) = max( max( input(2*x,2*y  ), input(2*x+1,2*y  ) ),
                        max( input(2*x,2*y+1), input(2*x+1,2*y+1) ) );
jrk
  • 2,896
  • 1
  • 22
  • 35