Do more. Code less. Free software for GPU computing.
<scroll to top>

examples/image/gfor_hist_demo.cpp

// ===Multi-subwindow histogram thresholding example===
//
// -Extract multiple subwindow regions from an image,
//  and threshold based on that sub region's histogram.
// -All the subwindows,histograms,thresholding are
//  processed in parallel, inside gfor loops.

#include <stdio.h>
#include <string.h>
#include <float.h>  // FLT_MIN

#include <arrayfire.h>
using namespace af; // single namespace

#include "ppm_utils.h"

// parameters
int width = 1366, height = 768; // check PPM size!
const int padding = 10; // border
const int window = 32; // nxn subsquare
const int HISTOGRAM_BINS = 256; // nbins
const float sum_thresh = window * window * 0.33; // threshold
const float sal_div = 1.5; // [1-2] saliency divisor (higher = more nwindows)

// globals
array g_src_img, g_sub_imgs, g_out_img;
array g_rowpos, g_colpos;
float* m_rowpos, *m_colpos;
int nwindows;

// gpu function
static void gpu(array& g_chipImg, bool console) {

    // memory
    array gfidx    = array(seq(window)); // FIXME
    array sums     = zeros(HISTOGRAM_BINS, nwindows);
    array binSizes = zeros(nwindows);
    array mmp      = zeros(nwindows, c32);

    // search subwindows:
    // generate histograms, find mins/maxs
    gfor(array i, nwindows) {
        array rr = g_rowpos(i) + gfidx;
        array cc = g_colpos(i) + gfidx;
        array subwin = g_chipImg(rr, cc);
        array hists = histogram(subwin, HISTOGRAM_BINS);
        sums(span, i) = accum(hists, 0);
        mmp(i) = minmax_packed(flat(subwin)); // complex: real=min, imag=max
        binSizes(i) = (imag(mmp(i)) - real(mmp(i)) + FLT_MIN) / HISTOGRAM_BINS;
    }

    // histogram search for thresholds:
    //  find the first bin index that breaks sum_threshold
    //  for each window
    array val, idx;
    array df = (sums - sum_thresh) < 0;
    af::min(val, idx, df);
    array wthresh = idx;

    // subwindow thresholding
    gfor(array i, nwindows) {
        array rr = g_rowpos(i) + gfidx;
        array cc = g_colpos(i) + gfidx;
        array oldsub = g_chipImg(rr, cc);
        // create thresholds
        wthresh(i) = mul(wthresh(i) , binSizes(i)) + real(mmp(i));
        // apply thresholds
        array newsub = mul((oldsub >= wthresh(i)) , imag(mmp(i))) + real(mmp(i));
        g_sub_imgs(span, span, i) = newsub;
    }

    // print thresholded subwindows
    gfor(array i, nwindows) {
        array rr = g_rowpos(i) + gfidx;
        array cc = g_colpos(i) + gfidx;
        g_out_img(rr, cc) = g_sub_imgs(span, span, i);
    }
    if (!console) {
        subfigure(2, 2, 4); imgplot(g_out_img); title("3. region processed");
    }
}

// averaging kernel
const float h_avg_kernel[] = { 1.0 / 12.0, 2.0 / 12.0, 1.0 / 12.0,
                               2.0 / 12.0, 0.0       , 2.0 / 12.0,
                               1.0 / 12.0, 2.0 / 12.0, 1.1 / 12.0
                             };
array avg_k = array(3, 3, h_avg_kernel);

static void run(bool console)
{
    // load image
    array Ig = 255 * load_gray_ppm("pattern.ppm"); // grayscale  [0-max]
    float scale = 1.0;
    Ig = resize(Ig, scale);
    width *= scale; height *= scale;
    printf("%dx%d\n", width, height);

    if (!console) {
        // show input
        palette("gray");
        subfigure(2, 2, 1); imgplot(Ig); title("1. input");
    }

    // saliece image
    array blur1 = filter(Ig, avg_k);
    array blur2 = filter(blur1, avg_k);
    array Is    = mul((Ig - blur2) , (Ig >= blur2));
    Is = filter(Is, avg_k);

    if (!console) {
        // show
        subfigure(2, 2, 2); imgplot(convert(Is, f32)); title("2. blurred diff");
    }

    // salient points
    float mx = max<float>(flat(Is));
    array Ib = (Is >= (mx / sal_div)); // threshold

    if (!console) {
        // show
        subfigure(2, 2, 3); imgplot(convert(morph(Ib, AF_BW_Dilate), f32)); title("3. salient areas");
    }

    // num windows estimate
    nwindows = count(flat(Ib));
    printf("nwindows: %d\n", nwindows);

    // setup window positions
    m_rowpos = (float*)malloc(nwindows * sizeof(*m_rowpos));
    m_colpos = (float*)malloc(nwindows * sizeof(*m_colpos));
    bool *h_ib = Ib.host<bool>();
    int ii = 0;
    for (unsigned x = padding; x < Ib.dims()[1] - padding; ++x) {
        for (unsigned y = padding; y < Ib.dims()[0] - padding; ++y) {
            if (h_ib[x*height+y]) { // column major
                m_rowpos[ii] = y;
                m_colpos[ii] = x;
                ++ii;
            }
        }
    }
    // num windows actual
    nwindows = ii;
    printf("nwindows: %d\n", nwindows);

    // copy to gpu
    g_sub_imgs = zeros(window, window, nwindows);
    g_out_img  = zeros(height, width);
    g_rowpos   = array(nwindows, m_rowpos);  free(m_rowpos);
    g_colpos   = array(nwindows, m_colpos);  free(m_colpos);
    g_src_img  = Ig;

    gpu(g_src_img, console);
}


int main(int argc, char **argv)
{
    bool console = false;
    if ( argc > 2 || (argc == 2 && strcmp(argv[1],"-")) ){
        printf("Usage: gfor_hist_demo [-]\n");
        return -1;
    } else if (argc == 2 && !strcmp(argv[1],"-")) {
        console = true;
    }

    try {
        run(console);
    } catch (af::exception& e) {
        fprintf(stderr, "%s\n", e.what());
    }

    #ifdef WIN32 // pause in Windows
    if (!console) {
        printf("hit [enter]...");
        getchar();
    }
    #endif
    return 0;
}
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines