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