In such cases, the operator should must be split into several atomic operators.
The goal of such a principle is threefold:
/* -*- mode: c++; c-basic-offset: 3 -*- * * Copyright (c) 2013, GREYC. * All rights reserved * * You may use this file under the terms of the BSD license as follows: * * "Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of the GREYC, nor the name of its * contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." * * For more information, refer to: * https://clouard.users.greyc.fr/Pandore/ */ #include <pandore.h> using namespace pandore; Errc Operator( const Img2duc &ims, Img2duc &imd, Short p ) { // Body return SUCCESS; } Errc Operator( const Img2dsl &ims, Img2dsl &imd, Short parameter ) { // Body return SUCCESS; } #ifdef MAIN /* * Modify only the following constants, and the operator switches. */ #define USAGE "usage: %s parameter [-m mask] [im_in|-] [im_out|-]" #define PARC 1 // Number of parameters #define FINC 1 // Number of input images #define FOUTC 1 // Number of output images #define MASK 0 // Level of masking int main( int argc, char *argv[] ) { Errc result; // The result code of the execution. Pobject* mask; // The mask. Pobject* objin[FINC + 1]; // The input objects. Pobject* objs[FINC + 1]; // The source objects masked by the mask. Pobject* objout[FOUTC + 1]; // The output objects. Pobject* objd[FOUTC + 1]; // The result objects of the execution. char* parv[PARC + 1]; // The input parameters. ReadArgs(argc, argv, PARC, FINC, FOUTC, &mask, objin, objs, objout, objd, parv, USAGE, MASK); switch(objs[0]->Type()){ case Po_Img2duc: { Img2duc* const ims = (Img2duc*)objs[0]; objd[0] = new Img2duc(ims->Props()); Img2duc* const imd = (Img2duc*)objd[0]; result = Operator(*ims, *imd, atoi(parv[0])); break; } case Po_Img2dsl: { Img2dsl* const ims = (Img2dsl*)objs[0]; objd[0] = new Img2dsl(ims->Props()); Img2dsl* const imd = (Img2dsl*)objd[0]; result = Operator(*ims, *imd, atoi(parv[0])); break; } default: PrintErrorFormat(objin, FINC); result = FAILURE; } if (result) { WriteArgs(argc, argv, PARC, FINC, FOUTC, &mask, objin, objs, objout, objd, MASK); } Exit(result); return 0; } #endif
Img2duc
x Img2duc
and one for Img2dsl
x Img2dsl
.However, it is possible to write only one function when the algorithm is the same for each type. There are two different ways to write generic functions:
template <typename T1, typename T2> Errc Operator ( const Imx3d<T1> &ims , Imx3d<T2> &imd, int p) { // Body return SUCCESS; }
template <typename T> Errc Erosion( const Img2d<T> &ims, Img2d<T> &imd, int connexity ) { Point2d p; T min,val; if (connexity != 4 && connexity != 8) return FAILURE; imd.Frame(0,1,1); if (connexity == 4) { for (p.y=1; p.y < ims.Width()-1; p.y++) for (p.x=1; p.x < ims.Height()-1; p.x++) { min=ims[p+v4[0]]; for (int v=1; v < 4; v++) if ((val=ims[p+v4[v]] < min) min = val; imd[p] = min; } } else { // connexity == 8. for (p.y=1; p.y <= ims.Height()-1; p.y++) for (p.x=1; p.x < ims.Width()-1; p.x++) { min=ims[p+v8[0]]; for (int v=1; v < 8; v++) if ((val=ims[p+v8[v]] < min) min = val; imd[p] = min; } } return SUCCESS; }
T::ValueType
gives access to its data type. For example:
Img2dsf::ValueType -> Float template <typename T1, typename T2> Errc Operator ( const Imx3d<T1> &ims , Imx3d<T2> &imd, int p) { for (int b=0; b<ims.Bands(); b++) { T1::ValueType *ps=ims.Vector(b); T2::ValueType *pd=imd.Vector(b); for ( ; p<ims.Vector()+ims.VectorSize(); ps++,pd++ ) { *pd = T2(*ps *2); } } return SUCCESS; }
Limits<T>::max()
and Limits<T>::min()
return respectively the maximum and the minimum values of the primitive type T (Uchar, Slong, Float....). For example: Limits<Ushort>::max() -> 65535 Limits<Img2duc::ValueType>::max() -> 255
Select
:Select<T1,T2>::LargestUnsigned
: returns the largest unsigned of the two types;Select<T1,T2>::LargestSigned
: returns the largest signed of the two types;Select<T1,T2>::SmallestUnsigned
: returns the smallest unsigned of the two types.Select<T1,T2>::SmallestSigned
: returns the smallest signed of the two types;Select<T1,T2>::Largest
: returns the largest of the two types (signed > unsigned);Select<T1,T2>::Smallest
: returns the smallest of the two types (signed > unsigned).For example:
Select<Uchar,Short>::LargestSigned -> returns Short Select<Img3duc,Img3dsl>::LargestSigned -> returns Img2sdl Select<Uchar,Short>::LargestUnsigned -> Ushort Select<Uchar,Char>::Largest -> Char Select<Uchar,Char>::Smallest -> Uchar
main()
function is used to generate a standalone program with the operator. When the operator is used as a function of another program then the main() must be discarded. That is why the main()
is enclosed between the two C directives #ifdef MAIN
and #end
. If the value of macro MAIN is defined then the operator is compiled as a standalone program else simply as a separate module.ReadArgs()
makes the verification of the argument command line and reads the input files and the parameters. ReadArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,parv,USAGE,MASK);
ReadArgs uses a set of constants that prototypes the operator command line:
Parameters are accessible by two ways:
First of all, the input image is built with the given input image masked by the given region map. All the pixel of the initial image that are masked by the region are set to 0, all the other are kept with their initial value.
Then, the operator is applied on the whole image even on the masked pixels.
Finally, the output image is built by the unmasking operation on the processed image. The output pixels are set with the new value if they are not masked or with their initial value if the are masked.
Type()
member function. switch(objs[0]->Type()){ case Po_Img2duc :{ }
WriteArgs()
creates the output results. WriteArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd);
This function uses the same arguments than the ReadArgs function. This time, if MASK=1 or MASK=3 then output images are unmasked before return.
To set the output result value, use:
Exit(result);
pstatus
.