Beatmup
image_sampler.cpp
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2020, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "image_sampler.h"
20 #include "../gpu/bgl.h"
21 
22 using namespace Beatmup;
23 using namespace NNets;
24 
25 
26 static const char *UNIFORM_INPUT = "img";
27 
29  const std::string& name,
30  const IntPoint& size,
31  bool centerCrop,
32  bool linearInterp
33 ):
35  size(size),
36  input(nullptr), output(nullptr), program(nullptr),
37  linearInterpolation(linearInterp), centerCrop(centerCrop), rotation(0)
38 {}
39 
40 
42  InvalidArgument::check(index == 0, "Invalid output index of ImageSampler operation: " + std::to_string(index));
43  texture = this->output;
44 }
45 
46 
47 void ImageSampler::setInput(GL::TextureHandler& texture, int inputIndex) {
48  InvalidArgument::check(inputIndex == 0, "Invalid input index of ImageSampler operation: " + std::to_string(inputIndex));
49  this->input = &texture;
50 }
51 
52 
53 void ImageSampler::setOutput(GL::TextureHandler& texture, int outputIndex) {
54  InvalidArgument::check(outputIndex == 0, "Invalid output index of ImageSampler operation: " + std::to_string(outputIndex));
55  InvalidArgument::check(texture.getWidth() == size.x && texture.getHeight() == size.y,
56  "ImageSampler output size mismatch");
57  this->output = &texture;
58 }
59 
60 
62  static class ImageSamplerDeserializer : public AbstractOperation::Deserializer {
63  public:
64  ImageSamplerDeserializer() : Deserializer("image_sampler") {}
65  AbstractOperation* deserialize(Context& context, const Listing::Block& block) {
66  /** \page NNetsOpsSerialization
67  \section ImageSampler
68  \code{yaml}
69  - _name: arbitrary operation name
70  _type: image_sampler # fixed string
71  output_width: 224 # resulting image width in pixels
72  output_height: 224 # resulting image width in pixels
73  center_crop: true # center crop enabled, "true" or "false" (defaults to "true")
74  linear_interp: true # linear interpolation of input pixels enabled, "true" or "false" (defaults to "true")
75  \endcode
76  */
77  return new ImageSampler(
78  block["_name"],
79  IntPoint(block.get<int>("output_width"), block.get<int>("output_height")),
80  block.get<bool>("center_crop", true),
81  block.get<bool>("linear_interp", true)
82  );
83  }
84  } john;
85 
86  return true;
87 }
88 
89 
90 std::map<std::string, std::string> ImageSampler::serialize() const {
91  return {
92  { "_name", getName() },
93  { "_type", "image_sampler" },
94  { "output_width", std::to_string(size.x) },
95  { "output_height", std::to_string(size.y) },
96  { "linear_interp", linearInterpolation ? "true" : "false" },
97  { "center_crop", centerCrop ? "true" : "false" }
98  };
99 }
100 
101 
103  input = output = nullptr;
104 }
105 
106 
107 
108 unsigned long ImageSampler::countTexelFetches() const {
109  return size.x * size.y;
110 }
111 
112 
114  RuntimeError::check(input, "Input is not provided to a ImageSampler operation.");
115 
116  // delete the old program
117  if (program)
118  bank.release(gpu, program);
119 
120  // begin the shader code
122 
123  // declare the sampler
125 
126  // add main code
127  code.printf(R"glsl(
128  void main() {
129  gl_FragColor = %s(%s, %s);
130  }
132 
133  // init program
134  bool enableExtTexExt = input->getTextureFormat() == GL::TextureHandler::TextureFormat::OES_Ext;
135  program = bank(gpu, code, enableExtTexExt);
136 }
137 
138 
140  if (!program)
141  throw NotReady(this);
142  RuntimeError::check(input, "Input is not provided to a ImageSampler operation.");
143  RuntimeError::check(output, "Output is not provided to a ImageSampler operation.");
144 
145  // enable program
146  program->enable(gpu);
147 
148  // bind output
149  gpu.bindOutput(*output);
150 
151  // bind input
153 
154  // setup texture coordinates
155  const IntPoint inputSize(input->getWidth(), input->getHeight());
156  Rectangle texCoords;
157  if (centerCrop) {
158  float hMargin = 0, vMargin = 0;
159  if (input->getWidth() * output->getHeight() > input->getHeight() * output->getWidth()) {
160  // input is cut vertically
161  hMargin = 0.5f * (input->getWidth() - (float)input->getHeight() * output->getWidth() / output->getHeight());
162  }
163  else {
164  // input is cut horizontally
165  vMargin = 0.5f * (input->getHeight() - (float)input->getWidth() * output->getHeight() / output->getWidth());
166  }
167  texCoords = gpu.getTextureCoordinates(Rectangle(hMargin, vMargin, input->getWidth() - 1 - hMargin, input->getHeight() - 1 - vMargin), inputSize, size);
168  }
169  else {
170  texCoords = gpu.getTextureCoordinates(Rectangle(0, 0, input->getWidth() - 1, input->getHeight() - 1), inputSize, size);
171  }
172 
173  // apply rotation
174  if (rotation % 4 != 0) {
175  Point topLeft(texCoords.a), topRight(texCoords.b.x, texCoords.a.y), bottomLeft(texCoords.a.x, texCoords.b.y), bottomRight(texCoords.b), tmp;
176  switch (rotation % 4) {
177  case 1:
178  tmp = bottomLeft;
179  bottomLeft = bottomRight;
180  bottomRight = topRight;
181  topRight = topLeft;
182  topLeft = tmp;
183  break;
184  case 2:
185  tmp = topLeft;
186  topLeft = bottomRight;
187  bottomRight = tmp;
188  tmp = topRight;
189  topRight = bottomLeft;
190  bottomLeft = tmp;
191  break;
192  case 3:
193  tmp = topLeft;
194  topLeft = topRight;
195  topRight = bottomRight;
196  bottomRight = bottomLeft;
197  bottomLeft = tmp;
198  break;
199  }
200  gpu.setTextureCoordinates(topLeft, topRight, bottomLeft, bottomRight);
201  }
202  else {
203  gpu.setTextureCoordinates(texCoords);
204  }
205 
206  // blend
207  program->blend();
208 }
A key-value pair set storing pieces of arbitrary data (chunks) under string keys.
Definition: chunkfile.h:36
Basic class: task and memory management, any kind of static data.
Definition: context.h:59
CustomPoint< numeric > b
Definition: geometry.h:131
CustomPoint< numeric > a
Definition: geometry.h:131
void enable(const GraphicPipeline &gpu)
Definition: program.cpp:250
static const char * DIALECT_SAMPLER_DECL_TYPE
glsl type name to declare a texture in Beatmup dialect
Definition: program.h:109
static const char * DIALECT_TEXTURE_SAMPLING_FUNC
glsl function name to sample a texture in Beatmup dialect
Definition: program.h:110
Stores linked GLSL programs and their associated fragment shader codes.
Definition: program_bank.h:31
void release(GraphicPipeline &gpu, GL::RenderingProgram *program)
Marks a program as unused any more.
void blend(bool onScreen)
Definition: program.cpp:548
static const char * TEXTURE_COORDINATES_ID
Texture coordinates shader variable name in vertex shader.
static const char * DECLARE_TEXTURE_COORDINATES_IN_FRAG
Declaring texture coordinates in fragment shader.
virtual const int getHeight() const =0
Height of the texture in pixels.
virtual const TextureFormat getTextureFormat() const =0
Returns the texture format specifying how the shader must interpret the data.
virtual const int getWidth() const =0
Width of the texture in pixels.
Internal low-level GPU control API.
Definition: pipeline.h:33
static Rectangle getTextureCoordinates(const Rectangle &area, const IntPoint &size, const IntPoint &sampling)
Computes floating-point texture coordinates for pixel-accurate sampling: a texture gets sampled exact...
Definition: pipeline.cpp:976
void bindOutput(AbstractBitmap &bitmap)
Binds a bitmap to the pipeline output.
Definition: pipeline.cpp:891
void setTextureCoordinates(const Rectangle &coords)
Specifies texture coordinates for the next rendering pass.
Definition: pipeline.cpp:966
void bind(GL::TextureHandler &texture, size_t texUnit, const TextureParam param)
Definition: pipeline.cpp:881
static void check(const bool condition, const std::string &message)
Definition: exception.h:75
Set of key-value pairs.
Definition: listing.h:46
T get(const std::string &key) const
Returns a value by key casted to a given type.
Enables construction of an operation from its serialized representation.
Definition: operation.h:248
Abstract neural net operation (layer).
Definition: operation.h:46
std::string getName() const
Definition: operation.h:242
void prepare(GraphicPipeline &gpu, ChunkCollection &data, GL::ProgramBank &bank)
Compiles GLSL shaders.
void execute(TaskThread &thread, GraphicPipeline &gpu)
Executes the operation.
bool linearInterpolation
if true, the input image is linearly interpolated when possible
Definition: image_sampler.h:37
void getOutput(GL::TextureHandler *&texture, int index=0)
Returns a GL::TextureHandler bound to a specific operation output.
std::map< std::string, std::string > serialize() const
Returns a serialized representation of th operation;.
void setOutput(GL::TextureHandler &texture, int outputIndex=0)
static bool initDeserializer()
Sets up deserialization of the operation.
GL::TextureHandler * output
Definition: image_sampler.h:35
bool centerCrop
if true, a center crop is performed to sample the output image from the input; otherwise the input is...
Definition: image_sampler.h:38
GL::TextureHandler * input
Definition: image_sampler.h:35
void disconnect()
Assigns empty inputs and outputs.
ImageSampler(const std::string &name, const IntPoint &size, bool centerCrop=true, bool linearInterp=true)
Creates an instance of image preprocessing operation.
GL::RenderingProgram * program
Definition: image_sampler.h:36
int rotation
clockwise rotation to apply to the input image; 1 unit = 90 degrees
Definition: image_sampler.h:41
void setInput(GL::TextureHandler &texture, int inputIndex=0)
unsigned long countTexelFetches() const
Counts (approximate) number of texels fetches.
static void check(const bool condition, const std::string &message)
Definition: exception.h:64
StringBuilder & printf(const char *format,...)
StringBuilder including a string container.
Thread executing tasks.
Definition: parallelism.h:154
static const char * UNIFORM_INPUT
CustomPoint< int > IntPoint
Definition: geometry.h:629
CustomRectangle< float > Rectangle
Definition: geometry.h:627
@ INTERP_LINEAR
bilinear pixel interpolation
@ INTERP_NEAREST
nearest neighbor pixel interpolation
std::string to_string(Beatmup::NNets::ActivationFunction function)
return(jlong) new Beatmup jlong jstring name
jlong jint index
jlong jobject size
JNIEnv jlong jint rotation