| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 | 
							- /*M//////////////////////////////////////////////////////////////////////////////
 
- //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 
- //
 
- //  By downloading, copying, installing or using the software you agree to
 
- //  this license.  If you do not agree to this license, do not download,
 
- //  install, copy or use the software.
 
- //
 
- //                           License Agreement
 
- //                For Open Source Computer Vision Library
 
- //
 
- // Copyright (C) 2008, Google, all rights reserved.
 
- // Third party copyrights are property of their respective owners.
 
- //
 
- // Redistribution and use in source and binary forms, with or without
 
- // modification, are permitted provided that the following conditions are met:
 
- //
 
- //  * Redistribution's of source code must retain the above copyright notice,
 
- //     this list of conditions and the following disclaimer.
 
- //
 
- //  * Redistribution's 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.
 
- //
 
- //  * The name of Intel Corporation or contributors may not 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 Intel Corporation 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.
 
- /////////////////////////////////////////////////////////////////////////////////
 
- //M*/
 
- #ifndef OPENCV_CORE_WIMAGE_HPP
 
- #define OPENCV_CORE_WIMAGE_HPP
 
- #include "opencv2/core/core_c.h"
 
- #ifdef __cplusplus
 
- namespace cv {
 
- //! @addtogroup core
 
- //! @{
 
- template <typename T> class WImage;
 
- template <typename T> class WImageBuffer;
 
- template <typename T> class WImageView;
 
- template<typename T, int C> class WImageC;
 
- template<typename T, int C> class WImageBufferC;
 
- template<typename T, int C> class WImageViewC;
 
- // Commonly used typedefs.
 
- typedef WImage<uchar>            WImage_b;
 
- typedef WImageView<uchar>        WImageView_b;
 
- typedef WImageBuffer<uchar>      WImageBuffer_b;
 
- typedef WImageC<uchar, 1>        WImage1_b;
 
- typedef WImageViewC<uchar, 1>    WImageView1_b;
 
- typedef WImageBufferC<uchar, 1>  WImageBuffer1_b;
 
- typedef WImageC<uchar, 3>        WImage3_b;
 
- typedef WImageViewC<uchar, 3>    WImageView3_b;
 
- typedef WImageBufferC<uchar, 3>  WImageBuffer3_b;
 
- typedef WImage<float>            WImage_f;
 
- typedef WImageView<float>        WImageView_f;
 
- typedef WImageBuffer<float>      WImageBuffer_f;
 
- typedef WImageC<float, 1>        WImage1_f;
 
- typedef WImageViewC<float, 1>    WImageView1_f;
 
- typedef WImageBufferC<float, 1>  WImageBuffer1_f;
 
- typedef WImageC<float, 3>        WImage3_f;
 
- typedef WImageViewC<float, 3>    WImageView3_f;
 
- typedef WImageBufferC<float, 3>  WImageBuffer3_f;
 
- // There isn't a standard for signed and unsigned short so be more
 
- // explicit in the typename for these cases.
 
- typedef WImage<short>            WImage_16s;
 
- typedef WImageView<short>        WImageView_16s;
 
- typedef WImageBuffer<short>      WImageBuffer_16s;
 
- typedef WImageC<short, 1>        WImage1_16s;
 
- typedef WImageViewC<short, 1>    WImageView1_16s;
 
- typedef WImageBufferC<short, 1>  WImageBuffer1_16s;
 
- typedef WImageC<short, 3>        WImage3_16s;
 
- typedef WImageViewC<short, 3>    WImageView3_16s;
 
- typedef WImageBufferC<short, 3>  WImageBuffer3_16s;
 
- typedef WImage<ushort>            WImage_16u;
 
- typedef WImageView<ushort>        WImageView_16u;
 
- typedef WImageBuffer<ushort>      WImageBuffer_16u;
 
- typedef WImageC<ushort, 1>        WImage1_16u;
 
- typedef WImageViewC<ushort, 1>    WImageView1_16u;
 
- typedef WImageBufferC<ushort, 1>  WImageBuffer1_16u;
 
- typedef WImageC<ushort, 3>        WImage3_16u;
 
- typedef WImageViewC<ushort, 3>    WImageView3_16u;
 
- typedef WImageBufferC<ushort, 3>  WImageBuffer3_16u;
 
- /** @brief Image class which provides a thin layer around an IplImage.
 
- The goals of the class design are:
 
-     -# All the data has explicit ownership to avoid memory leaks
 
-     -# No hidden allocations or copies for performance.
 
-     -# Easy access to OpenCV methods (which will access IPP if available)
 
-     -# Can easily treat external data as an image
 
-     -# Easy to create images which are subsets of other images
 
-     -# Fast pixel access which can take advantage of number of channels if known at compile time.
 
- The WImage class is the image class which provides the data accessors. The 'W' comes from the fact
 
- that it is also a wrapper around the popular but inconvenient IplImage class. A WImage can be
 
- constructed either using a WImageBuffer class which allocates and frees the data, or using a
 
- WImageView class which constructs a subimage or a view into external data. The view class does no
 
- memory management. Each class actually has two versions, one when the number of channels is known
 
- at compile time and one when it isn't. Using the one with the number of channels specified can
 
- provide some compile time optimizations by using the fact that the number of channels is a
 
- constant.
 
- We use the convention (c,r) to refer to column c and row r with (0,0) being the upper left corner.
 
- This is similar to standard Euclidean coordinates with the first coordinate varying in the
 
- horizontal direction and the second coordinate varying in the vertical direction. Thus (c,r) is
 
- usually in the domain [0, width) X [0, height)
 
- Example usage:
 
- @code
 
- WImageBuffer3_b  im(5,7);  // Make a 5X7 3 channel image of type uchar
 
- WImageView3_b  sub_im(im, 2,2, 3,3); // 3X3 submatrix
 
- vector<float> vec(10, 3.0f);
 
- WImageView1_f user_im(&vec[0], 2, 5);  // 2X5 image w/ supplied data
 
- im.SetZero();  // same as cvSetZero(im.Ipl())
 
- *im(2, 3) = 15;  // Modify the element at column 2, row 3
 
- MySetRand(&sub_im);
 
- // Copy the second row into the first.  This can be done with no memory
 
- // allocation and will use SSE if IPP is available.
 
- int w = im.Width();
 
- im.View(0,0, w,1).CopyFrom(im.View(0,1, w,1));
 
- // Doesn't care about source of data since using WImage
 
- void MySetRand(WImage_b* im) { // Works with any number of channels
 
- for (int r = 0; r < im->Height(); ++r) {
 
-  float* row = im->Row(r);
 
-  for (int c = 0; c < im->Width(); ++c) {
 
-     for (int ch = 0; ch < im->Channels(); ++ch, ++row) {
 
-       *row = uchar(rand() & 255);
 
-     }
 
-  }
 
- }
 
- }
 
- @endcode
 
- Functions that are not part of the basic image allocation, viewing, and access should come from
 
- OpenCV, except some useful functions that are not part of OpenCV can be found in wimage_util.h
 
- */
 
- template<typename T>
 
- class WImage
 
- {
 
- public:
 
-     typedef T BaseType;
 
-     // WImage is an abstract class with no other virtual methods so make the
 
-     // destructor virtual.
 
-     virtual ~WImage() = 0;
 
-     // Accessors
 
-     IplImage* Ipl() {return image_; }
 
-     const IplImage* Ipl() const {return image_; }
 
-     T* ImageData() { return reinterpret_cast<T*>(image_->imageData); }
 
-     const T* ImageData() const {
 
-         return reinterpret_cast<const T*>(image_->imageData);
 
-     }
 
-     int Width() const {return image_->width; }
 
-     int Height() const {return image_->height; }
 
-     // WidthStep is the number of bytes to go to the pixel with the next y coord
 
-     int WidthStep() const {return image_->widthStep; }
 
-     int Channels() const {return image_->nChannels; }
 
-     int ChannelSize() const {return sizeof(T); }  // number of bytes per channel
 
-     // Number of bytes per pixel
 
-     int PixelSize() const {return Channels() * ChannelSize(); }
 
-     // Return depth type (e.g. IPL_DEPTH_8U, IPL_DEPTH_32F) which is the number
 
-     // of bits per channel and with the signed bit set.
 
-     // This is known at compile time using specializations.
 
-     int Depth() const;
 
-     inline const T* Row(int r) const {
 
-         return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep);
 
-     }
 
-     inline T* Row(int r) {
 
-         return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep);
 
-     }
 
