Here is a short C++ scheme of the image structure\footnote{This is not the actual implementation, but it should work as a schematic summary of the image features.}. \codefile{image-class-scheme-1.cpp}{image class scheme} \section {Adjustment and Reinterpretion of Image Parameters} At this point, it shall be mentioned, that some image parameters can be changed more easily\footnote{in terms of processing performance} then other ones. Changing an images size or channel count implies, that image data pointers must be allocated, free'd -- or even reallocated. Futhermore, we will see soon, that the whole image structure must be reallocated if the image depth is changed. However changing the other parameters is sometimes much cheaper: E.g. changing an images ROI or time stamp works without changing the image data itself. Also the image format can be changed as long as the new format is not associated with another channel count\footnote{Ok, reinterpreting an RGB-images channels as an YUV-data does not really make sense, except when the assumption of the RGB image format was already wrong. Most of the time, this feature is necessary to reinterpret matrix-format data into a color-/gray-format or vice versa}.\\ Futhermore, it's worth mention, that all image parameter manipulating functions do only work on demand. E.g. if \inlinecode{setSize} is called on an image that already has the desired size, nothing is done. \subsection {Image Params Revised} To simplify the image class implementation, we introduced a utility data structure called \inlinecode{ImgParams} \iclclassref{Core}{ImgParams}. This structure consists of size, channel count, format, and ROI. Besides, it handles correlation between channel count and format as well as checking and adapting ROIs, that do not fit into the whole image rect. The image itself contains an \inlinecode{ImgParams} structure, a time stamp and a depth variable. Futhermore, one can make two images \inlinecode{A} and \inlinecode{B} compatible (except their depth-values) by calling \inlinecode{B.setParams(A.getParams())}. \section{The Image} Now we are able to put these things together: image features and image data. As mentioned sometimes above, we use templating\footnote{For those who are not so familiar with C++ templates, Chapter \ref{cha:templating} shell help to recapitulate most common rules and features.} to avoid redundant implementation for images of different data types. This image class template is called \inlinecode{Img} \iclclassref{Core}{Img}. First, it's structure looked something like that: \codefile{img-structure-with-params.cpp}{First prototype for \inlinecode{Img}-structure} Those who are familiar with C++-templating techniques, might have mentioned, that there is still some overhead within the implementation. Although all parameters except the image data vector do not depend on the template parameter \inlinecode{T}, they are a part of each template instance.\\ Furthermore, there's a special problem regarding C++ template classes, which can easily be stated with the \inlinecode{Img}-example: different template instances (e.g. \inlinecode{Img} and \inlinecode{Img}) have no common data structure at runtime. So there's no higher-level structure which can be used as an interface for different \inlinecode{Img}-classes.\\ This is why we decided to implement a base class for all \inlinecode{Img} template instances called \inlinecode{ImgBase} \iclclassref{Core}{ImgBase}. Basically, \inlinecode{Img} and \inlinecode{ImgBase} are linked like this: \codefile{img-and-img-base-scheme.cpp}{Inheritance scheme for \inlinecode{Img} and \inlinecode{ImgBase} classes} \section{Typedef-Confusions\label{sec:typedef-confusions}} To facilitate handling ICL image template types, we provide a set of \inlinecode{typedef}s within the \iclheaderref{Core}{Types}-header. In the first instance, there's a set of \inlinecode{typedef}s for some C++-POD\footnote{Plain Old Data-Types like \inlinecode{int}, \inlinecode{unsigned char}, \inlinecode{float} etc...}-types: \codefile{icl-D-typedefs.cpp}{ICL's POD-typedefs} As one can see, typedefs are made compatible to Intel IPP-typedefs in case of having IPP-support, otherwise according C/C++ types are used directly. Beyond that, by copying Intel IPP's type suffixes, we will be able to define macros that construct IPP function names dynamically.\\ Once having defined this types, also class instances of the \inlinecode{Img}-template can be \inlinecode{typedef}'ed to more convenient typenames: \codefile{img-D-typedefs.cpp}{ICL's Image-Types} To confuse the reader even a little more, also the runtime type identification \inlinecode{enum depth} uses the same type suffixes: \codefile{icl-depth-enum.cpp}{The depth enumeration} All this types (or values in case of the \inlinecode{depth-enum}) engage during implementation, as the following section will illustrate. The \emph{take-home-message} of this section is:\\ \begin{itemize} \item An \inlinecode{ImgX} uses \inlinecode{iclX}'s as pixel values. \item \inlinecode{ImgX} is just a \inlinecode{typedef} for \inlinecode{Img}. \item An \inlinecode{ImgX}'s \inlinecode{getDepth()}-member function returns \inlinecode{depthX}, which is essential if you want to determine the actual type of an \inlinecode{ImgBase}-pointer or -reference. \item Currently \inlinecode{X} may be \inlinecode{8u, 16s, 32s, 32f, 64f}. \end{itemize} \section{Implementing depth-independent functions} At this point we are able to explain the necessity of the depth parameter in the \inlinecode{ImgBase} class in detail. Consider there is a function (e.g. named \inlinecode{threshold}) that shall work with arbitrary image depths, so it must expect an \inlinecode{ImgBase}-parameter\footnote{as pointer or reference as inheritance does not work otherwise}: \displaycode{void threshold(ImgBase *image, double t);} The depth parameter within the \inlinecode{ImgBase} serves as runtime type identifier to perform a save cast into the real data type at runtime. \codefile{cast-imgbase-to-img-threshold-example.cpp}{Type-safe casting (downwards within the inheritance tree)} Ok, probably there are some contradictions:\\ \begin{itemize} \item \textbf{Type-safe casting downwards within the inheritance tree is already supported by the C++-RTTI\footnote{RunTime-Type-Identification}-interface}\\ Yes, it is, but it's very slow in comparison to comparing a single enumeration value. I figured out, that using \inlinecode{dynamic\_cast} instead of switching over the \inlinecode{depth enum} is about 20 times slower when compiling optimized. \item \textbf{Function implementation gets very complicated and we cannot exploit the fact, that \inlinecode{Img} instances are templates}\\ No - and yes we can! The code above was just an example to explain how it can be implemented. A real implementation of an image threshold could look like this: \codefile{cast-imgbase-to-img-threshold-example-real.cpp}{Type-safe threshold implementation revised} \item \textbf{This helps only to exploit templating, switching over all types produces still a lot of code}\\ There is a special ICL-macro that helps to implement such \inlinecode{switch}-calls, which is called \inlinecode{ICL\_INSTANTIATE\_ALL\_DEPTHS}. This macro then calls another macro named \inlinecode{ICL\_INSTANTIATE\_DEPTH(D)}, which defines how process a specific depth -- and which must be defined by the programmer before \inlinecode{ICL\_INSTANTIATE\_ALL\_DEPTHS} can be called. \inlinecode{ICL\_INSTANTIATE\_ALL\_DEPTHS} then just expands to \inlinecode{ICL\_INSTANTIATE\_DEPTH(8u)} \inlinecode{ICL\_INSTANTIATE\_DEPTH(16s)} etc. Of course \inlinecode{ICL\_INSTANTIATE\_DEPTH(D)} must be undefined after calling \inlinecode{ICL\_INSTANTIATE\_ALL\_DEPTHS} to allow to use this feature again later. The full threshold implementation could look like this\footnote{Ok, we use another macro called \inlinecode{ICL\_INVALID\_DEPTH} here, which just throws an appropriate exception}: \codefile{cast-imgbase-to-img-threshold-example-macro.cpp}{Using the \inlinecode{ICL\_INSTANTIATE\_ALL\_DEPTHS}-macro} \end{itemize} \section {Shallow Copy Concept\label{sec:shallow-copy-concept}} In contrast to e.g. Java, C++ copies all objects deeply on default. If a reference copy is desired (e.g. as function arguments) one can simply use the \inlinecode{&} character to make a function argument be copied by reference (shallowly). Unfortunately this mechanism cannot be transcribed to function return values. Return values are often temporary objects (that \emph{live} on the function stack) which cannot be passed by reference as return values. Hence, temporaries must: \begin{enumerate} \item be copied on the function return interface\footnote{There is a special case, when this isn't necessary, namely if the return values is stored in a brand new instance of that type, but often this is not appropriate.} \item or be passed as a pointer (allocated on the heap) \end{enumerate} Copying data always involves a large overhead especially when large data arrays have to be copied deeply. If a function returns a pointer, there's always some implementational overhead for deleting the image pointer later on, however this could be forgotten accidently, which would leads to a memory leak then.\\ This is why we broke with the C++ convention of \emph{deep copy on default} for the image class: \begin{center} \textbf{images are copied shallowly on default!}\\[20pt] \end{center} More precisely, \textbf{image channel data} is copied shallowly, and all other image parameters are copied deeply. This can be interpreted as follows: An \inlinecode{Img} instance corresponds to a \textbf{view} on the underlying image channel data. This can be exploited e.g. by having an image \inlinecode{A} which has a full ROI\footnote{this means the ROI-rectangle has offset $(0,0)$ and it's size is similar to the image size.} and another image \inlinecode{B} with a distinct ROI and both images share their channel data. Futhermore this enables us to construct an image from the channels of a set of other images, to flip image channels or to append image channels shallowly.\\ However there're of course situations where a deep copy is desired. This can either be done using the \inlinecode{deepCopy()}-function of an image or by calling the \inlinecode{detach()}-function on a shared image (see \iclclassref{Core}{Img} for details). \codefile{shallow-copied-imgs.cpp}{Deep- and shallow copies of images} \subsection{Drawbacks of Shallow-Copy-on-Default} In short, actually C++ doesn't support shallow copy on default (SCOD) very well. Firstly, there's a C++ convention that says \emph{C++ uses deep copy on default (DCOD)}, so breaking with that convention must be documented well to avoid really unexpected behaviour. Besides, there's another problem with C++'s \inlinecode{const}-concept, which can only hardly be combined properly with SCOD classes. Consider there's a class \inlinecode{I} (e.g. an image class) that realizes SCOD, by implementing at least the copy constructor \inlinecode{I::I(const I&)} and the assignment operator (\inlinecode{I& I::operator=(const I&)}. Now, consider some function interface like \inlinecode{void foo(const I &i)}, which \emph{promises} not to change the function argument \inlinecode{i} due to it's \inlinecode{const}-ness. If the class \inlinecode{I} is implemented correctly it will ensure this actively, by \emph{denying} access to un-\inlinecode{const} member functions and un-\inlinecode{mutable} class members of \inlinecode{i} at compile time. Unfortunately, it's still possible to create an un-\inlinecode{const} shallow copy of \inlinecode{i} to do that nevertheless. All attempts to avoid this will fail, because it's not possible to restrict a shallow copying copy constructor to un-\inlinecode{const} source images or to enforce new shallow copied instances of \inlinecode{const} class instances to be \inlinecode{const}.\\ Hence, take care when you're copying \inlinecode{const Img}-instances. \section {Channel Management} As mentioned above, also single channels can be shared by different \inlinecode{Img} instances. Of course, this does only work for images with an identical depth ans size. The following example demonstrates channel management: \codefile{channel-management.cpp}{Image channel management examples} \section {Converting Images} In some situations, incomming image depth is not sufficient for a certain task. There a two mechanism that may help in that situation: \begin{enumerate} \item Creation of another image with identical parameters except the first images depth, followed by a source-destination-fashioned pixel-wise conversion. \item An \emph{inplace}-adaption of the image-depth, which is only possible for \inlinecode{ImgBase}-instances on the heap. \end{enumerate} The following chapter will give a deeper insight into the \inlinecode{ImgBase} class and it's functions. In particular, depth-conversion will be discussed here. %This following two sub-sections will show, how to convert an images depth %(sec. \ref{subsec:depth-conversion}) and how to adapt an images depth \emph{inplace}(sec. \ref{subsec:depth-adaption}).