Image Component Library (ICL)
|
class for applying table look-up transformation to 3-channel integer-valued images More...
#include <LUTOp3Channel.h>
Classes | |
class | Plugin |
Internal plugin class for the LUTOp3Channel. More... | |
Public Member Functions | |
LUTOp3Channel (Plugin *p=0, icl8u shift=0) | |
creates a LUT object with given lut (LUT-mode) | |
virtual | ~LUTOp3Channel () |
Destructor. | |
virtual void | apply (const core::ImgBase *src, core::ImgBase **dst) |
Common Filter apply function using current mode. | |
void | setPlugin (Plugin *p) |
Sets a new plugin and re-calculates the internal LUT. | |
Plugin * | removePlugin () |
removes the internal plugin so it is not deleted with the LUTOp | |
Private Attributes | |
core::Img< T > | m_oLUT |
Image that holds the lut data. | |
Plugin * | m_poPlugin |
Current plugin pointer. | |
icl8u | m_ucShift |
channel range increment (...) |
class for applying table look-up transformation to 3-channel integer-valued images
In many applications it is necessary to create a feature map on 3-channel input images. These feature map creation procedure can take much time, depending on the complexity of the calculated feature. In a very simple case for instance, the LUTOp3Channel can be used to create thresholded color-distance map using the the euclidean distance to a reference color and a threshold for each pixel of the source image. This operation can be applied on each input (r,g,b)-Tuple by the following function (which is basically implemented in the "'Plugin" structure nested in the LUTOp3Channel class:
virtual T transform(icl8u v1, icl8u v2, icl8u v3){ return ::sqrt( ::pow(r-m_aiRGB[0],2) + ::pow(g-m_aiRGB[1],2) + ::pow(b-m_aiRGB[2],2) ) / (::sqrt(3.0)) < thresh ? 255 : 0; }
This virtual function can be reimplemented by special plugins to calculate custom LUT-accelerated maps on icl8u/icl16s and icl32s -source images. The source images must be at least integer-typed, as the LUT, which is used internally has only discrete entries.
It is recommended to work with icl8u input images to avoid illegal memory access when using the LUT.
The following procedure is used to create the LUT internally;
void create_lut(Plugin p, T lut[16777216]){ for(int r = 0; r < 256; ++r){ for(int g = 0; g < 256; ++g){ for(int b = 0; b < 256; ++b){ lut[r+ 256*g + 65536*b] = p.transform( r,g,b ); } } } }
When the LUT is created internally, it can be used for fast feature map calculation using a simple table look-up:
\#define CAST(x) Cast<srcT,icl8u>::cast(x) template<class srcT, class dstT> void apply_lut_op_3(const Img<srcT> &src, Img<dstT> &dst, dstT *lut){ const srcT * pSrcR = src.getData(0); const srcT * pSrcG = src.getData(1); const srcT * pSrcB = src.getData(2); dstT *pDst = dst.getData(0); dstT *pDstEnd = pDst+dst.getDim(); while(pDst < pDstEnd){ *pDst++ = lut[ CAST(*pSrcR++) + 256*CAST(*pSrcG++) + 65536*CAST(*pSrcB++) ]; } }
As it can be seen in section Implementing the Configurable Interface, each pixel is transformed by a simple table look up, which is performed by 2 multiplications, 2 additions and a simple dereferencing. The more complex part of this calculation is done by the calls to the Cast-class template. This is necessary to avoid index overruns due to the higher range of all non-icl8u input images types. The performance is much better, when using icl8u input images, because the Cast- call is left out in this case.
The default Plugins operation of threshold an implicitly created euclidean distance map takes about 18msec on an 640x480 3-channel icl8u input image. This can be accelerated by 61% to 11msec (1.6Mhz Pentium M) by using the LUTOp3Channel class. This benefit is not very high, but the euclidean distance function is only one possible function
which can be implemented using the 3 channel lut. Consider, that all of these possibly very complex operations will not take more then the above measured 11msec.
In some applications, it is sufficient to use a decreased resolution for each channel range. E.g. if we use only 7Bit per channel, we can reduce the LUT size from to further reduction of the quantization level of each channel to 6Bit results in a LUT.
The benefit of this optimization is at first of course the saving of a large part of necessary memory, but in a second view, it also increases processing speed even beyond the speed enhancement achieved using a LUT. The reason for the speed advantage compared with the full size LUT can be explained by the cpu's cache management: When using a 16.8MB data array which is nearly randomly accessed, the data can not be cached permanently, so the cache flow in influenced negatively. The following table illustrates some benchmark results using different bit shifts, compared on a 640x480 rgb icl8u image.
Shift | LUT size | Time* |
0 (no shift) | 16.8MB | 11ms |
1 | 2.2MB | 8ms |
2 | 262kB | 4.3ms |
3 | 33kB | 3.5ms |
4 | 4kB | 3.5ms |
5 | 512 Bytes | 3.5ms |
6 | 64 Bytes | 3.5ms |
7 | 8 Bytes | 3.5ms |
A bit shift value of 2 seems to be the best compromise between data resolution vs. speed and not at least memory usage. But note: There are some applications, where the data resolution can not be scaled down using bit shifts.
icl::filter::LUTOp3Channel< T >::LUTOp3Channel | ( | Plugin * | p = 0 , |
icl8u | shift = 0 |
||
) |
creates a LUT object with given lut (LUT-mode)
p | plugin to use for the creation of the internal lut. Note:the LUTOp3Channel takes the ownership of the given plugin |
shift | see Optimization "Shift" |
virtual icl::filter::LUTOp3Channel< T >::~LUTOp3Channel | ( | ) | [virtual] |
Destructor.
virtual void icl::filter::LUTOp3Channel< T >::apply | ( | const core::ImgBase * | src, |
core::ImgBase ** | dst | ||
) | [virtual] |
Common Filter apply function using current mode.
src | source image |
dst | destination image** |
Implements icl::filter::UnaryOp.
Plugin* icl::filter::LUTOp3Channel< T >::removePlugin | ( | ) | [inline] |
removes the internal plugin so it is not deleted with the LUTOp
void icl::filter::LUTOp3Channel< T >::setPlugin | ( | Plugin * | p | ) |
Sets a new plugin and re-calculates the internal LUT.
p | plugin to use for the creation of the internal lut. Note:the LUTOp3Channel takes the ownership of the given plugin |
core::Img<T> icl::filter::LUTOp3Channel< T >::m_oLUT [private] |
Image that holds the lut data.
Plugin* icl::filter::LUTOp3Channel< T >::m_poPlugin [private] |
Current plugin pointer.
icl8u icl::filter::LUTOp3Channel< T >::m_ucShift [private] |
channel range increment (...)