-     // Pixel accessors which returns a pointer to the start of the channel
 
-     inline T* operator() (int c, int r)  {
 
-         return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) +
 
-             c*Channels();
 
-     }
 
-     inline const T* operator() (int c, int r) const  {
 
-         return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) +
 
-             c*Channels();
 
-     }
 
-     // Copy the contents from another image which is just a convenience to cvCopy
 
-     void CopyFrom(const WImage<T>& src) { cvCopy(src.Ipl(), image_); }
 
-     // Set contents to zero which is just a convenient to cvSetZero
 
-     void SetZero() { cvSetZero(image_); }
 
-     // Construct a view into a region of this image
 
-     WImageView<T> View(int c, int r, int width, int height);
 
- protected:
 
-     // Disallow copy and assignment
 
-     WImage(const WImage&);
 
-     void operator=(const WImage&);
 
-     explicit WImage(IplImage* img) : image_(img) {
 
-         assert(!img || img->depth == Depth());
 
-     }
 
-     void SetIpl(IplImage* image) {
 
-         assert(!image || image->depth == Depth());
 
-         image_ = image;
 
-     }
 
-     IplImage* image_;
 
- };
 
- /** Image class when both the pixel type and number of channels
 
- are known at compile time.  This wrapper will speed up some of the operations
 
- like accessing individual pixels using the () operator.
 
- */
 
