-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-implemented median filtering as a function.
- Loading branch information
Manuel Guenther
committed
Jul 3, 2014
1 parent
88c50be
commit 223315b
Showing
8 changed files
with
198 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/** | ||
* @date Thu Jul 3 12:37:19 CEST 2014 | ||
* @author Manuel Guenther <manuel.guenther@idiap.ch> | ||
* | ||
* @brief This file provides a function to perform median filtering | ||
* | ||
* Copyright (C) Idiap Research Institute, Martigny, Switzerland | ||
*/ | ||
|
||
#ifndef BOB_IP_BASE_MEDIAN_H | ||
#define BOB_IP_BASE_MEDIAN_H | ||
|
||
#include <vector> | ||
#include <algorithm> | ||
#include "bob/core/assert.h" | ||
#include "bob/core/cast.h" | ||
|
||
namespace bob { namespace ip { namespace base { | ||
|
||
template <typename T> | ||
void medianFilter( | ||
const blitz::Array<T,2>& src, | ||
blitz::Array<T,2>& dst, | ||
const blitz::TinyVector<int,2>& radius | ||
){ | ||
// Checks | ||
bob::core::array::assertZeroBase(src); | ||
bob::core::array::assertZeroBase(dst); | ||
blitz::TinyVector<int,2> dst_size(src.extent(0) - 2 * radius[0], src.extent(1) - 2 * radius[1]); | ||
bob::core::array::assertSameShape(dst, dst_size); | ||
|
||
// compute centeral pixel | ||
int center = (2*radius[0]+1)*(2*radius[1]+1)/2; | ||
// we only sort the first half of the sequence (this is all we need) | ||
std::vector<T> _temp(center+1); | ||
// iterate over the destination array | ||
for (int y = 0; y < dst_size[0]; ++y) | ||
for (int x = 0; x < dst_size[1]; ++x){ | ||
// get a slice from the src array | ||
const blitz::Array<T,2> slice(src(blitz::Range(y, y + 2 * radius[0]), blitz::Range(x, x + 2 * radius[1]))); | ||
// compute the median | ||
// we only sort the first half of the sequence | ||
std::partial_sort_copy(slice.begin(), slice.end(), _temp.begin(), _temp.end()); | ||
// get the central element | ||
dst(y,x) = _temp[center]; | ||
} | ||
} | ||
|
||
|
||
template <typename T> | ||
void medianFilter( | ||
const blitz::Array<T,3>& src, | ||
blitz::Array<T,3>& dst, | ||
const blitz::TinyVector<int,2>& radius | ||
){ | ||
// iterate over the color layers | ||
for (int p = 0; p < dst.extent(0); ++p){ | ||
const blitz::Array<T,2> src_slice = src(p, blitz::Range::all(), blitz::Range::all()); | ||
blitz::Array<T,2> dst_slice = dst(p, blitz::Range::all(), blitz::Range::all()); | ||
|
||
// Apply median filter to the plane | ||
medianFilter(src_slice, dst_slice, radius); | ||
} | ||
} | ||
|
||
} } } // namespaces | ||
|
||
#endif // BOB_IP_BASE_MEDIAN_H | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/** | ||
* @author Manuel Guenther <manuel.guenther@idiap.ch> | ||
* @date Thu Jul 3 13:30:38 CEST 2014 | ||
* | ||
* @brief Binds image filter functions of bob::ip::base class to python | ||
* | ||
* Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland | ||
*/ | ||
|
||
|
||
#include "main.h" | ||
#include "cpp/Median.h" | ||
|
||
static inline bool f(PyObject* o){return o != 0 && PyObject_IsTrue(o) > 0;} /* converts PyObject to bool and returns false if object is NULL */ | ||
|
||
|
||
bob::extension::FunctionDoc s_median = bob::extension::FunctionDoc( | ||
"median", | ||
"Performs a median filtering of the input image with the given radius", | ||
"This function computes a histogram of the given input image, in several ways.\n\n" | ||
"* (version 1 and 2, only valid for uint8 and uint16 types -- and uint32 and uint64 when ``bin_count`` is specified or ``hist`` is given as parameter): For each pixel value of the ``src`` image, a histogram bin is computed, using a fast implementation. " | ||
"The number of bins can be limited, and there will be a check that the source image pixels are actually in the desired range ``(0, bin_count-1)``\n\n" | ||
"* (version 3 and 4, valid for many data types): The histogram is computed by defining regular bins between the provided minimum and maximum values." | ||
) | ||
.add_prototype("src, radius, [dst]", "dst") | ||
.add_parameter("src", "array_like (2D or 3D)", "The source image to filter, might be a gray level image or a color image") | ||
.add_parameter("radius", "(int, int)", "The radius of the median filter; the final filter will have the size ``(2*radius[0]+1, 2*radius[1]+1)``") | ||
.add_parameter("dst", "array_like (2D or 3D)", "The median-filtered image to write; need to be of size ``src.shape - 2*radius``; if not specified, it will be created") | ||
.add_return("dst", "array_like (2D or 3D)", "The median-filtered image; the same as the ``dst`` parameter, if specified") | ||
; | ||
|
||
template <typename T, int D> PyObject* inner_median(PyBlitzArrayObject* src, PyBlitzArrayObject* dst, const blitz::TinyVector<int,2>& radius) { | ||
bob::ip::base::medianFilter(*PyBlitzArrayCxx_AsBlitz<T, D>(src), *PyBlitzArrayCxx_AsBlitz<T, D>(dst), radius); | ||
Py_INCREF(dst); | ||
return PyBlitzArray_AsNumpyArray(dst, 0); | ||
} | ||
|
||
PyObject* PyBobIpBase_median(PyObject*, PyObject* args, PyObject* kwargs) { | ||
TRY | ||
|
||
static char* kwlist[] = {c("src"), c("radius"), c("dst"), NULL}; | ||
|
||
PyBlitzArrayObject* src,* dst = 0; | ||
blitz::TinyVector<int,2> radius; | ||
|
||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&(ii)|O&", kwlist, &PyBlitzArray_Converter, &src, &radius[0], &radius[1], &PyBlitzArray_OutputConverter, &dst)) return 0; | ||
|
||
auto src_ = make_safe(src), dst_ = make_xsafe(dst); | ||
|
||
// allocate the output, if needed | ||
if (!dst){ | ||
if (src->ndim == 2){ | ||
Py_ssize_t n[] = {src->shape[0] - 2*radius[0], src->shape[1] - 2*radius[1]}; | ||
dst = reinterpret_cast<PyBlitzArrayObject*>(PyBlitzArray_SimpleNew(src->type_num, 2, n)); | ||
} else if (src->ndim == 3){ | ||
Py_ssize_t n[] = {src->shape[0], src->shape[1] - 2*radius[0], src->shape[2] - 2*radius[1]}; | ||
dst = reinterpret_cast<PyBlitzArrayObject*>(PyBlitzArray_SimpleNew(src->type_num, 3, n)); | ||
} else { | ||
PyErr_Format(PyExc_TypeError, "'median' : only 2D or 3D arrays are supported."); | ||
return 0; | ||
} | ||
dst_ = make_safe(dst); | ||
} else { | ||
if (dst->type_num != src->type_num || dst->ndim != src->ndim){ | ||
PyErr_Format(PyExc_TypeError, "'median' : 'src' and 'dst' images must have the same type and number of dimensions, but %s != %s or %d != %d.", PyBlitzArray_TypenumAsString(src->type_num), PyBlitzArray_TypenumAsString(dst->type_num), (int)src->ndim, (int)dst->ndim); | ||
return 0; | ||
} | ||
} | ||
|
||
// compute the median | ||
switch (src->type_num){ | ||
case NPY_UINT8: if (src->ndim == 2) return inner_median<uint8_t,2>(src, dst, radius); else return inner_median<uint8_t,3>(src, dst, radius); | ||
case NPY_UINT16: if (src->ndim == 2) return inner_median<uint16_t,2>(src, dst, radius); else return inner_median<uint16_t,3>(src, dst, radius); | ||
case NPY_FLOAT16: if (src->ndim == 2) return inner_median<double,2>(src, dst, radius); else return inner_median<double,3>(src, dst, radius); | ||
default: | ||
PyErr_Format(PyExc_ValueError, "'median' of %s arrays is currently not supported, only uint8, uint16 or float64 arrays are", PyBlitzArray_TypenumAsString(src->type_num)); | ||
return 0; | ||
} | ||
|
||
CATCH_("in median", 0) | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/usr/bin/env python | ||
# vim: set fileencoding=utf-8 : | ||
# Manuel Guenther <manuel.guenther@idiap.ch> | ||
# Thu Jul 3 14:31:48 CEST 2014 | ||
# | ||
# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland | ||
|
||
"""Tests filtertering""" | ||
|
||
import numpy | ||
import nose.tools | ||
import bob.ip.base | ||
import bob.sp | ||
|
||
import bob.io.base | ||
import bob.io.base.test_utils | ||
import bob.io.image | ||
|
||
def test_median(): | ||
# tests median filtering | ||
src = numpy.array([ | ||
[1, 2, 3, 4, 5], | ||
[6, 7, 8, 9, 10], | ||
[11, 12, 13, 14, 15], | ||
[16, 17, 18, 19, 20]], | ||
dtype = numpy.uint16 | ||
) | ||
ref = numpy.array([ | ||
[7, 8, 9], | ||
[12, 13, 14]], | ||
dtype = numpy.uint16) | ||
|
||
dst = bob.ip.base.median(src, (1,1)) | ||
assert numpy.allclose(ref, dst) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters