Skip to content

Instantly share code, notes, and snippets.

@sschnug
Last active April 17, 2018 20:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sschnug/c8eeaf5cd81eb1ec04220fb36bb202c7 to your computer and use it in GitHub Desktop.
Save sschnug/c8eeaf5cd81eb1ec04220fb36bb202c7 to your computer and use it in GitHub Desktop.
#include "Halide.h"
#include "Halide/tools/halide_image_io.h"
#include <iostream>
// This code calculates a block based mean on some a-priori known image-dimensions (1 uint8_t channel)
// An example image to process: http://i.imgur.com/Eyo0Xvc.png
// No customized scheduling within this code, but the SO-answer gives some recommendation!
int main(int argc, char **argv) {
Halide::Buffer<uint8_t> input = Halide::Tools::load_image("TestImages/block_example.png");
// This is a simple example assumes an input of 64x128
std::cout << "dim 0: " << input.width() << std::endl;
std::cout << "dim 1: " << input.height() << std::endl;
// The "outer" (block) and "inner" (pixel) indices that describe a pixel in a tile.
Halide::Var xo, yo, xi, yi, x, y;
// The distance between the start of each tile in the input.
int tile_stride_x = 32;
int tile_stride_y = 64;
int tile_size_x = 32;
int tile_size_y = 64;
Halide::Func tiled_f;
tiled_f(xi, yi, xo, yo) = input(xo * tile_stride_x + xi, yo * tile_stride_y + yi);
Halide::RDom tile_dom(0, tile_size_x, 0, tile_size_y);
Halide::Func tile_means;
tile_means(xo, yo) = sum(Halide::cast<uint32_t>(tiled_f(tile_dom.x, tile_dom.y, xo, yo))) / (tile_size_x * tile_size_y);
Halide::Func output;
output(xo, yo) = Halide::cast<uint8_t>(tile_means(xo, yo));
Halide::Buffer<uint8_t> output_(2, 2);
output.realize(output_);
Halide::Tools::save_image(output_, "block_based_stuff.png");
}
@dsharletg
Copy link

I think the problem in this code is actually just that the sum is overflowing, and the division is probably not helping either. Try changing line 27 to:

tile_means(xo, yo) = sum(cast<uint16_t>(tiled_f(tile_dom.x, tile_dom.y, xo, yo))) / (tile_size_x * tile_size_y));

(Note I also added parens around tile_size_x * tile_size_y, since it probably wasn't doing what you wanted before.)

This will produce a uint16 sum instead of a uin8 sum. You'll need to change the output to uint16 as well, or cast the sum (after dividing by tile_size_x * tile_size_y) back to uint8.

@sschnug
Copy link
Author

sschnug commented Apr 18, 2017

@dsharletg Output is now row 0: 16, 0 row 1: 0, 16. Better, but still not what was expected (16, 64; 32, 48). I will have a look tomorrow about my block-constant logic. Thanks for the comment! (And casting before buffer-stuff results in a lot of compile-time errors while this worked for my other simple examples; Halide/tools/halide_image_io.h:579:42: error: no matching function for call to ‘convert(std::enable_if<true, Halide::FuncRef>::type, uint16_t&)’ Internal::convert(im(x, y, c), value); which indicates some other problem before that)

@dsharletg
Copy link

Sorry, I think it might still be overflowing. I did some boneheaded math when deciding uint16 was enough, but it's not: 32 * 64 > 256, which is the maximum number of pixels in a tile that you can have before overflowing a uint16 accumulator of uint8 values. You need to be accumulating into a uint32 result before dividing.

The second error you mention I think is just happening probably because save_image doesn't support 16 bit buffers.

@sschnug
Copy link
Author

sschnug commented Apr 18, 2017

@dsharletg Amazing. Indeed the buffer should be uint8 before using Halide::Tools::save_image. And the cast-before-output is now working too (i don't know what went wrong before). Everything is fine now! Thanks for all your help! I will add this tiny example to my SO-question as edit based on your answer and mark it as accepted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment