1 /*
2 * Simd Library (http://ermig1979.github.io/Simd).
3 *
4 * Copyright (c) 2011-2019 Yermalayeu Ihar,
5 *               2014-2019 Antonenka Mikhail,
6 *               2018-2019 Dmitry Fedorov,
7 *               2019-2019 Artur Voronkov.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27 #ifndef __SimdView_hpp__
28 #define __SimdView_hpp__
29 
30 #include "Simd/SimdDefs.h"
31 #include "Simd/SimdRectangle.hpp"
32 #include "Simd/SimdAllocator.hpp"
33 
34 #include <memory.h>
35 #include <assert.h>
36 #include <algorithm>
37 #include <fstream>
38 
39 namespace Simd
40 {
41     /*! @ingroup cpp_view
42 
43         \short The View structure provides storage and manipulation of images.
44 
45         In order to have mutual conversion with OpenCV image type (cv::Mat) you have to define macro SIMD_OPENCV_ENABLE:
46         \verbatim
47         #include "opencv2/core/core.hpp"
48         #define SIMD_OPENCV_ENABLE
49         #include "Simd/SimdView.hpp"
50 
51         int main()
52         {
53             typedef Simd::View<Simd::Allocator> View;
54 
55             View view1(40, 30, View::Bgr24);
56             cv::Mat mat1(80, 60, CV_8UC3)
57 
58             View view2 = mat1; // view2 will be refer to mat1, it is not a copy!
59             cv::Mat mat2 = view1; // mat2 will be refer to view1, it is not a copy!
60 
61             return 0;
62         }
63         \endverbatim
64 
65         \ref cpp_view_functions.
66     */
67     template <template<class> class A>
68     struct View
69     {
70         typedef A<uint8_t> Allocator; /*!< Allocator type definition. */
71 
72         /*!
73             \enum Format
74             Describes pixel format types of an image view.
75             \note This type is corresponds to C type ::SimdPixelFormatType.
76         */
77         enum Format
78         {
79             /*! An undefined pixel format. */
80             None = 0,
81             /*! A 8-bit gray pixel format. */
82             Gray8,
83             /*! A 24-bit (3 8-bit channels) BGR (Blue, Green, Red) pixel format. */
84             Bgr24,
85             /*! A 32-bit (4 8-bit channels) BGRA (Blue, Green, Red, Alpha) pixel format. */
86             Bgra32,
87             /*! A single channel 16-bit integer pixel format. */
88             Int16,
89             /*! A single channel 32-bit integer pixel format. */
90             Int32,
91             /*! A single channel 64-bit integer pixel format. */
92             Int64,
93             /*! A single channel 32-bit float point pixel format. */
94             Float,
95             /*! A single channel 64-bit float point pixel format. */
96             Double,
97             /*! A 24-bit (3 8-bit channels) RGB (Red, Green, Blue) pixel format. */
98             Rgb24
99         };
100 
101         /*!
102             \enum Position
103             Describes the position of the child image view to the parent image view.
104             This enum is used for creation of sub image view in method Simd::View::Region.
105         */
106         enum Position
107         {
108             TopLeft, /*!< A position in the top-left corner. */
109             TopCenter, /*!< A position at the top center. */
110             TopRight, /*!< A position in the top-right corner. */
111             MiddleLeft, /*!< A position of the left in the middle. */
112             MiddleCenter, /*!< A central position. */
113             MiddleRight, /*!< A position of the right in the middle. */
114             BottomLeft, /*!< A position in the bottom-left corner. */
115             BottomCenter, /*!< A position at the bottom center. */
116             BottomRight, /*!< A position in the bottom-right corner. */
117         };
118 
119         const size_t width; /*!< \brief A width of the image. */
120         const size_t height; /*!< \brief A height of the image. */
121         const ptrdiff_t stride; /*!< \brief A row size of the image in bytes. */
122         const Format format; /*!< \brief A pixel format types of the image. */
123         uint8_t * const data; /*!< \brief A pointer to the pixel data (first row) of the image. */
124 
125         /*!
126             Creates a new empty View structure.
127         */
128         View();
129 
130         /*!
131             Creates a new View structure on the base of the image view.
132 
133             \note This constructor is not create new image view! It only creates a reference to the same image. If you want to create a copy then must use method Simd::View::Clone.
134 
135             \param [in] view - an original image view.
136         */
137         View(const View & view);
138 
139 #ifdef SIMD_OPENCV_ENABLE
140         /*!
141             Creates a new View structure on the base of OpenCV Mat type.
142 
143             \note You have to define SIMD_OPENCV_ENABLE in order to use this functionality.
144 
145             \param [in] mat - an OpenCV Mat.
146         */
147         View(const cv::Mat & mat);
148 #endif
149 
150 
151         /*!
152             Creates a new View structure with specified width, height, row size, pixel format and pointer to pixel data.
153 
154             \param [in] w - a width of created image view.
155             \param [in] h - a height of created image view.
156             \param [in] s - a stride (row size) of created image view.
157             \param [in] f - a pixel format of created image view.
158             \param [in] d - a pointer to the external buffer with pixel data. If this pointer is NULL then will be created own buffer.
159         */
160         View(size_t w, size_t h, ptrdiff_t s, Format f, void * d);
161 
162         /*!
163             Creates a new View structure with specified width, height, pixel format, pointer to pixel data and memory alignment.
164 
165             \param [in] w - a width of created image view.
166             \param [in] h - a height of created image view.
167             \param [in] f - a pixel format of created image view.
168             \param [in] d - a pointer to the external buffer with pixel data. If this pointer is NULL then will be created own buffer.
169             \param [in] align - a required memory alignment. Its default value is determined by function Allocator::Alignment.
170         */
171         View(size_t w, size_t h, Format f, void * d = NULL, size_t align = Allocator::Alignment());
172 
173         /*!
174             Creates a new View structure with specified width, height and pixel format.
175 
176             \param [in] size - a size (width and height) of created image view.
177             \param [in] f - a pixel format of created image view.
178         */
179         View(const Point<ptrdiff_t> & size, Format f);
180 
181         /*!
182             A View destructor.
183         */
184         ~View();
185 
186 #ifdef SIMD_OPENCV_ENABLE
187         /*!
188             Creates an OpenCV Mat which references this image.
189 
190             \note You have to define SIMD_OPENCV_ENABLE in order to use this functionality.
191 
192             \return an OpenCV Mat which references to this image.
193         */
194         operator cv::Mat() const;
195 #endif
196 
197 
198 #ifdef SIMD_TENSORFLOW_ENABLE
199         /*!
200             Creates an Tensorflow Tensor which references this image.
201 
202             \note You have to define SIMD_TENSORFLOW_ENABLE in order to use this functionality.
203 
204             \return an Tensorflow Tensor which references to this image.
205         */
206         void ToTFTensor(tensorflow::Tensor & tensor, float shift = 0, float scale = 1) const;
207 
208 
209         /*!
210            Creates an Tensorflow Tensor which references this image.
211 
212            \note You have to define SIMD_TENSORFLOW_ENABLE in order to use this functionality.
213 
214            \return an Tensorflow Tensor which references to this image.
215        */
216         void ToTFTensor(tensorflow::Tensor & tensor, int batchIndex, float shift = 0, float scale = 0) const;
217 #endif
218 
219         /*!
220             Gets a copy of current image view.
221 
222             \return a pointer to the new View structure. The user must free this pointer after usage.
223         */
224         View * Clone() const;
225 
226         /*!
227             Gets a copy of current image view using buffer as a storage.
228 
229             \param [in] buffer - an external view as a buffer.
230             \return a pointer to the new View structure (not owner). The user must free this pointer after usage.
231         */
232         View * Clone(View & buffer) const;
233 
234         /*!
235             Creates view which references to other View structure.
236 
237             \note This function does not create a copy of image view! It only creates a reference to the same image.
238 
239             \param [in] view - an original image view.
240             \return a reference to itself.
241         */
242         View & operator = (const View & view);
243 
244 #ifdef SIMD_OPENCV_ENABLE
245         /*!
246             Creates view which references to an OpenCV Mat.
247 
248             \note You have to define SIMD_OPENCV_ENABLE in order to use this functionality.
249 
250             \param [in] mat - an OpenCV Mat.
251             \return a reference to itself.
252         */
253         View & operator = (const cv::Mat & mat);
254 #endif
255 
256         /*!
257             Creates reference to itself.
258             It may be useful if we need to create reference to the temporary object:
259             \verbatim
260             #include "Simd/SimdLib.hpp"
261 
262             int main()
263             {
264                 typedef Simd::View<Simd::Allocator> View;
265                 View a(100, 100, View::Gray8);
266                 View b(100, 100, View::Gray8);
267                 // Copying of a central part of a to the center of b:
268                 Simd::Copy(a.Region(20, 20, 80, 80), b.Region(20, 20, 80, 80).Ref());
269                 return 0;
270             }
271             \endverbatim
272 
273             \return a reference to itself.
274         */
275         View & Ref();
276 
277         /*!
278             Re-creates a View structure with specified width, height, pixel format, pointer to pixel data and memory alignment.
279 
280             \param [in] w - a width of re-created image view.
281             \param [in] h - a height of re-created image view.
282             \param [in] f - a pixel format of re-created image view.
283             \param [in] d - a pointer to the external buffer with pixel data. If this pointer is NULL then will be created own buffer.
284             \param [in] align - a required memory alignment. Its default value is determined by function Allocator::Alignment.
285         */
286         void Recreate(size_t w, size_t h, Format f, void * d = NULL, size_t align = Allocator::Alignment());
287 
288         /*!
289             Re-creates a View structure with specified width, height and pixel format.
290 
291             \param [in] size - a size (width and height) of re-created image view.
292             \param [in] f - a pixel format of re-created image view.
293         */
294         void Recreate(const Point<ptrdiff_t> & size, Format f);
295 
296         /*!
297             Creates a new View structure which points to the region of current image bounded by the rectangle with specified coordinates.
298 
299             \param [in] left - a left side of the region.
300             \param [in] top - a top side of the region.
301             \param [in] right - a right side of the region.
302             \param [in] bottom - a bottom side of the region.
303             \return - a new View structure which points to the region of current image.
304         */
305         View Region(ptrdiff_t left, ptrdiff_t top, ptrdiff_t right, ptrdiff_t bottom) const;
306 
307         /*!
308             Creates a new View structure which points to the region of current image bounded by the rectangle with specified coordinates.
309 
310             \param [in] topLeft - a top-left corner of the region.
311             \param [in] bottomRight - a bottom-right corner of the region.
312             \return - a new View structure which points to the region of current image.
313         */
314         View Region(const Point<ptrdiff_t> & topLeft, const Point<ptrdiff_t> & bottomRight) const;
315 
316         /*!
317             Creates a new View structure which points to the region of current image bounded by the rectangle with specified coordinates.
318 
319             \param [in] rect - a rectangle which bound the region.
320             \return - a new View structure which points to the region of current image.
321         */
322         View Region(const Rectangle<ptrdiff_t> & rect) const;
323 
324         /*!
325             Creates a new View structure which points to the region of current image bounded by the rectangle with specified coordinates.
326 
327             \param [in] size - a size (width and height) of the region.
328             \param [in] position - a value represents the position of the region (see Simd::View::Position).
329             \return - a new View structure which points to the region of current image.
330         */
331         View Region(const Point<ptrdiff_t> & size, Position position) const;
332 
333         /*!
334             Creates a new View structure which points to the vertically flipped image.
335 
336             \return - a new View structure which points to the flipped image.
337         */
338         View Flipped() const;
339 
340         /*!
341             Gets size (width and height) of the image.
342 
343             \return - a new Point structure with image width and height.
344         */
345         Point<ptrdiff_t> Size() const;
346 
347         /*!
348             Gets size in bytes required to store pixel data of current View structure.
349 
350             \return - a size of data pixels in bytes.
351         */
352         size_t DataSize() const;
353 
354         /*!
355             Gets area in pixels of of current View structure.
356 
357             \return - a area of current View in pixels.
358         */
359         size_t Area() const;
360 
361         /*!
362             Gets constant reference to the pixel of arbitrary type into current view with specified coordinates.
363 
364             \param [in] x - a x-coordinate of the pixel.
365             \param [in] y - a y-coordinate of the pixel.
366             \return - a constant reference to pixel of arbitrary type.
367         */
368         template <class T> const T & At(size_t x, size_t y) const;
369 
370         /*!
371             Gets reference to the pixel of arbitrary type into current view with specified coordinates.
372 
373             \param [in] x - a x-coordinate of the pixel.
374             \param [in] y - a y-coordinate of the pixel.
375             \return - a reference to pixel of arbitrary type.
376         */
377         template <class T> T & At(size_t x, size_t y);
378 
379         /*!
380             Gets constant reference to the pixel of arbitrary type into current view with specified coordinates.
381 
382             \param [in] p - a point with coordinates of the pixel.
383             \return - a constant reference to pixel of arbitrary type.
384         */
385         template <class T> const T & At(const Point<ptrdiff_t> & p) const;
386 
387         /*!
388             Gets reference to the pixel of arbitrary type into current view with specified coordinates.
389 
390             \param [in] p - a point with coordinates of the pixel.
391             \return - a reference to pixel of arbitrary type.
392         */
393         template <class T> T & At(const Point<ptrdiff_t> & p);
394 
395         /*!
396             Gets constant pointer to the first pixel of specified row.
397 
398             \param [in] row - a row of the image.
399             \return - a constant pointer to the first pixel.
400         */
401         template <class T> const T * Row(size_t row) const;
402 
403         /*!
404             Gets pointer to the first pixel of specified row.
405 
406             \param [in] row - a row of the image.
407             \return - a pointer to the first pixel.
408         */
409         template <class T> T * Row(size_t row);
410 
411         /*!
412             \fn size_t PixelSize(Format format);
413 
414             Gets pixel size in bytes for current pixel format.
415 
416             \param [in] format - a pixel format.
417             \return - a pixel size in bytes.
418         */
419         static size_t PixelSize(Format format);
420 
421         /*!
422             Gets pixel size in bytes for current image.
423 
424             \return - a pixel size in bytes.
425         */
426         size_t PixelSize() const;
427 
428         /*!
429             \fn size_t ChannelSize(Format format);
430 
431             Gets pixel channel size in bytes for current pixel format.
432 
433             \param [in] format - a pixel format.
434             \return - a pixel channel size in bytes.
435         */
436         static size_t ChannelSize(Format format);
437 
438         /*!
439             Gets pixel channel size in bytes for current image.
440 
441             \return - a pixel channel size in bytes.
442         */
443         size_t ChannelSize() const;
444 
445         /*!
446             \fn size_t ChannelCount(Format format);
447 
448             Gets number of channels in the pixel for current pixel format.
449 
450             \param [in] format - a pixel format.
451             \return - a number of channels.
452         */
453         static size_t ChannelCount(Format format);
454 
455         /*!
456             Gets number of channels in the pixel for current image.
457 
458             \return - a number of channels.
459         */
460         size_t ChannelCount() const;
461 
462 #ifdef SIMD_OPENCV_ENABLE
463         /*!
464             Converts Simd Library pixel format to OpenCV Matrix type.
465 
466             \note You have to define SIMD_OPENCV_ENABLE in order to use this functionality.
467 
468             \param [in] format - a Simd Library pixel format.
469             \return - an OpenCV Matrix type.
470         */
471         static int ToOcv(Format format);
472 
473         /*!
474             Converts OpenCV Matrix type to Simd Library pixel format.
475 
476             \note You have to define SIMD_OPENCV_ENABLE in order to use this functionality.
477 
478             \param [in] type - an OpenCV Matrix type.
479             \return - a Simd Library pixel format.
480         */
481         static Format OcvTo(int type);
482 #endif
483 
484         /*!
485             Swaps content of two (this and other) View  structures.
486 
487             \param [in] other - an other image view.
488         */
489         void Swap(View & other);
490 
491         /*!
492             Loads image from file.
493 
494             Supported formats:
495              - PGM(Portable Gray Map) text(P2) or binary(P5) (the file is loaded as 8-bit gray image).
496              - PPM(Portable Pixel Map) text(P3) or binary(P6) (the file is loaded as 32-bit BGRA image).
497 
498             \note PGM and PPM files with comments are not supported.
499 
500             \param [in] path - a path to file with PGM or PPM image.
501             \return - a result of loading.
502         */
503         bool Load(const std::string & path);
504 
505         /*!
506             Saves image to file.
507 
508             Supported formats:
509              - PGM(Portable Gray Map) binary(P5) (this format is used in order to save 8-bit gray images).
510              - PPM(Portable Pixel Map) binary(P6) (this format is used in order to save 24-bit BGR and 32-bit BGRA images).
511 
512             \param [in] path - a path to file.
513             \return - a result of saving.
514         */
515         bool Save(const std::string & path) const;
516 
517         /*!
518             Clear View structure (reset all fields) and free memory if it's owner
519          */
520         void Clear();
521 
522     private:
523         bool _owner;
524     };
525 
526     /*! @ingroup cpp_view_functions
527 
528         \fn template <template<class> class A, class T> const T & At(const View<A> & view, size_t x, size_t y);
529 
530         Gets constant reference to the pixel of arbitrary type at the point at the image with specified coordinates.
531 
532         \param [in] view - an image.
533         \param [in] x - a x-coordinate of the pixel.
534         \param [in] y - a y-coordinate of the pixel.
535         \return - a const reference to pixel of arbitrary type.
536     */
537     template <template<class> class A, class T> const T & At(const View<A> & view, size_t x, size_t y);
538 
539     /*! @ingroup cpp_view_functions
540 
541         \fn template <template<class> class A, class T> T & At(View<A> & view, size_t x, size_t y);
542 
543         Gets reference to the pixel of arbitrary type at the point at the image with specified coordinates.
544 
545         \param [in] view - an image.
546         \param [in] x - a x-coordinate of the pixel.
547         \param [in] y - a y-coordinate of the pixel.
548         \return - a reference to pixel of arbitrary type.
549     */
550     template <template<class> class A, class T> T & At(View<A> & view, size_t x, size_t y);
551 
552 
553     /*! @ingroup cpp_view_functions
554 
555         \fn template <template<class> class A, template<class> class B> bool EqualSize(const View<A> & a, const View<B> & b);
556 
557         Checks two image views on the same size.
558 
559         \param [in] a - a first image.
560         \param [in] b - a second image.
561         \return - a result of checking.
562     */
563     template <template<class> class A, template<class> class B> bool EqualSize(const View<A> & a, const View<B> & b);
564 
565     /*! @ingroup cpp_view_functions
566 
567         \fn template <template<class> class A> bool EqualSize(const View<A> & a, const View<A> & b, const View<A> & c);
568 
569         Checks three image views on the same size.
570 
571         \param [in] a - a first image.
572         \param [in] b - a second image.
573         \param [in] c - a third image.
574         \return - a result of checking.
575     */
576     template <template<class> class A> bool EqualSize(const View<A> & a, const View<A> & b, const View<A> & c);
577 
578 
579     /*! @ingroup cpp_view_functions
580 
581         \fn template <template<class> class A> bool EqualSize(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d);
582 
583         Checks four image views on the same size.
584 
585         \param [in] a - a first image.
586         \param [in] b - a second image.
587         \param [in] c - a third image.
588         \param [in] d - a fourth image.
589         \return - a result of checking.
590     */
591     template <template<class> class A> bool EqualSize(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d);
592 
593     /*! @ingroup cpp_view_functions
594 
595         \fn template <template<class> class A, template<class> class B> bool Compatible(const View<A> & a, const View<B> & b);
596 
597         Checks two image views on compatibility (the images must have the same size and pixel format).
598 
599         \param [in] a - a first image.
600         \param [in] b - a second image.
601         \return - a result of checking.
602     */
603     template <template<class> class A, template<class> class B> bool Compatible(const View<A> & a, const View<B> & b);
604 
605     /*! @ingroup cpp_view_functions
606 
607         \fn template <template<class> class A> bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c);
608 
609         Checks three image views on compatibility (the images must have the same size and pixel format).
610 
611         \param [in] a - a first image.
612         \param [in] b - a second image.
613         \param [in] c - a third image.
614         \return - a result of checking.
615     */
616     template <template<class> class A> bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c);
617 
618     /*! @ingroup cpp_view_functions
619 
620         \fn template <template<class> class A> bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d);
621 
622         Checks four image views on compatibility (the images must have the same size and pixel format).
623 
624         \param [in] a - a first image.
625         \param [in] b - a second image.
626         \param [in] c - a third image.
627         \param [in] d - a fourth image.
628         \return - a result of checking.
629     */
630     template <template<class> class A> bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d);
631 
632     /*! @ingroup cpp_view_functions
633 
634         \fn template <template<class> class A> bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d, const View<A> & e);
635 
636         Checks five image views on compatibility (the images must have the same size and pixel format).
637 
638         \param [in] a - a first image.
639         \param [in] b - a second image.
640         \param [in] c - a third image.
641         \param [in] d - a fourth image.
642         \param [in] e - a fifth image.
643         \return - a result of checking.
644     */
645     template <template<class> class A> bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d, const View<A> & e);
646 
647     //-------------------------------------------------------------------------
648 
649     // struct View implementation:
650 
View()651     template <template<class> class A> SIMD_INLINE View<A>::View()
652         : width(0)
653         , height(0)
654         , stride(0)
655         , format(None)
656         , data(NULL)
657         , _owner(false)
658     {
659     }
660 
661     /*! \cond */
View(const View<A> & view)662     template <template<class> class A> SIMD_INLINE View<A>::View(const View<A> & view)
663         : width(view.width)
664         , height(view.height)
665         , stride(view.stride)
666         , format(view.format)
667         , data(view.data)
668         , _owner(false)
669     {
670     }
671     /*! \endcond */
672 
673 #ifdef SIMD_OPENCV_ENABLE
View(const cv::Mat & mat)674     template <template<class> class A> SIMD_INLINE View<A>::View(const cv::Mat & mat)
675         : width(mat.cols)
676         , height(mat.rows)
677         , stride(mat.step[0])
678         , format(OcvTo(mat.type()))
679         , data(mat.data)
680         , _owner(false)
681     {
682     }
683 #endif
684 
685 #ifdef SIMD_TENSORFLOW_ENABLE
ToTFTensor(tensorflow::Tensor & tensor,float shift,float scale) const686     template <template<class> class A> SIMD_INLINE void View<A>::ToTFTensor( tensorflow::Tensor & tensor, float shift, float scale) const
687     {
688         auto mapped = tensor.tensor<float, 3>();
689 
690         if (format == View<A>::Bgr24)
691         {
692             for (size_t row = 0; row < height; ++row)
693             {
694                 const uint8_t * bgr = data + row*stride;
695                 for (size_t col = 0; col < width; ++col, bgr += 3)
696                 {
697                     mapped(row, col, 0) = (bgr[0] + shift) * scale;
698                     mapped(row, col, 1) = (bgr[1] + shift) * scale;
699                     mapped(row, col, 2) = (bgr[2] + shift) * scale;
700                 }
701             }
702         } else if (format == View<A>::Bgra32)
703         {
704 
705             for (size_t row = 0; row < height; ++row)
706             {
707                 const uint8_t * bgra = data + row*stride;
708                 for (size_t col = 0; col < width; ++col, bgra += 4)
709                 {
710                     mapped(row, col, 0) = (bgra[0] + shift) * scale;
711                     mapped(row, col, 1) = (bgra[1] + shift) * scale;
712                     mapped(row, col, 2) = (bgra[2] + shift) * scale;
713                 }
714             }
715         } else if (format == View<A>::Gray8)
716         {
717             for (size_t row = 0; row < height; ++row)
718             {
719                 const uint8_t * gray = data + row*stride;
720                 for (size_t col = 0; col < width; ++col)
721                 {
722                     mapped(row, col, 0) = (gray[0] + shift) * scale;
723                 }
724             }
725         }
726     }
727 
ToTFTensor(tensorflow::Tensor & tensor,int batchIndex,float shift,float scale) const728     template <template<class> class A> SIMD_INLINE void View<A>::ToTFTensor( tensorflow::Tensor & tensor, int batchIndex, float shift, float scale) const
729     {
730         auto mapped = tensor.tensor<float, 4>();
731 
732         if (format == View<A>::Bgr24)
733         {
734             for (size_t row = 0; row < height; ++row)
735             {
736                 const uint8_t * bgr = data + row*stride;
737                 for (size_t col = 0; col < width; ++col, bgr += 3)
738                 {
739                     mapped(batchIndex, row, col, 0) = ((float)bgr[0] + shift) * scale;
740                     mapped(batchIndex, row, col, 1) = ((float)bgr[1] + shift) * scale;
741                     mapped(batchIndex, row, col, 2) = ((float)bgr[2] + shift) * scale;
742                 }
743             }
744         } else if (format == View<A>::Bgra32)
745         {
746 
747             for (size_t row = 0; row < height; ++row)
748             {
749                 const uint8_t * bgra = data + row*stride;
750                 for (size_t col = 0; col < width; ++col, bgra += 4)
751                 {
752                     mapped(batchIndex, row, col, 0) = ((float)bgra[0] + shift) * scale;
753                     mapped(batchIndex, row, col, 1) = ((float)bgra[1] + shift) * scale;
754                     mapped(batchIndex, row, col, 2) = ((float)bgra[2] + shift) * scale;
755                 }
756             }
757         } else if (format == View<A>::Gray8)
758         {
759             for (size_t row = 0; row < height; ++row)
760             {
761                 const uint8_t * gray = data + row*stride;
762                 for (size_t col = 0; col < width; ++col)
763                 {
764                     mapped(batchIndex, row, col, 0) = ((float)gray[0] + shift) * scale;
765                 }
766             }
767         }
768     }
769 #endif
770 
View(size_t w,size_t h,ptrdiff_t s,Format f,void * d)771     template <template<class> class A> SIMD_INLINE View<A>::View(size_t w, size_t h, ptrdiff_t s, Format f, void * d)
772         : width(w)
773         , height(h)
774         , stride(s)
775         , format(f)
776         , data((uint8_t*)d)
777         , _owner(false)
778     {
779         if (data == NULL && height && width && stride && format != None)
780         {
781             *(void**)&data = Allocator::Allocate(height*stride, Allocator::Alignment());
782             _owner = true;
783         }
784     }
785 
View(size_t w,size_t h,Format f,void * d,size_t align)786     template <template<class> class A> SIMD_INLINE View<A>::View(size_t w, size_t h, Format f, void * d, size_t align)
787         : width(0)
788         , height(0)
789         , stride(0)
790         , format(None)
791         , data(NULL)
792         , _owner(false)
793     {
794         Recreate(w, h, f, d, align);
795     }
796 
View(const Point<ptrdiff_t> & size,Format f)797     template <template<class> class A> SIMD_INLINE View<A>::View(const Point<ptrdiff_t> & size, Format f)
798         : width(0)
799         , height(0)
800         , stride(0)
801         , format(None)
802         , data(NULL)
803         , _owner(false)
804     {
805         Recreate(size.x, size.y, f);
806     }
807 
~View()808     template <template<class> class A> SIMD_INLINE View<A>::~View()
809     {
810         if (_owner && data)
811         {
812             Allocator::Free(data);
813         }
814     }
815 
816 #ifdef SIMD_OPENCV_ENABLE
operator cv::Mat() const817     template <template<class> class A> SIMD_INLINE View<A>::operator cv::Mat() const
818     {
819         return cv::Mat((int)height, (int)width, ToOcv(format), data, stride);
820     }
821 #endif
822 
Clone() const823     template <template<class> class A> SIMD_INLINE View<A> * View<A>::Clone() const
824     {
825         View<A> * view = new View<A>(width, height, format);
826         size_t size = width*PixelSize();
827         for (size_t row = 0; row < height; ++row)
828             memcpy(view->data + view->stride*row, data + stride*row, size);
829         return view;
830     }
831 
Clone(View & buffer) const832     template <template<class> class A> SIMD_INLINE View<A> * View<A>::Clone(View & buffer) const
833     {
834         if (buffer.width < width || buffer.height < height)
835             buffer.Recreate(width, height, format);
836 
837         View<A> * view = new View<A>(width, height, format, buffer.data);
838         size_t size = width*PixelSize();
839         for (size_t row = 0; row < height; ++row)
840             memcpy(view->data + view->stride*row, data + stride*row, size);
841         return view;
842     }
843 
844     /*! \cond */
operator =(const View<A> & view)845     template <template<class> class A> SIMD_INLINE View<A> & View<A>::operator = (const View<A> & view)
846     {
847         if (this != &view)
848         {
849             if (_owner && data)
850             {
851                 Allocator::Free(data);
852                 assert(0);
853             }
854             *(size_t*)&width = view.width;
855             *(size_t*)&height = view.height;
856             *(Format*)&format = view.format;
857             *(ptrdiff_t*)&stride = view.stride;
858             *(unsigned char**)&data = view.data;
859             _owner = false;
860         }
861         return *this;
862     }
863     /*! \endcond */
864 
865 #ifdef SIMD_OPENCV_ENABLE
operator =(const cv::Mat & mat)866     template <template<class> class A> SIMD_INLINE View<A> & View<A>::operator = (const cv::Mat & mat)
867     {
868         *this = View<A>(mat);
869         return *this;
870     }
871 #endif
872 
Ref()873     template <template<class> class A> SIMD_INLINE View<A> & View<A>::Ref()
874     {
875         return *this;
876     }
877 
Recreate(size_t w,size_t h,Format f,void * d,size_t align)878     template <template<class> class A> SIMD_INLINE void View<A>::Recreate(size_t w, size_t h, Format f, void * d, size_t align)
879     {
880         if (_owner && data)
881         {
882             Allocator::Free(data);
883             *(void**)&data = NULL;
884             _owner = false;
885         }
886         *(size_t*)&width = w;
887         *(size_t*)&height = h;
888         *(Format*)&format = f;
889         *(ptrdiff_t*)&stride = Allocator::Align(width*PixelSize(format), align);
890         if (d)
891         {
892             *(void**)&data = Allocator::Align(d, align);
893             _owner = false;
894         }
895         else if(height && stride)
896         {
897             *(void**)&data = Allocator::Allocate(height*stride, align);
898             _owner = true;
899         }
900     }
901 
Recreate(const Point<ptrdiff_t> & size,Format f)902     template <template<class> class A> SIMD_INLINE void View<A>::Recreate(const Point<ptrdiff_t> & size, Format f)
903     {
904         Recreate(size.x, size.y, f);
905     }
906 
Region(ptrdiff_t left,ptrdiff_t top,ptrdiff_t right,ptrdiff_t bottom) const907     template <template<class> class A> SIMD_INLINE View<A> View<A>::Region(ptrdiff_t left, ptrdiff_t top, ptrdiff_t right, ptrdiff_t bottom) const
908     {
909         if (data != NULL && right >= left && bottom >= top)
910         {
911             left = std::min<ptrdiff_t>(std::max<ptrdiff_t>(left, 0), width);
912             top = std::min<ptrdiff_t>(std::max<ptrdiff_t>(top, 0), height);
913             right = std::min<ptrdiff_t>(std::max<ptrdiff_t>(right, 0), width);
914             bottom = std::min<ptrdiff_t>(std::max<ptrdiff_t>(bottom, 0), height);
915             return View<A>(right - left, bottom - top, stride, format, data + top*stride + left*PixelSize(format));
916         }
917         else
918             return View<A>();
919     }
920 
Region(const Point<ptrdiff_t> & topLeft,const Point<ptrdiff_t> & bottomRight) const921     template <template<class> class A> SIMD_INLINE View<A> View<A>::Region(const Point<ptrdiff_t> & topLeft, const Point<ptrdiff_t> & bottomRight) const
922     {
923         return Region(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
924     }
925 
Region(const Rectangle<ptrdiff_t> & rect) const926     template <template<class> class A> SIMD_INLINE View<A> View<A>::Region(const Rectangle<ptrdiff_t> & rect) const
927     {
928         return Region(rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
929     }
930 
Region(const Point<ptrdiff_t> & size,Position position) const931     template <template<class> class A> SIMD_INLINE View<A> View<A>::Region(const Point<ptrdiff_t> & size, Position position) const
932     {
933         ptrdiff_t w = width, h = height;
934         switch (position)
935         {
936         case TopLeft:
937             return Region(0, 0, size.x, size.y);
938         case TopCenter:
939             return Region((w - size.x) / 2, 0, (w + size.x) / 2, size.y);
940         case TopRight:
941             return Region(w - size.x, 0, w, size.y);
942         case MiddleLeft:
943             return Region(0, (h - size.y) / 2, size.x, (h + size.y) / 2);
944         case MiddleCenter:
945             return Region((w - size.x) / 2, (h - size.y) / 2, (w + size.x) / 2, (h + size.y) / 2);
946         case MiddleRight:
947             return Region(w - size.x, (h - size.y) / 2, w, (h + size.y) / 2);
948         case BottomLeft:
949             return Region(0, h - size.y, size.x, h);
950         case BottomCenter:
951             return Region((w - size.x) / 2, h - size.y, (w + size.x) / 2, h);
952         case BottomRight:
953             return Region(w - size.x, h - size.y, w, h);
954         default:
955             assert(0);
956         }
957         return View<A>();
958     }
959 
Flipped() const960     template <template<class> class A> SIMD_INLINE View<A> View<A>::Flipped() const
961     {
962         return View<A>(width, height, -stride, format, data + (height - 1)*stride);
963     }
964 
Size() const965     template <template<class> class A> SIMD_INLINE Point<ptrdiff_t> View<A>::Size() const
966     {
967         return Point<ptrdiff_t>(width, height);
968     }
969 
DataSize() const970     template <template<class> class A> SIMD_INLINE size_t View<A>::DataSize() const
971     {
972         return stride*height;
973     }
974 
Area() const975     template <template<class> class A> SIMD_INLINE size_t View<A>::Area() const
976     {
977         return width*height;
978     }
979 
At(size_t x,size_t y) const980     template <template<class> class A> template<class T> SIMD_INLINE const T & View<A>::At(size_t x, size_t y) const
981     {
982         assert(x < width && y < height);
983         return ((const T*)(data + y*stride))[x];
984     }
985 
At(size_t x,size_t y)986     template <template<class> class A> template<class T> SIMD_INLINE T & View<A>::At(size_t x, size_t y)
987     {
988         assert(x < width && y < height);
989         return ((T*)(data + y*stride))[x];
990     }
991 
At(const Point<ptrdiff_t> & p) const992     template <template<class> class A> template<class T> SIMD_INLINE const T & View<A>::At(const Point<ptrdiff_t> & p) const
993     {
994         return At<T>(p.x, p.y);
995     }
996 
At(const Point<ptrdiff_t> & p)997     template <template<class> class A> template<class T> SIMD_INLINE T & View<A>::At(const Point<ptrdiff_t> & p)
998     {
999         return At<T>(p.x, p.y);
1000     }
1001 
Row(size_t row) const1002     template <template<class> class A> template<class T> SIMD_INLINE const T * View<A>::Row(size_t row) const
1003     {
1004         assert(row < height);
1005         return ((const T*)(data + row*stride));
1006     }
1007 
Row(size_t row)1008     template <template<class> class A> template<class T> SIMD_INLINE T * View<A>::Row(size_t row)
1009     {
1010         assert(row < height);
1011         return ((T*)(data + row*stride));
1012     }
1013 
PixelSize(Format format)1014     template <template<class> class A> SIMD_INLINE size_t View<A>::PixelSize(Format format)
1015     {
1016         switch (format)
1017         {
1018         case None:      return 0;
1019         case Gray8:     return 1;
1020         case Bgr24:     return 3;
1021         case Bgra32:    return 4;
1022         case Int16:     return 2;
1023         case Int32:     return 4;
1024         case Int64:     return 8;
1025         case Float:     return 4;
1026         case Double:    return 8;
1027         case Rgb24:     return 3;
1028         default: assert(0); return 0;
1029         }
1030     }
1031 
PixelSize() const1032     template <template<class> class A> SIMD_INLINE size_t View<A>::PixelSize() const
1033     {
1034         return PixelSize(format);
1035     }
1036 
ChannelSize(Format format)1037     template <template<class> class A> SIMD_INLINE size_t View<A>::ChannelSize(Format format)
1038     {
1039         switch (format)
1040         {
1041         case None:      return 0;
1042         case Gray8:     return 1;
1043         case Bgr24:     return 1;
1044         case Bgra32:    return 1;
1045         case Int16:     return 2;
1046         case Int32:     return 4;
1047         case Int64:     return 8;
1048         case Float:     return 4;
1049         case Double:    return 8;
1050         case Rgb24:     return 1;
1051         default: assert(0); return 0;
1052         }
1053     }
1054 
ChannelSize() const1055     template <template<class> class A> SIMD_INLINE size_t View<A>::ChannelSize() const
1056     {
1057         return ChannelSize(format);
1058     }
1059 
ChannelCount(Format format)1060     template <template<class> class A> SIMD_INLINE size_t View<A>::ChannelCount(Format format)
1061     {
1062         switch (format)
1063         {
1064         case None:      return 0;
1065         case Gray8:     return 1;
1066         case Bgr24:     return 3;
1067         case Bgra32:    return 4;
1068         case Int16:     return 1;
1069         case Int32:     return 1;
1070         case Int64:     return 1;
1071         case Float:     return 1;
1072         case Double:    return 1;
1073         case Rgb24:     return 3;
1074         default: assert(0); return 0;
1075         }
1076     }
1077 
ChannelCount() const1078     template <template<class> class A> SIMD_INLINE size_t View<A>::ChannelCount() const
1079     {
1080         return ChannelCount(format);
1081     }
1082 
1083 #ifdef SIMD_OPENCV_ENABLE
ToOcv(Format format)1084     template <template<class> class A> SIMD_INLINE int View<A>::ToOcv(Format format)
1085     {
1086         switch (format)
1087         {
1088         case Gray8:     return CV_8UC1;
1089         case Bgr24:     return CV_8UC3;
1090         case Bgra32:    return CV_8UC4;
1091         case Int16:     return CV_16SC1;
1092         case Int32:     return CV_32SC1;
1093         case Float:     return CV_32FC1;
1094         case Double:    return CV_64FC1;
1095         default: assert(0); return 0;
1096         }
1097     }
1098 
OcvTo(int type)1099     template <template<class> class A> SIMD_INLINE typename View<A>::Format View<A>::OcvTo(int type)
1100     {
1101         switch (type)
1102         {
1103         case CV_8UC1:   return Gray8;
1104         case CV_8UC3:   return Bgr24;
1105         case CV_8UC4:   return Bgra32;
1106         case CV_16SC1:  return Int16;
1107         case CV_32SC1:  return Int32;
1108         case CV_32FC1:  return Float;
1109         case CV_64FC1:  return Double;
1110         default: assert(0); return None;
1111         }
1112     }
1113 #endif
1114 
Swap(View<A> & other)1115     template <template<class> class A> SIMD_INLINE void View<A>::Swap(View<A> & other)
1116     {
1117         std::swap((size_t&)width, (size_t&)other.width);
1118         std::swap((size_t&)height, (size_t&)other.height);
1119         std::swap((ptrdiff_t&)stride, (ptrdiff_t&)other.stride);
1120         std::swap((Format&)format, (Format&)other.format);
1121         std::swap((uint8_t*&)data, (uint8_t*&)other.data);
1122         std::swap((bool&)_owner, (bool&)other._owner);
1123     }
1124 
Load(const std::string & path)1125     template <template<class> class A> SIMD_INLINE bool View<A>::Load(const std::string & path)
1126     {
1127         std::ifstream ifs(path.c_str(), std::ifstream::binary);
1128         if (ifs.is_open())
1129         {
1130             std::string type;
1131             ifs >> type;
1132             if (type == "P2" || type == "P5")
1133             {
1134                 size_t w, h, d;
1135                 ifs >> w >> h >> d;
1136                 if (d != 255)
1137                     return false;
1138                 ifs.get();
1139                 Recreate(w, h, View<A>::Gray8);
1140                 if (type == "P2")
1141                 {
1142                     for (size_t row = 0; row < height; ++row)
1143                     {
1144                         for (size_t col = 0; col < width; ++col)
1145                         {
1146                             int gray;
1147                             ifs >> gray;
1148                             data[row * stride + col] = (uint8_t)gray;
1149                         }
1150                     }
1151                 }
1152                 else
1153                 {
1154                     for (size_t row = 0; row < height; ++row)
1155                         ifs.read((char*)(data + row*stride), width);
1156                 }
1157                 return true;
1158             }
1159             if (type == "P3" || type == "P6")
1160             {
1161                 size_t w, h, d;
1162                 ifs >> w >> h >> d;
1163                 if (d != 255)
1164                     return false;
1165                 ifs.get();
1166                 Recreate(w, h, View<A>::Bgra32);
1167                 if (type == "P3")
1168                 {
1169                     for (size_t row = 0; row < height; ++row)
1170                     {
1171                         uint8_t * bgra = data + row * stride;
1172                         for (size_t col = 0; col < width; ++col, bgra += 4)
1173                         {
1174                             int blue, green, red;
1175                             ifs >> red >> green >> blue;
1176                             bgra[0] = (uint8_t)blue;
1177                             bgra[1] = (uint8_t)green;
1178                             bgra[2] = (uint8_t)red;
1179                             bgra[3] = 0xFF;
1180                         }
1181                     }
1182                 }
1183                 else
1184                 {
1185                     View buffer(width, 1, Bgr24);
1186                     for (size_t row = 0; row < height; ++row)
1187                     {
1188                         ifs.read((char*)buffer.data, width*3);
1189                         const uint8_t * rgb = buffer.data;
1190                         uint8_t * bgra = data + row*stride;
1191                         for (size_t col = 0; col < width; ++col, rgb += 3, bgra += 4)
1192                         {
1193                             bgra[0] = rgb[2];
1194                             bgra[1] = rgb[1];
1195                             bgra[2] = rgb[0];
1196                             bgra[3] = 0xFF;
1197                         }
1198                     }
1199                 }
1200                 return true;
1201             }
1202         }
1203         return false;
1204     }
1205 
Save(const std::string & path) const1206     template <template<class> class A> SIMD_INLINE bool View<A>::Save(const std::string & path) const
1207     {
1208         if (!(format == View<A>::Gray8 || format == View<A>::Bgr24 || format == View<A>::Bgra32))
1209             return false;
1210 
1211         std::ofstream ofs(path.c_str(), std::ofstream::binary);
1212         if (ofs.is_open())
1213         {
1214             if (format == View<A>::Gray8)
1215             {
1216                 ofs << "P5\n" << width << " " << height << "\n255\n";
1217                 for (size_t row = 0; row < height; ++row)
1218                     ofs.write((const char*)(data + row*stride), width);
1219             }
1220             else if (format == View<A>::Bgr24)
1221             {
1222                 ofs << "P6\n" << width << " " << height << "\n255\n";
1223                 View buffer(width, 1, Bgr24);
1224                 for (size_t row = 0; row < height; ++row)
1225                 {
1226                     const uint8_t * bgr = data + row*stride;
1227                     uint8_t * rgb = buffer.data;
1228                     for (size_t col = 0; col < width; ++col, bgr += 3, rgb += 3)
1229                     {
1230                         rgb[0] = bgr[2];
1231                         rgb[1] = bgr[1];
1232                         rgb[2] = bgr[0];
1233                     }
1234                     ofs.write((const char*)(buffer.data), width*3);
1235                 }
1236             }
1237             else if (format == View<A>::Bgra32)
1238             {
1239                 ofs << "P6\n" << width << " " << height << "\n255\n";
1240                 View buffer(width, 1, Bgr24);
1241                 for (size_t row = 0; row < height; ++row)
1242                 {
1243                     const uint8_t * bgra = data + row*stride;
1244                     uint8_t * rgb = buffer.data;
1245                     for (size_t col = 0; col < width; ++col, bgra += 4, rgb += 3)
1246                     {
1247                         rgb[0] = bgra[2];
1248                         rgb[1] = bgra[1];
1249                         rgb[2] = bgra[0];
1250                     }
1251                     ofs.write((const char*)buffer.data, width * 3);
1252                 }
1253             }
1254             return true;
1255         }
1256         else
1257             return false;
1258     }
1259 
Clear()1260     template <template<class> class A> SIMD_INLINE void View<A>::Clear()
1261     {
1262         if (_owner && data)
1263             Allocator::Free(data);
1264 #ifdef SIMD_CPP_2011_ENABLE
1265         *(void**)&data = nullptr;
1266 #else
1267         *(void**)&data = NULL;
1268 #endif
1269         _owner = false;
1270         *(size_t*)&width = 0;
1271         *(size_t*)&height = 0;
1272         *(ptrdiff_t *)&stride = 0;
1273 #ifdef SIMD_CPP_2011_ENABLE
1274         *(Format*)&format = Format::None;
1275 #else
1276         *(Format*)&format = 0;
1277 #endif
1278     }
1279 
1280     // View utilities implementation:
1281 
At(const View<A> & view,size_t x,size_t y)1282     template <template<class> class A, class T> const T & At(const View<A> & view, size_t x, size_t y)
1283     {
1284         assert(x < view.width && y < view.height);
1285 
1286         return ((const T*)(view.data + y*view.stride))[x];
1287     }
1288 
At(View<A> & view,size_t x,size_t y)1289     template <template<class> class A, class T> T & At(View<A> & view, size_t x, size_t y)
1290     {
1291         assert(x < view.width && y < view.height);
1292 
1293         return ((T*)(view.data + y*view.stride))[x];
1294     }
1295 
EqualSize(const View<A> & a,const View<B> & b)1296     template <template<class> class A, template<class> class B> SIMD_INLINE bool EqualSize(const View<A> & a, const View<B> & b)
1297     {
1298         return
1299             (a.width == b.width && a.height == b.height);
1300     }
1301 
EqualSize(const View<A> & a,const View<A> & b,const View<A> & c)1302     template <template<class> class A> SIMD_INLINE bool EqualSize(const View<A> & a, const View<A> & b, const View<A> & c)
1303     {
1304         return
1305             (a.width == b.width && a.height == b.height) &&
1306             (a.width == c.width && a.height == c.height);
1307     }
1308 
EqualSize(const View<A> & a,const View<A> & b,const View<A> & c,const View<A> & d)1309     template <template<class> class A> SIMD_INLINE bool EqualSize(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d)
1310     {
1311         return
1312             (a.width == b.width && a.height == b.height) &&
1313             (a.width == c.width && a.height == c.height) &&
1314             (a.width == d.width && a.height == d.height);
1315     }
1316 
Compatible(const View<A> & a,const View<B> & b)1317     template <template<class> class A, template<class> class B> SIMD_INLINE bool Compatible(const View<A> & a, const View<B> & b)
1318     {
1319         typedef typename View<A>::Format Format;
1320 
1321         return
1322             (a.width == b.width && a.height == b.height && a.format == (Format)b.format);
1323     }
1324 
Compatible(const View<A> & a,const View<A> & b,const View<A> & c)1325     template <template<class> class A> SIMD_INLINE bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c)
1326     {
1327         return
1328             (a.width == b.width && a.height == b.height && a.format == b.format) &&
1329             (a.width == c.width && a.height == c.height && a.format == c.format);
1330     }
1331 
Compatible(const View<A> & a,const View<A> & b,const View<A> & c,const View<A> & d)1332     template <template<class> class A> SIMD_INLINE bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d)
1333     {
1334         return
1335             (a.width == b.width && a.height == b.height && a.format == b.format) &&
1336             (a.width == c.width && a.height == c.height && a.format == c.format) &&
1337             (a.width == d.width && a.height == d.height && a.format == d.format);
1338     }
1339 
Compatible(const View<A> & a,const View<A> & b,const View<A> & c,const View<A> & d,const View<A> & e)1340     template <template<class> class A> SIMD_INLINE bool Compatible(const View<A> & a, const View<A> & b, const View<A> & c, const View<A> & d, const View<A> & e)
1341     {
1342         return
1343             (a.width == b.width && a.height == b.height && a.format == b.format) &&
1344             (a.width == c.width && a.height == c.height && a.format == c.format) &&
1345             (a.width == d.width && a.height == d.height && a.format == d.format) &&
1346             (a.width == e.width && a.height == e.height && a.format == e.format);
1347     }
1348 }
1349 
1350 #endif//__SimdView_hpp__
1351