xref: /aosp_15_r20/external/ComputeLibrary/utils/ImageLoader.h (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1*c217d954SCole Faust /*
2*c217d954SCole Faust  * Copyright (c) 2018-2021 Arm Limited.
3*c217d954SCole Faust  *
4*c217d954SCole Faust  * SPDX-License-Identifier: MIT
5*c217d954SCole Faust  *
6*c217d954SCole Faust  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*c217d954SCole Faust  * of this software and associated documentation files (the "Software"), to
8*c217d954SCole Faust  * deal in the Software without restriction, including without limitation the
9*c217d954SCole Faust  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*c217d954SCole Faust  * sell copies of the Software, and to permit persons to whom the Software is
11*c217d954SCole Faust  * furnished to do so, subject to the following conditions:
12*c217d954SCole Faust  *
13*c217d954SCole Faust  * The above copyright notice and this permission notice shall be included in all
14*c217d954SCole Faust  * copies or substantial portions of the Software.
15*c217d954SCole Faust  *
16*c217d954SCole Faust  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*c217d954SCole Faust  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*c217d954SCole Faust  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*c217d954SCole Faust  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*c217d954SCole Faust  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*c217d954SCole Faust  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*c217d954SCole Faust  * SOFTWARE.
23*c217d954SCole Faust  */
24*c217d954SCole Faust #ifndef __UTILS_IMAGE_LOADER_H__
25*c217d954SCole Faust #define __UTILS_IMAGE_LOADER_H__
26*c217d954SCole Faust 
27*c217d954SCole Faust #include "arm_compute/core/Error.h"
28*c217d954SCole Faust #include "arm_compute/core/ITensor.h"
29*c217d954SCole Faust #include "arm_compute/core/TensorInfo.h"
30*c217d954SCole Faust #include "arm_compute/core/Types.h"
31*c217d954SCole Faust 
32*c217d954SCole Faust #include "utils/Utils.h"
33*c217d954SCole Faust 
34*c217d954SCole Faust #pragma GCC diagnostic push
35*c217d954SCole Faust #pragma GCC diagnostic ignored "-Wswitch-default"
36*c217d954SCole Faust #pragma GCC diagnostic ignored "-Wstrict-overflow"
37*c217d954SCole Faust #include "stb/stb_image.h"
38*c217d954SCole Faust #pragma GCC diagnostic pop
39*c217d954SCole Faust 
40*c217d954SCole Faust #include <cstdlib>
41*c217d954SCole Faust #include <memory>
42*c217d954SCole Faust #include <string>
43*c217d954SCole Faust 
44*c217d954SCole Faust namespace arm_compute
45*c217d954SCole Faust {
46*c217d954SCole Faust namespace utils
47*c217d954SCole Faust {
48*c217d954SCole Faust /** Image feeder interface */
49*c217d954SCole Faust class IImageDataFeeder
50*c217d954SCole Faust {
51*c217d954SCole Faust public:
52*c217d954SCole Faust     /** Virtual base destructor */
53*c217d954SCole Faust     virtual ~IImageDataFeeder() = default;
54*c217d954SCole Faust     /** Gets a character from an image feed */
55*c217d954SCole Faust     virtual uint8_t get() = 0;
56*c217d954SCole Faust     /** Feed a whole row to a destination pointer
57*c217d954SCole Faust      *
58*c217d954SCole Faust      * @param[out] dst      Destination pointer
59*c217d954SCole Faust      * @param[in]  row_size Row size in terms of bytes
60*c217d954SCole Faust      */
61*c217d954SCole Faust     virtual void get_row(uint8_t *dst, size_t row_size) = 0;
62*c217d954SCole Faust };
63*c217d954SCole Faust /** File Image feeder concrete implementation */
64*c217d954SCole Faust class FileImageFeeder : public IImageDataFeeder
65*c217d954SCole Faust {
66*c217d954SCole Faust public:
67*c217d954SCole Faust     /** Default constructor
68*c217d954SCole Faust      *
69*c217d954SCole Faust      * @param[in] fs Image file stream
70*c217d954SCole Faust      */
FileImageFeeder(std::ifstream & fs)71*c217d954SCole Faust     FileImageFeeder(std::ifstream &fs)
72*c217d954SCole Faust         : _fs(fs)
73*c217d954SCole Faust     {
74*c217d954SCole Faust     }
75*c217d954SCole Faust     // Inherited overridden methods
get()76*c217d954SCole Faust     uint8_t get() override
77*c217d954SCole Faust     {
78*c217d954SCole Faust         return _fs.get();
79*c217d954SCole Faust     }
get_row(uint8_t * dst,size_t row_size)80*c217d954SCole Faust     void get_row(uint8_t *dst, size_t row_size) override
81*c217d954SCole Faust     {
82*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(dst == nullptr);
83*c217d954SCole Faust         _fs.read(reinterpret_cast<std::fstream::char_type *>(dst), row_size);
84*c217d954SCole Faust     }
85*c217d954SCole Faust 
86*c217d954SCole Faust private:
87*c217d954SCole Faust     std::ifstream &_fs;
88*c217d954SCole Faust };
89*c217d954SCole Faust /** Memory Image feeder concrete implementation */
90*c217d954SCole Faust class MemoryImageFeeder : public IImageDataFeeder
91*c217d954SCole Faust {
92*c217d954SCole Faust public:
93*c217d954SCole Faust     /** Default constructor
94*c217d954SCole Faust      *
95*c217d954SCole Faust      * @param[in] data Pointer to data
96*c217d954SCole Faust      */
MemoryImageFeeder(const uint8_t * data)97*c217d954SCole Faust     MemoryImageFeeder(const uint8_t *data)
98*c217d954SCole Faust         : _data(data)
99*c217d954SCole Faust     {
100*c217d954SCole Faust     }
101*c217d954SCole Faust     /** Prevent instances of this class from being copied (As this class contains pointers) */
102*c217d954SCole Faust     MemoryImageFeeder(const MemoryImageFeeder &) = delete;
103*c217d954SCole Faust     /** Default move constructor */
104*c217d954SCole Faust     MemoryImageFeeder(MemoryImageFeeder &&) = default;
105*c217d954SCole Faust     /** Prevent instances of this class from being copied (As this class contains pointers) */
106*c217d954SCole Faust     MemoryImageFeeder &operator=(const MemoryImageFeeder &) = delete;
107*c217d954SCole Faust     /** Default move assignment operator */
108*c217d954SCole Faust     MemoryImageFeeder &operator=(MemoryImageFeeder &&) = default;
109*c217d954SCole Faust     // Inherited overridden methods
get()110*c217d954SCole Faust     uint8_t get() override
111*c217d954SCole Faust     {
112*c217d954SCole Faust         return *_data++;
113*c217d954SCole Faust     }
get_row(uint8_t * dst,size_t row_size)114*c217d954SCole Faust     void get_row(uint8_t *dst, size_t row_size) override
115*c217d954SCole Faust     {
116*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(dst == nullptr);
117*c217d954SCole Faust         memcpy(dst, _data, row_size);
118*c217d954SCole Faust         _data += row_size;
119*c217d954SCole Faust     }
120*c217d954SCole Faust 
121*c217d954SCole Faust private:
122*c217d954SCole Faust     const uint8_t *_data;
123*c217d954SCole Faust };
124*c217d954SCole Faust 
125*c217d954SCole Faust /** Image loader interface */
126*c217d954SCole Faust class IImageLoader
127*c217d954SCole Faust {
128*c217d954SCole Faust public:
129*c217d954SCole Faust     /** Default Constructor */
IImageLoader()130*c217d954SCole Faust     IImageLoader()
131*c217d954SCole Faust         : _feeder(nullptr), _width(0), _height(0)
132*c217d954SCole Faust     {
133*c217d954SCole Faust     }
134*c217d954SCole Faust     /** Virtual base destructor */
135*c217d954SCole Faust     virtual ~IImageLoader() = default;
136*c217d954SCole Faust     /** Return the width of the currently open image file. */
width()137*c217d954SCole Faust     unsigned int width() const
138*c217d954SCole Faust     {
139*c217d954SCole Faust         return _width;
140*c217d954SCole Faust     }
141*c217d954SCole Faust     /** Return the height of the currently open image file. */
height()142*c217d954SCole Faust     unsigned int height() const
143*c217d954SCole Faust     {
144*c217d954SCole Faust         return _height;
145*c217d954SCole Faust     }
146*c217d954SCole Faust     /** Return true if the image file is currently open */
147*c217d954SCole Faust     virtual bool is_open() = 0;
148*c217d954SCole Faust     /** Open an image file and reads its metadata (Width, height)
149*c217d954SCole Faust      *
150*c217d954SCole Faust      * @param[in] filename File to open
151*c217d954SCole Faust      */
152*c217d954SCole Faust     virtual void open(const std::string &filename) = 0;
153*c217d954SCole Faust     /** Closes an image file */
154*c217d954SCole Faust     virtual void close() = 0;
155*c217d954SCole Faust     /** Initialise an image's metadata with the dimensions of the image file currently open
156*c217d954SCole Faust      *
157*c217d954SCole Faust      * @param[out] image  Image to initialise
158*c217d954SCole Faust      * @param[in]  format Format to use for the image (Must be RGB888 or U8)
159*c217d954SCole Faust      */
160*c217d954SCole Faust     template <typename T>
init_image(T & image,Format format)161*c217d954SCole Faust     void init_image(T &image, Format format)
162*c217d954SCole Faust     {
163*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(!is_open());
164*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(format != Format::RGB888 && format != Format::U8);
165*c217d954SCole Faust 
166*c217d954SCole Faust         // Use the size of the input image
167*c217d954SCole Faust         TensorInfo image_info(_width, _height, format);
168*c217d954SCole Faust         image.allocator()->init(image_info);
169*c217d954SCole Faust     }
170*c217d954SCole Faust     /** Fill an image with the content of the currently open image file.
171*c217d954SCole Faust      *
172*c217d954SCole Faust      * @note If the image is a CLImage, the function maps and unmaps the image
173*c217d954SCole Faust      *
174*c217d954SCole Faust      * @param[in,out] image Image to fill (Must be allocated, and of matching dimensions with the opened image file).
175*c217d954SCole Faust      */
176*c217d954SCole Faust     template <typename T>
fill_image(T & image)177*c217d954SCole Faust     void fill_image(T &image)
178*c217d954SCole Faust     {
179*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(!is_open());
180*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(image.info()->dimension(0) != _width || image.info()->dimension(1) != _height);
181*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(&image, Format::U8, Format::RGB888);
182*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(_feeder.get() == nullptr);
183*c217d954SCole Faust         try
184*c217d954SCole Faust         {
185*c217d954SCole Faust             // Map buffer if creating a CLTensor
186*c217d954SCole Faust             map(image, true);
187*c217d954SCole Faust 
188*c217d954SCole Faust             // Validate feeding data
189*c217d954SCole Faust             validate_info(image.info());
190*c217d954SCole Faust 
191*c217d954SCole Faust             switch(image.info()->format())
192*c217d954SCole Faust             {
193*c217d954SCole Faust                 case Format::U8:
194*c217d954SCole Faust                 {
195*c217d954SCole Faust                     // We need to convert the data from RGB to grayscale:
196*c217d954SCole Faust                     // Iterate through every pixel of the image
197*c217d954SCole Faust                     Window window;
198*c217d954SCole Faust                     window.set(Window::DimX, Window::Dimension(0, _width, 1));
199*c217d954SCole Faust                     window.set(Window::DimY, Window::Dimension(0, _height, 1));
200*c217d954SCole Faust 
201*c217d954SCole Faust                     Iterator out(&image, window);
202*c217d954SCole Faust 
203*c217d954SCole Faust                     unsigned char red   = 0;
204*c217d954SCole Faust                     unsigned char green = 0;
205*c217d954SCole Faust                     unsigned char blue  = 0;
206*c217d954SCole Faust 
207*c217d954SCole Faust                     execute_window_loop(window, [&](const Coordinates &)
208*c217d954SCole Faust                     {
209*c217d954SCole Faust                         red   = _feeder->get();
210*c217d954SCole Faust                         green = _feeder->get();
211*c217d954SCole Faust                         blue  = _feeder->get();
212*c217d954SCole Faust 
213*c217d954SCole Faust                         *out.ptr() = 0.2126f * red + 0.7152f * green + 0.0722f * blue;
214*c217d954SCole Faust                     },
215*c217d954SCole Faust                     out);
216*c217d954SCole Faust 
217*c217d954SCole Faust                     break;
218*c217d954SCole Faust                 }
219*c217d954SCole Faust                 case Format::RGB888:
220*c217d954SCole Faust                 {
221*c217d954SCole Faust                     // There is no format conversion needed: we can simply copy the content of the input file to the image one row at the time.
222*c217d954SCole Faust                     // Create a vertical window to iterate through the image's rows:
223*c217d954SCole Faust                     Window window;
224*c217d954SCole Faust                     window.set(Window::DimY, Window::Dimension(0, _height, 1));
225*c217d954SCole Faust 
226*c217d954SCole Faust                     Iterator out(&image, window);
227*c217d954SCole Faust                     size_t   row_size = _width * image.info()->element_size();
228*c217d954SCole Faust 
229*c217d954SCole Faust                     execute_window_loop(window, [&](const Coordinates &)
230*c217d954SCole Faust                     {
231*c217d954SCole Faust                         _feeder->get_row(out.ptr(), row_size);
232*c217d954SCole Faust                     },
233*c217d954SCole Faust                     out);
234*c217d954SCole Faust 
235*c217d954SCole Faust                     break;
236*c217d954SCole Faust                 }
237*c217d954SCole Faust                 default:
238*c217d954SCole Faust                     ARM_COMPUTE_ERROR("Unsupported format");
239*c217d954SCole Faust             }
240*c217d954SCole Faust 
241*c217d954SCole Faust             // Unmap buffer if creating a CLTensor
242*c217d954SCole Faust             unmap(image);
243*c217d954SCole Faust         }
244*c217d954SCole Faust         catch(const std::ifstream::failure &e)
245*c217d954SCole Faust         {
246*c217d954SCole Faust             ARM_COMPUTE_ERROR_VAR("Loading image file: %s", e.what());
247*c217d954SCole Faust         }
248*c217d954SCole Faust     }
249*c217d954SCole Faust     /** Fill a tensor with 3 planes (one for each channel) with the content of the currently open image file.
250*c217d954SCole Faust      *
251*c217d954SCole Faust      * @note If the image is a CLImage, the function maps and unmaps the image
252*c217d954SCole Faust      *
253*c217d954SCole Faust      * @param[in,out] tensor Tensor with 3 planes to fill (Must be allocated, and of matching dimensions with the opened image). Data types supported: U8/F16/F32
254*c217d954SCole Faust      * @param[in]     bgr    (Optional) Fill the first plane with blue channel (default = false)
255*c217d954SCole Faust      */
256*c217d954SCole Faust     template <typename T>
257*c217d954SCole Faust     void fill_planar_tensor(T &tensor, bool bgr = false)
258*c217d954SCole Faust     {
259*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(!is_open());
260*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(&tensor, 1, DataType::U8, DataType::QASYMM8, DataType::F32, DataType::F16);
261*c217d954SCole Faust 
262*c217d954SCole Faust         const DataLayout  data_layout  = tensor.info()->data_layout();
263*c217d954SCole Faust         const TensorShape tensor_shape = tensor.info()->tensor_shape();
264*c217d954SCole Faust 
265*c217d954SCole Faust         ARM_COMPUTE_UNUSED(tensor_shape);
266*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(tensor_shape[get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH)] != _width);
267*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(tensor_shape[get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT)] != _height);
268*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(tensor_shape[get_data_layout_dimension_index(data_layout, DataLayoutDimension::CHANNEL)] != 3);
269*c217d954SCole Faust 
270*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(_feeder.get() == nullptr);
271*c217d954SCole Faust 
272*c217d954SCole Faust         try
273*c217d954SCole Faust         {
274*c217d954SCole Faust             // Map buffer if creating a CLTensor
275*c217d954SCole Faust             map(tensor, true);
276*c217d954SCole Faust 
277*c217d954SCole Faust             // Validate feeding data
278*c217d954SCole Faust             validate_info(tensor.info());
279*c217d954SCole Faust 
280*c217d954SCole Faust             // Stride across channels
281*c217d954SCole Faust             size_t stride_z = 0;
282*c217d954SCole Faust 
283*c217d954SCole Faust             // Iterate through every pixel of the image
284*c217d954SCole Faust             Window window;
285*c217d954SCole Faust             if(data_layout == DataLayout::NCHW)
286*c217d954SCole Faust             {
287*c217d954SCole Faust                 window.set(Window::DimX, Window::Dimension(0, _width, 1));
288*c217d954SCole Faust                 window.set(Window::DimY, Window::Dimension(0, _height, 1));
289*c217d954SCole Faust                 window.set(Window::DimZ, Window::Dimension(0, 1, 1));
290*c217d954SCole Faust                 stride_z = tensor.info()->strides_in_bytes()[2];
291*c217d954SCole Faust             }
292*c217d954SCole Faust             else
293*c217d954SCole Faust             {
294*c217d954SCole Faust                 window.set(Window::DimX, Window::Dimension(0, 1, 1));
295*c217d954SCole Faust                 window.set(Window::DimY, Window::Dimension(0, _width, 1));
296*c217d954SCole Faust                 window.set(Window::DimZ, Window::Dimension(0, _height, 1));
297*c217d954SCole Faust                 stride_z = tensor.info()->strides_in_bytes()[0];
298*c217d954SCole Faust             }
299*c217d954SCole Faust 
300*c217d954SCole Faust             Iterator out(&tensor, window);
301*c217d954SCole Faust 
302*c217d954SCole Faust             unsigned char red   = 0;
303*c217d954SCole Faust             unsigned char green = 0;
304*c217d954SCole Faust             unsigned char blue  = 0;
305*c217d954SCole Faust 
306*c217d954SCole Faust             execute_window_loop(window, [&](const Coordinates &)
307*c217d954SCole Faust             {
308*c217d954SCole Faust                 red   = _feeder->get();
309*c217d954SCole Faust                 green = _feeder->get();
310*c217d954SCole Faust                 blue  = _feeder->get();
311*c217d954SCole Faust 
312*c217d954SCole Faust                 switch(tensor.info()->data_type())
313*c217d954SCole Faust                 {
314*c217d954SCole Faust                     case DataType::U8:
315*c217d954SCole Faust                     case DataType::QASYMM8:
316*c217d954SCole Faust                     {
317*c217d954SCole Faust                         *(out.ptr() + 0 * stride_z) = bgr ? blue : red;
318*c217d954SCole Faust                         *(out.ptr() + 1 * stride_z) = green;
319*c217d954SCole Faust                         *(out.ptr() + 2 * stride_z) = bgr ? red : blue;
320*c217d954SCole Faust                         break;
321*c217d954SCole Faust                     }
322*c217d954SCole Faust                     case DataType::F32:
323*c217d954SCole Faust                     {
324*c217d954SCole Faust                         *reinterpret_cast<float *>(out.ptr() + 0 * stride_z) = static_cast<float>(bgr ? blue : red);
325*c217d954SCole Faust                         *reinterpret_cast<float *>(out.ptr() + 1 * stride_z) = static_cast<float>(green);
326*c217d954SCole Faust                         *reinterpret_cast<float *>(out.ptr() + 2 * stride_z) = static_cast<float>(bgr ? red : blue);
327*c217d954SCole Faust                         break;
328*c217d954SCole Faust                     }
329*c217d954SCole Faust                     case DataType::F16:
330*c217d954SCole Faust                     {
331*c217d954SCole Faust                         *reinterpret_cast<half *>(out.ptr() + 0 * stride_z) = static_cast<half>(bgr ? blue : red);
332*c217d954SCole Faust                         *reinterpret_cast<half *>(out.ptr() + 1 * stride_z) = static_cast<half>(green);
333*c217d954SCole Faust                         *reinterpret_cast<half *>(out.ptr() + 2 * stride_z) = static_cast<half>(bgr ? red : blue);
334*c217d954SCole Faust                         break;
335*c217d954SCole Faust                     }
336*c217d954SCole Faust                     default:
337*c217d954SCole Faust                     {
338*c217d954SCole Faust                         ARM_COMPUTE_ERROR("Unsupported data type");
339*c217d954SCole Faust                     }
340*c217d954SCole Faust                 }
341*c217d954SCole Faust             },
342*c217d954SCole Faust             out);
343*c217d954SCole Faust 
344*c217d954SCole Faust             // Unmap buffer if creating a CLTensor
345*c217d954SCole Faust             unmap(tensor);
346*c217d954SCole Faust         }
catch(const std::ifstream::failure & e)347*c217d954SCole Faust         catch(const std::ifstream::failure &e)
348*c217d954SCole Faust         {
349*c217d954SCole Faust             ARM_COMPUTE_ERROR_VAR("Loading image file: %s", e.what());
350*c217d954SCole Faust         }
351*c217d954SCole Faust     }
352*c217d954SCole Faust 
353*c217d954SCole Faust protected:
354*c217d954SCole Faust     /** Validate metadata */
validate_info(const ITensorInfo * tensor_info)355*c217d954SCole Faust     virtual void validate_info(const ITensorInfo *tensor_info)
356*c217d954SCole Faust     {
357*c217d954SCole Faust         ARM_COMPUTE_UNUSED(tensor_info);
358*c217d954SCole Faust     }
359*c217d954SCole Faust 
360*c217d954SCole Faust protected:
361*c217d954SCole Faust     std::unique_ptr<IImageDataFeeder> _feeder;
362*c217d954SCole Faust     unsigned int                      _width;
363*c217d954SCole Faust     unsigned int                      _height;
364*c217d954SCole Faust };
365*c217d954SCole Faust 
366*c217d954SCole Faust /** PPM Image loader concrete implementation */
367*c217d954SCole Faust class PPMLoader : public IImageLoader
368*c217d954SCole Faust {
369*c217d954SCole Faust public:
370*c217d954SCole Faust     /** Default Constructor */
PPMLoader()371*c217d954SCole Faust     PPMLoader()
372*c217d954SCole Faust         : IImageLoader(), _fs()
373*c217d954SCole Faust     {
374*c217d954SCole Faust     }
375*c217d954SCole Faust 
376*c217d954SCole Faust     // Inherited methods overridden:
is_open()377*c217d954SCole Faust     bool is_open() override
378*c217d954SCole Faust     {
379*c217d954SCole Faust         return _fs.is_open();
380*c217d954SCole Faust     }
open(const std::string & filename)381*c217d954SCole Faust     void open(const std::string &filename) override
382*c217d954SCole Faust     {
383*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(is_open());
384*c217d954SCole Faust         try
385*c217d954SCole Faust         {
386*c217d954SCole Faust             _fs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
387*c217d954SCole Faust             _fs.open(filename, std::ios::in | std::ios::binary);
388*c217d954SCole Faust 
389*c217d954SCole Faust             unsigned int max_val = 0;
390*c217d954SCole Faust             std::tie(_width, _height, max_val) = parse_ppm_header(_fs);
391*c217d954SCole Faust 
392*c217d954SCole Faust             ARM_COMPUTE_ERROR_ON_MSG_VAR(max_val >= 256, "2 bytes per colour channel not supported in file %s",
393*c217d954SCole Faust                                          filename.c_str());
394*c217d954SCole Faust 
395*c217d954SCole Faust             _feeder = std::make_unique<FileImageFeeder>(_fs);
396*c217d954SCole Faust         }
397*c217d954SCole Faust         catch(std::runtime_error &e)
398*c217d954SCole Faust         {
399*c217d954SCole Faust             ARM_COMPUTE_ERROR_VAR("Accessing %s: %s", filename.c_str(), e.what());
400*c217d954SCole Faust         }
401*c217d954SCole Faust     }
close()402*c217d954SCole Faust     void close() override
403*c217d954SCole Faust     {
404*c217d954SCole Faust         if(is_open())
405*c217d954SCole Faust         {
406*c217d954SCole Faust             _fs.close();
407*c217d954SCole Faust             _feeder = nullptr;
408*c217d954SCole Faust         }
409*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(is_open());
410*c217d954SCole Faust     }
411*c217d954SCole Faust 
412*c217d954SCole Faust protected:
413*c217d954SCole Faust     // Inherited methods overridden:
validate_info(const ITensorInfo * tensor_info)414*c217d954SCole Faust     void validate_info(const ITensorInfo *tensor_info) override
415*c217d954SCole Faust     {
416*c217d954SCole Faust         // Check if the file is large enough to fill the image
417*c217d954SCole Faust         const size_t current_position = _fs.tellg();
418*c217d954SCole Faust         _fs.seekg(0, std::ios_base::end);
419*c217d954SCole Faust         const size_t end_position = _fs.tellg();
420*c217d954SCole Faust         _fs.seekg(current_position, std::ios_base::beg);
421*c217d954SCole Faust 
422*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON_MSG((end_position - current_position) < tensor_info->tensor_shape().total_size(),
423*c217d954SCole Faust                                  "Not enough data in file");
424*c217d954SCole Faust         ARM_COMPUTE_UNUSED(end_position, tensor_info);
425*c217d954SCole Faust     }
426*c217d954SCole Faust 
427*c217d954SCole Faust private:
428*c217d954SCole Faust     std::ifstream _fs;
429*c217d954SCole Faust };
430*c217d954SCole Faust 
431*c217d954SCole Faust /** Class to load the content of a JPEG file into an Image */
432*c217d954SCole Faust class JPEGLoader : public IImageLoader
433*c217d954SCole Faust {
434*c217d954SCole Faust private:
435*c217d954SCole Faust     /** Custom malloc deleter struct */
436*c217d954SCole Faust     struct malloc_deleter
437*c217d954SCole Faust     {
operatormalloc_deleter438*c217d954SCole Faust         void operator()(uint8_t *p) const
439*c217d954SCole Faust         {
440*c217d954SCole Faust             free(p);
441*c217d954SCole Faust         }
442*c217d954SCole Faust     };
443*c217d954SCole Faust 
444*c217d954SCole Faust public:
445*c217d954SCole Faust     /** Default Constructor */
JPEGLoader()446*c217d954SCole Faust     JPEGLoader()
447*c217d954SCole Faust         : IImageLoader(), _is_loaded(false), _data(nullptr)
448*c217d954SCole Faust     {
449*c217d954SCole Faust     }
450*c217d954SCole Faust 
451*c217d954SCole Faust     // Inherited methods overridden:
is_open()452*c217d954SCole Faust     bool is_open() override
453*c217d954SCole Faust     {
454*c217d954SCole Faust         return _is_loaded;
455*c217d954SCole Faust     }
open(const std::string & filename)456*c217d954SCole Faust     void open(const std::string &filename) override
457*c217d954SCole Faust     {
458*c217d954SCole Faust         int      bpp, width, height;
459*c217d954SCole Faust         uint8_t *rgb_image = stbi_load(filename.c_str(), &width, &height, &bpp, 3);
460*c217d954SCole Faust         if(rgb_image == NULL)
461*c217d954SCole Faust         {
462*c217d954SCole Faust             ARM_COMPUTE_ERROR_VAR("Accessing %s failed", filename.c_str());
463*c217d954SCole Faust         }
464*c217d954SCole Faust         else
465*c217d954SCole Faust         {
466*c217d954SCole Faust             _width     = width;
467*c217d954SCole Faust             _height    = height;
468*c217d954SCole Faust             _data      = std::unique_ptr<uint8_t, malloc_deleter>(rgb_image);
469*c217d954SCole Faust             _is_loaded = true;
470*c217d954SCole Faust             _feeder    = std::make_unique<MemoryImageFeeder>(_data.get());
471*c217d954SCole Faust         }
472*c217d954SCole Faust     }
close()473*c217d954SCole Faust     void close() override
474*c217d954SCole Faust     {
475*c217d954SCole Faust         if(is_open())
476*c217d954SCole Faust         {
477*c217d954SCole Faust             _width  = 0;
478*c217d954SCole Faust             _height = 0;
479*c217d954SCole Faust             release();
480*c217d954SCole Faust         }
481*c217d954SCole Faust         ARM_COMPUTE_ERROR_ON(is_open());
482*c217d954SCole Faust     }
483*c217d954SCole Faust     /** Explicitly Releases the memory of the loaded data */
release()484*c217d954SCole Faust     void release()
485*c217d954SCole Faust     {
486*c217d954SCole Faust         if(_is_loaded)
487*c217d954SCole Faust         {
488*c217d954SCole Faust             _data.reset();
489*c217d954SCole Faust             _is_loaded = false;
490*c217d954SCole Faust             _feeder    = nullptr;
491*c217d954SCole Faust         }
492*c217d954SCole Faust     }
493*c217d954SCole Faust 
494*c217d954SCole Faust private:
495*c217d954SCole Faust     bool _is_loaded;
496*c217d954SCole Faust     std::unique_ptr<uint8_t, malloc_deleter> _data;
497*c217d954SCole Faust };
498*c217d954SCole Faust 
499*c217d954SCole Faust /** Factory for generating appropriate image loader**/
500*c217d954SCole Faust class ImageLoaderFactory final
501*c217d954SCole Faust {
502*c217d954SCole Faust public:
503*c217d954SCole Faust     /** Create an image loader depending on the image type
504*c217d954SCole Faust      *
505*c217d954SCole Faust      * @param[in] filename File than needs to be loaded
506*c217d954SCole Faust      *
507*c217d954SCole Faust      * @return Image loader
508*c217d954SCole Faust      */
create(const std::string & filename)509*c217d954SCole Faust     static std::unique_ptr<IImageLoader> create(const std::string &filename)
510*c217d954SCole Faust     {
511*c217d954SCole Faust         ImageType type = arm_compute::utils::get_image_type_from_file(filename);
512*c217d954SCole Faust         switch(type)
513*c217d954SCole Faust         {
514*c217d954SCole Faust             case ImageType::PPM:
515*c217d954SCole Faust                 return std::make_unique<PPMLoader>();
516*c217d954SCole Faust             case ImageType::JPEG:
517*c217d954SCole Faust                 return std::make_unique<JPEGLoader>();
518*c217d954SCole Faust             case ImageType::UNKNOWN:
519*c217d954SCole Faust             default:
520*c217d954SCole Faust                 return nullptr;
521*c217d954SCole Faust         }
522*c217d954SCole Faust     }
523*c217d954SCole Faust };
524*c217d954SCole Faust } // namespace utils
525*c217d954SCole Faust } // namespace arm_compute
526*c217d954SCole Faust #endif /* __UTILS_IMAGE_LOADER_H__*/
527