- template<typename T, int C>
 
- class WImageC : public WImage<T>
 
- {
 
- public:
 
-     typedef typename WImage<T>::BaseType BaseType;
 
-     enum { kChannels = C };
 
-     explicit WImageC(IplImage* img) : WImage<T>(img) {
 
-         assert(!img || img->nChannels == Channels());
 
-     }
 
-     // Construct a view into a region of this image
 
-     WImageViewC<T, C> View(int c, int r, int width, int height);
 
-     // Copy the contents from another image which is just a convenience to cvCopy
 
-     void CopyFrom(const WImageC<T, C>& src) {
 
-         cvCopy(src.Ipl(), WImage<T>::image_);
 
-     }
 
-     // WImageC is an abstract class with no other virtual methods so make the
 
-     // destructor virtual.
 
-     virtual ~WImageC() = 0;
 
-     int Channels() const {return C; }
 
- protected:
 
-     // Disallow copy and assignment
 
-     WImageC(const WImageC&);
 
-     void operator=(const WImageC&);
 
-     void SetIpl(IplImage* image) {
 
-         assert(!image || image->depth == WImage<T>::Depth());
 
-         WImage<T>::SetIpl(image);
 
-     }
 
- };
 
- /** Image class which owns the data, so it can be allocated and is always
 
- freed.  It cannot be copied but can be explicity cloned.
 
- */
 
- template<typename T>
 
- class WImageBuffer : public WImage<T>
 
- {
 
- public:
 
-     typedef typename WImage<T>::BaseType BaseType;
 
-     // Default constructor which creates an object that can be
 
-     WImageBuffer() : WImage<T>(0) {}
 
-     WImageBuffer(int width, int height, int nchannels) : WImage<T>(0) {
 
-         Allocate(width, height, nchannels);
 
-     }
 
-     // Constructor which takes ownership of a given IplImage so releases
 
-     // the image on destruction.
 
-     explicit WImageBuffer(IplImage* img) : WImage<T>(img) {}
 
-     // Allocate an image.  Does nothing if current size is the same as
 
-     // the new size.
 
-     void Allocate(int width, int height, int nchannels);
 
-     // Set the data to point to an image, releasing the old data
 
-     void SetIpl(IplImage* img) {
 
-         ReleaseImage();
 
-         WImage<T>::SetIpl(img);
 
-     }
 
-     // Clone an image which reallocates the image if of a different dimension.
 
-     void CloneFrom(const WImage<T>& src) {
 
-         Allocate(src.Width(), src.Height(), src.Channels());
 
-         CopyFrom(src);
 
-     }
 
-     ~WImageBuffer() {
 
-         ReleaseImage();
 
-     }
 
-     // Release the image if it isn't null.
 
-     void ReleaseImage() {
 
-         if (WImage<T>::image_) {
 
-             IplImage* image = WImage<T>::image_;
 
-             cvReleaseImage(&image);
 
-             WImage<T>::SetIpl(0);
 
-         }
 
-     }
 
-     bool IsNull() const {return WImage<T>::image_ == NULL; }
 
- private:
 
-     // Disallow copy and assignment
 
-     WImageBuffer(const WImageBuffer&);
 
-     void operator=(const WImageBuffer&);
 
- };
 
- /** Like a WImageBuffer class but when the number of channels is known at compile time.
 
- */
 
- template<typename T, int C>
 
- class WImageBufferC : public WImageC<T, C>
 
