0

I think I found a good use for alloca() to allocate memory. The purpose of this code is to perform a median filter on an image. I am using openmp so I didn't want to use anything which might cause an exception like new to allocate memory. Also each array would need to be local to the thread which makes things a bit more complicated. The solution I came up with was to allocate the arrays on the stack using alloca() since this should be much faster than new or malloc. I was just wondering what you guys think about it. Also let me know if you have any suggestions to speed up this function since the median filter is kind of slow.

#include "../../Image.hpp"
#include <utility>
#include <cstdlib>

using namespace cpimg;

Image Image::median_filter(int radius) const
{
    img_assert(radius > 0, "Invalid radius.");

    Image result(w, h);
    int n = radius * 2 + 1;

    auto median = [this, radius, n](dim_t r, dim_t c)
    {
        int size = 0;

        dim_t istart = r - radius;
        dim_t jstart = c - radius;
        dim_t iend = r + radius;
        dim_t jend = c + radius;

        istart = istart < 0 ? 0 : istart;
        jstart = jstart < 0 ? 0 : jstart;
        iend = iend >= h ? h - 1 : iend;
        jend = jend >= w ? w - 1 : jend;

        int alloc = (iend - istart) * (jend - jstart) * sizeof(float);
        float* reds = (float*)alloca(alloc);
        float* greens = (float*)alloca(alloc);
        float* blues = (float*)alloca(alloc);

        for(dim_t i = istart; i < iend; i++)
        {
            for(dim_t j = jstart; j < jend; j++)
            {
                reds[size] = (*this)[i][j].red;
                greens[size] = (*this)[i][j].green;
                blues[size] = (*this)[i][j].blue;

                for(int k = size; k > 0 && reds[k - 1] > reds[k]; k--)
                    std::swap(reds[k], reds[k - 1]);
                for(int k = size; k > 0 && greens[k - 1] > greens[k]; k--)
                    std::swap(greens[k], greens[k - 1]);
                for(int k = size; k > 0 && blues[k - 1] > blues[k]; k--)
                    std::swap(blues[k], blues[k - 1]);
                size++;
            }
        }

        Pixel m;
        m.red = size % 2 ? reds[size / 2] : 0.5 * (reds[size / 2] + reds[size / 2 - 1]);
        m.green = size % 2 ? greens[size / 2] : 0.5 * (greens[size / 2] + greens[size / 2 - 1]);
        m.blue = size % 2 ? blues[size / 2] : 0.5 * (blues[size / 2] + blues[size / 2 - 1]);
        return m;
    };

    #pragma omp parallel for
    for(dim_t r = 0; r < h; r++)
    {
        for(dim_t c = 0; c < w; c++)
        {
            result[r][c] = median(r, c);
        }
    }

    return result;
}
Rostislav
  • 3,857
  • 18
  • 30
chasep255
  • 11,745
  • 8
  • 58
  • 115
  • I guess it could be OK, as long as the large arrays do not need to be communicated into, or out of, the threads to/from other threads, then it could be a good idea. – Martin James Oct 19 '15 at 23:57
  • So you'd rather blow up the stack than throwing an exception, when something goes seriously wrong? – user3528438 Oct 19 '15 at 23:58
  • 2
    Well, since it's better overall if array bounds overruns are detected before delivery to customers, it can be said that a stack bufer is safer - a few bytes overrun is likely to result in a nice, comforting disaster at test time instead of a 'seems to work OK' UB that gets shoved onto cutomers' boxes. – Martin James Oct 20 '15 at 00:01
  • 1
    `I didn't want to use anything which might cause an exception like new to allocate memory` Then use the [`nothrow`](http://en.cppreference.com/w/cpp/memory/new/operator_new) variant of new. – user657267 Oct 20 '15 at 00:11

0 Answers0