tfrun

An easy-to-use C++ wrapper over the stable C API of TensorFlow
git clone https://0xff.ir/g/tfrun.git
Log | Files | Refs | README | LICENSE

bmpread.cpp (3021B)


      1 // Copyright 2017 The TensorFlow Authors. All Rights Reserved.
      2 // SPDX-License-Identifier: Apache-2.0
      3 // tensorflow/lite/examples/label_image/bitmap_helpers.cc
      4 
      5 #include "bmpread.hpp"
      6 
      7 #include <fstream>
      8 #include <stdexcept>
      9 
     10 using namespace std::literals;
     11 
     12 namespace {
     13 
     14 std::vector<uint8_t>
     15 bmpdecode(const uint8_t* input,
     16           int row_size,
     17           int width,
     18           int height,
     19           int channels,
     20           bool top_down)
     21 {
     22   std::vector<uint8_t> output(height * width * channels);
     23 
     24   for (int i = 0; i < height; i++) {
     25     int src_pos;
     26     int dst_pos;
     27 
     28     for (int j = 0; j < width; j++) {
     29       if (!top_down)
     30         src_pos = ((height - 1 - i) * row_size) + j * channels;
     31       else
     32         src_pos = i * row_size + j * channels;
     33       dst_pos = (i * width + j) * channels;
     34 
     35       switch (channels) {
     36         case 1:
     37           output[dst_pos] = input[src_pos];
     38           break;
     39 
     40         case 3:
     41           // BGR -> RGB
     42           output[dst_pos] = input[src_pos + 2];
     43           output[dst_pos + 1] = input[src_pos + 1];
     44           output[dst_pos + 2] = input[src_pos];
     45           break;
     46 
     47         case 4:
     48           // BGRA -> RGBA
     49           output[dst_pos] = input[src_pos + 2];
     50           output[dst_pos + 1] = input[src_pos + 1];
     51           output[dst_pos + 2] = input[src_pos];
     52           output[dst_pos + 3] = input[src_pos + 3];
     53           break;
     54 
     55         default:
     56           throw std::runtime_error{ "Unexpected number of channels: "s +
     57                                     std::to_string(channels) };
     58       }
     59     }
     60   }
     61   return output;
     62 }
     63 
     64 } // namespace
     65 
     66 std::vector<uint8_t>
     67 bmpread(const std::string& input_bmp_name,
     68         int* width,
     69         int* height,
     70         int* channels)
     71 {
     72   int begin, end;
     73 
     74   std::ifstream file(input_bmp_name, std::ios::in | std::ios::binary);
     75 
     76   if (!file)
     77     throw std::runtime_error{ "input file "s + input_bmp_name +
     78                               " not found\n" };
     79 
     80   begin = file.tellg();
     81   file.seekg(0, std::ios::end);
     82   end = file.tellg();
     83   size_t len = end - begin;
     84 
     85   std::vector<uint8_t> img_bytes(len);
     86 
     87   file.seekg(0, std::ios::beg);
     88   file.read(reinterpret_cast<char*>(img_bytes.data()), len);
     89 
     90   const int32_t header_size =
     91     *(reinterpret_cast<const int32_t*>(img_bytes.data() + 10));
     92 
     93   *width = *(reinterpret_cast<const int32_t*>(img_bytes.data() + 18));
     94   *height = *(reinterpret_cast<const int32_t*>(img_bytes.data() + 22));
     95 
     96   const int32_t bpp =
     97     *(reinterpret_cast<const int32_t*>(img_bytes.data() + 28));
     98 
     99   *channels = bpp / 8;
    100 
    101   // there may be padding bytes when the width is not a multiple of 4 bytes
    102   // 8 * channels == bits per pixel
    103   const int row_size = (8 * *channels * *width + 31) / 32 * 4;
    104 
    105   // if height is negative, data layout is top down
    106   // otherwise, it's bottom up
    107   bool top_down = (*height < 0);
    108 
    109   // Decode image, allocating tensor once the image size is known
    110   const uint8_t* bmp_pixels = &img_bytes[header_size];
    111   return bmpdecode(
    112     bmp_pixels, row_size, *width, abs(*height), *channels, top_down);
    113 }