- {
 
- public:
 
-     typedef typename WImage<T>::BaseType BaseType;
 
-     enum { kChannels = C };
 
-     // Default constructor which creates an object that can be
 
-     WImageBufferC() : WImageC<T, C>(0) {}
 
-     WImageBufferC(int width, int height) : WImageC<T, C>(0) {
 
-         Allocate(width, height);
 
-     }
 
-     // Constructor which takes ownership of a given IplImage so releases
 
-     // the image on destruction.
 
-     explicit WImageBufferC(IplImage* img) : WImageC<T, C>(img) {}
 
-     // Allocate an image.  Does nothing if current size is the same as
 
-     // the new size.
 
-     void Allocate(int width, int height);
 
-     // Set the data to point to an image, releasing the old data
 
-     void SetIpl(IplImage* img) {
 
-         ReleaseImage();
 
-         WImageC<T, C>::SetIpl(img);
 
-     }
 
-     // Clone an image which reallocates the image if of a different dimension.
 
-     void CloneFrom(const WImageC<T, C>& src) {
 
-         Allocate(src.Width(), src.Height());
 
-         CopyFrom(src);
 
-     }
 
-     ~WImageBufferC() {
 
-         ReleaseImage();
 
-     }
 
-     // Release the image if it isn't null.
 
-     void ReleaseImage() {
 
-         if (WImage<T>::image_) {
 
-             IplImage* image = WImage<T>::image_;
 
-             cvReleaseImage(&image);
 
-             WImageC<T, C>::SetIpl(0);
 
-         }
 
-     }
 
-     bool IsNull() const {return WImage<T>::image_ == NULL; }
 
- private:
 
-     // Disallow copy and assignment
 
-     WImageBufferC(const WImageBufferC&);
 
-     void operator=(const WImageBufferC&);
 
- };
 
- /** View into an image class which allows treating a subimage as an image or treating external data
 
- as an image
 
- */
 
- template<typename T> class WImageView : public WImage<T>
 
- {
 
- public:
 
-     typedef typename WImage<T>::BaseType BaseType;
 
-     // Construct a subimage.  No checks are done that the subimage lies
 
-     // completely inside the original image.
 
-     WImageView(WImage<T>* img, int c, int r, int width, int height);
 
-     // Refer to external data.
 
-     // If not given width_step assumed to be same as width.
 
-     WImageView(T* data, int width, int height, int channels, int width_step = -1);
 
-     // Refer to external data.  This does NOT take ownership
 
-     // of the supplied IplImage.
 
-     WImageView(IplImage* img) : WImage<T>(img) {}
 
-     // Copy constructor
 
-     WImageView(const WImage<T>& img) : WImage<T>(0) {
 
-         header_ = *(img.Ipl());
 
-         WImage<T>::SetIpl(&header_);
 
-     }
 
-     WImageView& operator=(const WImage<T>& img) {
 
-         header_ = *(img.Ipl());
 
-         WImage<T>::SetIpl(&header_);
 
-         return *this;
 
-     }
 
- protected:
 
-     IplImage header_;
 
- };
 
- template<typename T, int C>
 
- class WImageViewC : public WImageC<T, C>
 
- {
 
- public:
 
-     typedef typename WImage<T>::BaseType BaseType;
 
-     enum { kChannels = C };
 
-     // Default constructor needed for vectors of views.
 
-     WImageViewC();
 
-     virtual ~WImageViewC() {}
 
-     // Construct a subimage.  No checks are done that the subimage lies
 
-     // completely inside the original image.
 
-     WImageViewC(WImageC<T, C>* img,
 
-         int c, int r, int width, int height);
 
-     // Refer to external data
 
-     WImageViewC(T* data, int width, int height, int width_step = -1);
 
-     // Refer to external data.  This does NOT take ownership
 
-     // of the supplied IplImage.
 
-     WImageViewC(IplImage* img) : WImageC<T, C>(img) {}
 
-     // Copy constructor which does a shallow copy to allow multiple views
 
-     // of same data.  gcc-4.1.1 gets confused if both versions of
 
-     // the constructor and assignment operator are not provided.
 
-     WImageViewC(const WImageC<T, C>& img) : WImageC<T, C>(0) {
 
-         header_ = *(img.Ipl());
 
-         WImageC<T, C>::SetIpl(&header_);
 
-     }
 
-     WImageViewC(const WImageViewC<T, C>& img) : WImageC<T, C>(0) {
 
-         header_ = *(img.Ipl());
 
-         WImageC<T, C>::SetIpl(&header_);
 
-     }
 
-     WImageViewC& operator=(const WImageC<T, C>& img) {
 
-         header_ = *(img.Ipl());
 
-         WImageC<T, C>::SetIpl(&header_);
 
-         return *this;
 
-     }
 
-     WImageViewC& operator=(const WImageViewC<T, C>& img) {
 
-         header_ = *(img.Ipl());
 
-         WImageC<T, C>::SetIpl(&header_);
 
-         return *this;
 
-     }
 
- protected:
 
-     IplImage header_;
 
- };
 
- // Specializations for depth
 
- template<>
 
