p::object image_to_python_object(const h::Image<> &im) { PyObject *obj = nullptr; if (im.type() == h::UInt(8)) { p::manage_new_object::apply<h::Image<uint8_t> *>::type converter; obj = converter(new h::Image<uint8_t>(im)); } else if (im.type() == h::UInt(16)) { p::manage_new_object::apply<h::Image<uint16_t> *>::type converter; obj = converter(new h::Image<uint16_t>(im)); } else if (im.type() == h::UInt(32)) { p::manage_new_object::apply<h::Image<uint32_t> *>::type converter; obj = converter(new h::Image<uint32_t>(im)); } else if (im.type() == h::Int(8)) { p::manage_new_object::apply<h::Image<int8_t> *>::type converter; obj = converter(new h::Image<int8_t>(im)); } else if (im.type() == h::Int(16)) { p::manage_new_object::apply<h::Image<int16_t> *>::type converter; obj = converter(new h::Image<int16_t>(im)); } else if (im.type() == h::Int(32)) { p::manage_new_object::apply<h::Image<int32_t> *>::type converter; obj = converter(new h::Image<int32_t>(im)); } else if (im.type() == h::Float(32)) { p::manage_new_object::apply<h::Image<float> *>::type converter; obj = converter(new h::Image<float>(im)); } else if (im.type() == h::Float(64)) { p::manage_new_object::apply<h::Image<double> *>::type converter; obj = converter(new h::Image<double>(im)); } else { throw std::invalid_argument("image_to_python_object received an Image of unsupported type."); } return p::object(p::handle<>(obj)); }
int main(int argc, char **argv) { Halide::Func cell("cell"); Halide::Var x, y; cell(x, y) = 0; cell(2, 1) = 1; cell(3, 2) = 1; cell(1, 3) = 1; cell(2, 3) = 1; cell(3, 3) = 1; Halide::Image<int32_t> output; output = cell.realize(NX,NY); Halide::ImageParam input(Halide::Int(32), 2); // int32_t 2D Halide::Func cell2; cell2(x,y)=input(x,y)+1; Halide::Func nbd("nbd"); Halide::Func bc("bc"); for (int t=0; t<10; ++t) { Halide::Image<int32_t> output = cell.realize(NX,NY); for (int j = 0; j < output.height(); j++) { for (int i = 0; i < output.width(); i++) { printf("%1d", output(i, j)); } printf("\n"); } printf("\n"); bc(x,y)=select((x>=0)&&(x<NX)&&(y>=0)&&(y<NY) ,output(min(NX-1,max(x,0)),min(NY-1,max(y,0))),0); nbd(x,y)=-bc(x,y); // staged programming! for(int dy=-1; dy<=1; ++dy) { for(int dx=-1; dx<=1; ++dx) { nbd(x,y)+=bc(x+dx,y+dy); } } cell(x,y)=select((bc(x,y)==1&&nbd(x,y)==3)||(bc(x,y)==1&&nbd(x,y)==2) || (bc(x,y)==0&&nbd(x,y)==3) ,1,0); } return 0; }
void NamedWindow::showImage2D(Halide::Image<uint8_t> im) { static Halide::Func convert("convertToMat2D"); static Halide::ImageParam ip(Halide::UInt(8), 2); static Halide::Var x, y; if (!convert.defined()) { convert(x, y) = ip(x, y); convert.vectorize(x, 4).parallel(y, 4); } ip.set(im); cv::Mat mat(im.height(), im.width(), CV_8UC1, cv::Scalar(0)); convert.realize(Halide::Buffer(Halide::UInt(8), im.width(), im.height(), 0, 0, mat.data)); cv::imshow(name, mat); }
void NamedWindow::showImage3D(Halide::Image<float> im) { static Halide::Func convert("convertToMat3D"); static Halide::ImageParam ip(Halide::Float(32), 3); static Halide::Var x, y, c; if (!convert.defined()) { convert(c, x, y) = Halide::cast<uint8_t>(ip(x, y, 2 - c) * 255); convert.vectorize(x, 4).parallel(y, 4); } ip.set(im); cv::Mat mat(im.height(), im.width(), CV_8UC3, cv::Scalar(0)); convert.realize(Halide::Buffer(Halide::UInt(8), im.channels(), im.width(), im.height(), 0, mat.data)); cv::imshow(name, mat); }
int sobel_example(int argc, const char **argv) { Halide::Image<uint8_t> input = load<uint8_t>(argv[0]); Halide::Var x,y,c; Halide::Func padded; padded(x,y) = input(clamp(x, 0, input.width()-1), clamp(y, 0, input.height()-1)); Halide::Image<uint8_t> sobel_output(input.width(), input.height()); // smooth the image // Halide::Func gaussian = gaussian_3x3(padded, true); // calculate the horizontal and vertical gradients (GX, Gy) std::pair<Halide::Func, Halide::Func> sobel = sobel_3x3(padded, true); Halide::Func Gx, Gy; Gx(x,y) = AS_UINT8(sobel.first(x,y)); Gx.realize(sobel_output); save(sobel_output, "output/sobel_gx.png"); Gy(x,y) = AS_UINT8(sobel.second(x,y)); Gy.realize(sobel_output); save(sobel_output, "output/sobel_gy.png"); // Calculate gradient magnitudes and scale them to image intensity // Described in http://patrick-fuller.com/gradients-image-processing-for-scientists-and-engineers-part-3/ Halide::RDom r(input); Halide::Func maxpix, minpix, luminosity, mag, mag_uint8; // calculate the {min,max} luminosity values of the original grayscale image Halide::Image<int32_t> max_out, min_out; maxpix(x) = 0; minpix(x) = 0; maxpix(0) = max(input(r.x, r.y), maxpix(0)); minpix(0) = min(input(r.x, r.y), minpix(0)); max_out = maxpix.realize(1); min_out = minpix.realize(1); // calculate the magnitude of Gx, Gy mag = grad_magnitude(sobel.first, sobel.second); // scale the magnitude by the luminosity range luminosity(x,y) = 255.0f * ((mag(x,y)-min_out(0)) / (max_out(0)-min_out(0))); TO_2D_UINT8_LAMBDA(luminosity).realize(sobel_output); save(sobel_output, "output/sobel_mag.png"); printf("%s DONE\n", __func__); return EXIT_SUCCESS; }
void NamedWindow::showImage(Halide::Image<float> im) { switch (im.dimensions()) { case 2: showImage2D(im); break; case 3: showImage3D(im); break; default: throw std::exception("Image must be either 2- or 3-dimensional."); } }
std::string image_repr(const h::Image<T> &image) { std::string repr; h::Type t = halide_type_of<T>(); std::string suffix = "_???"; if (t.is_float()) { suffix = "_float"; } else if (t.is_int()) { suffix = "_int"; } else if (t.is_uint()) { suffix = "_uint"; } else if (t.is_bool()) { suffix = "_bool"; } else if (t.is_handle()) { suffix = "_handle"; } boost::format f("<halide.Image%s%i; element_size %i bytes; " "extent (%i %i %i %i); min (%i %i %i %i); stride (%i %i %i %i)>"); repr = boost::str(f % suffix % t.bits() % t.bytes() % image.extent(0) % image.extent(1) % image.extent(2) % image.extent(3) % image.min(0) % image.min(1) % image.min(2) % image.min(3) % image.stride(0) % image.stride(1) % image.stride(2) % image.stride(3)); return repr; }
int main(int argc, char **argv) { // This program defines a single-stage imaging pipeline that // brightens an image. // First we'll load the input image we wish to brighten. Halide::Image<uint8_t> input = load<uint8_t>("../apps/images/rgb.png"); // Next we define our Func object that represents our one pipeline // stage. Halide::Func brighter; // Our Func will have three arguments, representing the position // in the image and the color channel. Halide treats color // channels as an extra dimension of the image. Halide::Var x, y, c; // Normally we'd probably write the whole function definition on // one line. Here we'll break it apart so we can explain what // we're doing at every step. // For each pixel of the input image. Halide::Expr value = input(x, y, c); // Cast it to a floating point value. value = Halide::cast<float>(value); // Multiply it by 1.5 to brighten it. Halide represents real // numbers as floats, not doubles, so we stick an 'f' on the end // of our constant. value = value * 1.5f; // Clamp it to be less than 255, so we don't get overflow when we // cast it back to an 8-bit unsigned int. value = Halide::min(value, 255.0f); // Cast it back to an 8-bit unsigned integer. value = Halide::cast<uint8_t>(value); // Define the function. brighter(x, y, c) = value; // The equivalent one-liner to all of the above is: // // brighter(x, y, c) = Halide::cast<uint8_t>(min(input(x, y, c) * 1.5f, 255)); // // In the shorter version: // - I skipped the cast to float, because multiplying by 1.5f does // that automatically. // - I also used integer constants in clamp, because they get cast // to match the type of the first argument. // - I left the Halide:: off clamp. It's unnecessary due to Koenig // lookup. // Remember. All we've done so far is build a representation of a // Halide program in memory. We haven't actually processed any // pixels yet. We haven't even compiled that Halide program yet. // So now we'll realize the Func. The size of the output image // should match the size of the input image. If we just wanted to // brighten a portion of the input image we could request a // smaller size. If we request a larger size Halide will throw an // error at runtime telling us we're trying to read out of bounds // on the input image. Halide::Image<uint8_t> output = brighter.realize(input.width(), input.height(), input.channels()); // Save the output for inspection. It should look like a bright parrot. save(output, "brighter.png"); printf("Success!\n"); return 0; }
int main(int argc, char **argv) { // This program defines a single-stage imaging pipeline that // outputs a grayscale diagonal gradient. // A 'Func' object represents a pipeline stage. It's a pure // function that defines what value each pixel should have. You // can think of it as a computed image. Halide::Func gradient; // Var objects are names to use as variables in the definition of // a Func. They have no meaning by themselves. Halide::Var x, y; // We typically use Vars named 'x' and 'y' to correspond to the x // and y axes of an image, and we write them in that order. If // you're used to thinking of images as having rows and columns, // then x is the column index, and y is the row index. // Funcs are defined at any integer coordinate of its variables as // an Expr in terms of those variables and other functions. // Here, we'll define an Expr which has the value x + y. Vars have // appropriate operator overloading so that expressions like // 'x + y' become 'Expr' objects. Halide::Expr e = x + y; // Now we'll add a definition for the Func object. At pixel x, y, // the image will have the value of the Expr e. On the left hand // side we have the Func we're defining and some Vars. On the right // hand side we have some Expr object that uses those same Vars. gradient(x, y) = e; // This is the same as writing: // // gradient(x, y) = x + y; // // which is the more common form, but we are showing the // intermediate Expr here for completeness. // That line of code defined the Func, but it didn't actually // compute the output image yet. At this stage it's just Funcs, // Exprs, and Vars in memory, representing the structure of our // imaging pipeline. We're meta-programming. This C++ program is // constructing a Halide program in memory. Actually computing // pixel data comes next. // Now we 'realize' the Func, which JIT compiles some code that // implements the pipeline we've defined, and then runs it. We // also need to tell Halide the domain over which to evaluate the // Func, which determines the range of x and y above, and the // resolution of the output image. Halide.h also provides a basic // templatized Image type we can use. We'll make an 800 x 600 // image. Halide::Image<int32_t> output = gradient.realize(800, 600); // Halide does type inference for you. Var objects represent // 32-bit integers, so the Expr object 'x + y' also represents a // 32-bit integer, and so 'gradient' defines a 32-bit image, and // so we got a 32-bit signed integer image out when we call // 'realize'. Halide types and type-casting rules are equivalent // to C. // Let's check everything worked, and we got the output we were // expecting: for (int j = 0; j < output.height(); j++) { for (int i = 0; i < output.width(); i++) { // We can access a pixel of an Image object using similar // syntax to defining and using functions. if (output(i, j) != i + j) { printf("Something went wrong!\n" "Pixel %d, %d was supposed to be %d, but instead it's %d\n", i, j, i+j, output(i, j)); return -1; } } } // Everything worked! We defined a Func, then called 'realize' on // it to generate and run machine code that produced an Image. printf("Success!\n"); return 0; }
void image_copy_to_host(h::Image<T> &im) { im.copy_to_host(); }
void image_set_min4(h::Image<T> &im, int m0, int m1, int m2, int m3) { im.set_min(m0, m1, m2, m3); }
void image_set_min3(h::Image<T> &im, int m0, int m1, int m2) { im.set_min(m0, m1, m2); }
void image_set_min2(h::Image<T> &im, int m0, int m1) { im.set_min(m0, m1); }
void image_set_min1(h::Image<T> &im, int m0) { im.set_min(m0); }