- inline int WImage<uchar>::Depth() const {return IPL_DEPTH_8U; }
 
- template<>
 
- inline int WImage<signed char>::Depth() const {return IPL_DEPTH_8S; }
 
- template<>
 
- inline int WImage<short>::Depth() const {return IPL_DEPTH_16S; }
 
- template<>
 
- inline int WImage<ushort>::Depth() const {return IPL_DEPTH_16U; }
 
- template<>
 
- inline int WImage<int>::Depth() const {return IPL_DEPTH_32S; }
 
- template<>
 
- inline int WImage<float>::Depth() const {return IPL_DEPTH_32F; }
 
- template<>
 
- inline int WImage<double>::Depth() const {return IPL_DEPTH_64F; }
 
- template<typename T> inline WImage<T>::~WImage() {}
 
- template<typename T, int C> inline WImageC<T, C>::~WImageC() {}
 
- template<typename T>
 
- inline void WImageBuffer<T>::Allocate(int width, int height, int nchannels)
 
- {
 
-     if (IsNull() || WImage<T>::Width() != width ||
 
-         WImage<T>::Height() != height || WImage<T>::Channels() != nchannels) {
 
-         ReleaseImage();
 
-         WImage<T>::image_ = cvCreateImage(cvSize(width, height),
 
-             WImage<T>::Depth(), nchannels);
 
-     }
 
- }
 
- template<typename T, int C>
 
- inline void WImageBufferC<T, C>::Allocate(int width, int height)
 
- {
 
-     if (IsNull() || WImage<T>::Width() != width || WImage<T>::Height() != height) {
 
-         ReleaseImage();
 
-         WImageC<T, C>::SetIpl(cvCreateImage(cvSize(width, height),WImage<T>::Depth(), C));
 
-     }
 
- }
 
- template<typename T>
 
- WImageView<T>::WImageView(WImage<T>* img, int c, int r, int width, int height)
 
-         : WImage<T>(0)
 
- {
 
-     header_ = *(img->Ipl());
 
-     header_.imageData = reinterpret_cast<char*>((*img)(c, r));
 
-     header_.width = width;
 
-     header_.height = height;
 
-     WImage<T>::SetIpl(&header_);
 
- }
 
- template<typename T>
 
- WImageView<T>::WImageView(T* data, int width, int height, int nchannels, int width_step)
 
-           : WImage<T>(0)
 
- {
 
-     cvInitImageHeader(&header_, cvSize(width, height), WImage<T>::Depth(), nchannels);
 
-     header_.imageData = reinterpret_cast<char*>(data);
 
-     if (width_step > 0) {
 
-         header_.widthStep = width_step;
 
-     }
 
-     WImage<T>::SetIpl(&header_);
 
- }
 
- template<typename T, int C>
 
- WImageViewC<T, C>::WImageViewC(WImageC<T, C>* img, int c, int r, int width, int height)
 
-         : WImageC<T, C>(0)
 
- {
 
-     header_ = *(img->Ipl());
 
-     header_.imageData = reinterpret_cast<char*>((*img)(c, r));
 
-     header_.width = width;
 
-     header_.height = height;
 
-     WImageC<T, C>::SetIpl(&header_);
 
- }
 
- template<typename T, int C>
 
- WImageViewC<T, C>::WImageViewC() : WImageC<T, C>(0) {
 
-     cvInitImageHeader(&header_, cvSize(0, 0), WImage<T>::Depth(), C);
 
-     header_.imageData = reinterpret_cast<char*>(0);
 
-     WImageC<T, C>::SetIpl(&header_);
 
- }
 
- template<typename T, int C>
 
- WImageViewC<T, C>::WImageViewC(T* data, int width, int height, int width_step)
 
-     : WImageC<T, C>(0)
 
- {
 
-     cvInitImageHeader(&header_, cvSize(width, height), WImage<T>::Depth(), C);
 
-     header_.imageData = reinterpret_cast<char*>(data);
 
-     if (width_step > 0) {
 
-         header_.widthStep = width_step;
 
-     }
 
-     WImageC<T, C>::SetIpl(&header_);
 
- }
 
- // Construct a view into a region of an image
 
- template<typename T>
 
- WImageView<T> WImage<T>::View(int c, int r, int width, int height) {
 
-     return WImageView<T>(this, c, r, width, height);
 
- }
 
- template<typename T, int C>
 
- WImageViewC<T, C> WImageC<T, C>::View(int c, int r, int width, int height) {
 
-     return WImageViewC<T, C>(this, c, r, width, height);
 
- }
 
- //! @} core
 
- }  // end of namespace
 
- #endif // __cplusplus
 
- #endif
 
 
  |