13e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
23e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
33e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerLicensed under the Apache License, Version 2.0 (the "License");
43e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFloweryou may not use this file except in compliance with the License.
53e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerYou may obtain a copy of the License at
63e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
73e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    http://www.apache.org/licenses/LICENSE-2.0
83e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
93e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerUnless required by applicable law or agreed to in writing, software
103e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerdistributed under the License is distributed on an "AS IS" BASIS,
113e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerSee the License for the specific language governing permissions and
133e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerlimitations under the License.
143e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower==============================================================================*/
151019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower#define EIGEN_USE_THREADS
161019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower
171019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower#if GOOGLE_CUDA
181019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower#define EIGEN_USE_GPU
191019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower#endif
201019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower
211019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower#include "tensorflow/core/kernels/adjust_saturation_op.h"
223e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include <memory>
233e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
243e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/framework/op_kernel.h"
253e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/framework/register_types.h"
263e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/framework/tensor.h"
273e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/framework/tensor_shape.h"
283e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/framework/types.h"
293e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/lib/core/status.h"
303e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/platform/logging.h"
313e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower#include "tensorflow/core/util/work_sharder.h"
323e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
333e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowernamespace tensorflow {
343e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
353e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowertypedef Eigen::ThreadPoolDevice CPUDevice;
363e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowertypedef Eigen::GpuDevice GPUDevice;
373e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
383e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerclass AdjustSaturationOpBase : public OpKernel {
393e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower protected:
406882effb863dcd0da00d3287959deac46734a0b2A. Unique TensorFlower  explicit AdjustSaturationOpBase(OpKernelConstruction* context)
416882effb863dcd0da00d3287959deac46734a0b2A. Unique TensorFlower      : OpKernel(context) {}
423e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
433e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  struct ComputeOptions {
443e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const Tensor* input;
453e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const Tensor* scale;
463e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    Tensor* output;
473e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    int64 channel_count;
483e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  };
493e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
503e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  virtual void DoCompute(OpKernelContext* context,
513e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                         const ComputeOptions& options) = 0;
523e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
533e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  void Compute(OpKernelContext* context) override {
543e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const Tensor& input = context->input(0);
553e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const Tensor& scale = context->input(1);
563e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    OP_REQUIRES(context, input.dims() >= 3,
573e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                errors::InvalidArgument("input must be at least 3-D, got shape",
583e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                                        input.shape().DebugString()));
593e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    OP_REQUIRES(context, TensorShapeUtils::IsScalar(scale.shape()),
603e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                errors::InvalidArgument("scale must be scalar: ",
613e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                                        scale.shape().DebugString()));
623e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    auto channels = input.dim_size(input.dims() - 1);
633e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    OP_REQUIRES(
643e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower        context, channels == 3,
653e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower        errors::InvalidArgument("input must have 3 channels but instead has ",
663e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                                channels, " channels."));
673e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
683e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    Tensor* output = nullptr;
693e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    OP_REQUIRES_OK(context,
703e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                   context->allocate_output(0, input.shape(), &output));
713e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
723e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    if (input.NumElements() > 0) {
733e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      const int64 channel_count = input.NumElements() / channels;
743e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      ComputeOptions options;
753e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      options.input = &input;
763e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      options.scale = &scale;
773e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      options.output = output;
783e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      options.channel_count = channel_count;
793e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      DoCompute(context, options);
803e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    }
813e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
823e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower};
833e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
843e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowertemplate <class Device>
853e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerclass AdjustSaturationOp;
863e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
873e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowernamespace internal {
883e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerstatic void rgb_to_hsv(float r, float g, float b, float* h, float* s,
893e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                       float* v) {
903e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float vv = std::max(r, std::max(g, b));
913e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float range = vv - std::min(r, std::min(g, b));
923e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  if (vv > 0) {
933e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    *s = range / vv;
943e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  } else {
953e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    *s = 0;
963e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
973e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float norm = 1.0f / (6.0f * range);
983e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float hh;
993e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  if (r == vv) {
1003e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    hh = norm * (g - b);
1013e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  } else if (g == vv) {
1023e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    hh = norm * (b - r) + 2.0 / 6.0;
1033e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  } else {
1043e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    hh = norm * (r - g) + 4.0 / 6.0;
1053e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
1063e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  if (range <= 0.0) {
1073e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    hh = 0;
1083e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
1093e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  if (hh < 0.0) {
1103e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    hh = hh + 1;
1113e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
1123e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  *v = vv;
1133e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  *h = hh;
1143e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower}
1153e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
1163e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower// Algorithm from wikipedia, https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
1173e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerstatic void hsv_to_rgb(float h, float s, float v, float* r, float* g,
1183e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                       float* b) {
1193e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float c = s * v;
1203e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float m = v - c;
1213e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float dh = h * 6;
1223e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float rr, gg, bb;
1233e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  int h_category = static_cast<int>(dh);
1243e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float fmodu = dh;
1253e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  while (fmodu <= 0) {
1263e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    fmodu += 2.0f;
1273e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
1283e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  while (fmodu >= 2.0f) {
1293e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    fmodu -= 2.0f;
1303e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
1313e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  float x = c * (1 - std::abs(fmodu - 1));
1323e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  switch (h_category) {
1333e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    case 0:
1343e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      rr = c;
1353e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      gg = x;
1363e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      bb = 0;
1373e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      break;
1383e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    case 1:
1393e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      rr = x;
1403e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      gg = c;
1413e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      bb = 0;
1423e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      break;
1433e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    case 2:
1443e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      rr = 0;
1453e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      gg = c;
1463e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      bb = x;
1473e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      break;
1483e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    case 3:
1493e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      rr = 0;
1503e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      gg = x;
1513e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      bb = c;
1523e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      break;
1533e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    case 4:
1543e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      rr = x;
1553e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      gg = 0;
1563e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      bb = c;
1573e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      break;
1583e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    case 5:
1593e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      rr = c;
1603e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      gg = 0;
1613e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      bb = x;
1623e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      break;
1633e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    default:
1643e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      rr = 0;
1653e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      gg = 0;
1663e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      bb = 0;
1673e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
1683e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  *r = rr + m;
1693e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  *g = gg + m;
1703e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  *b = bb + m;
1713e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower}
1723e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
1733e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower}  // namespace internal
1743e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
1753e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowertemplate <>
1763e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerclass AdjustSaturationOp<CPUDevice> : public AdjustSaturationOpBase {
1773e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower public:
1783e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  explicit AdjustSaturationOp(OpKernelConstruction* context)
1793e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower      : AdjustSaturationOpBase(context) {}
1803e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
1813e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  void DoCompute(OpKernelContext* context,
1823e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                 const ComputeOptions& options) override {
1833e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const Tensor* input = options.input;
1843e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const Tensor* scale = options.scale;
1853e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    Tensor* output = options.output;
1863e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const int64 channel_count = options.channel_count;
1873e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    static const int kChannelSize = 3;
1883e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    auto input_data = input->shaped<float, 2>({channel_count, kChannelSize});
1893e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const float scale_h = scale->scalar<float>()();
1903e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    auto output_data = output->shaped<float, 2>({channel_count, kChannelSize});
1913e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const int kCostPerChannel = 10;
1923e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    const DeviceBase::CpuWorkerThreads& worker_threads =
1933e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower        *context->device()->tensorflow_cpu_worker_threads();
1943e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower    Shard(worker_threads.num_threads, worker_threads.workers, channel_count,
195982549ea3423df4270ff154e5c764beb43d472daRasmus Munk Larsen          kCostPerChannel,
196982549ea3423df4270ff154e5c764beb43d472daRasmus Munk Larsen          [channel_count, &input_data, &output_data, scale_h](
197982549ea3423df4270ff154e5c764beb43d472daRasmus Munk Larsen              int64 start_channel, int64 end_channel) {
1983e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower            const float* p = input_data.data() + start_channel * kChannelSize;
1993e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower            float* q = output_data.data() + start_channel * kChannelSize;
2003e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower            for (int i = start_channel; i < end_channel; i++) {
2013e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              float h, s, v;
2023e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              // Convert the RGB color to Hue/V-range.
2033e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              internal::rgb_to_hsv(p[0], p[1], p[2], &h, &s, &v);
2043e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              s = std::min(1.0f, std::max(0.0f, s * scale_h));
2053e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              // Convert the hue and v-range back into RGB.
2063e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              internal::hsv_to_rgb(h, s, v, q, q + 1, q + 2);
2073e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              p += kChannelSize;
2083e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower              q += kChannelSize;
2093e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower            }
2103e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower          });
2113e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower  }
2123e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower};
2133e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
2143e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlowerREGISTER_KERNEL_BUILDER(Name("AdjustSaturation").Device(DEVICE_CPU),
2153e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower                        AdjustSaturationOp<CPUDevice>);
2163e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower
2171019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower#if GOOGLE_CUDA
2181019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlowertemplate <>
2191019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlowerclass AdjustSaturationOp<GPUDevice> : public AdjustSaturationOpBase {
2201019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower public:
2211019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower  explicit AdjustSaturationOp(OpKernelConstruction* context)
2221019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower      : AdjustSaturationOpBase(context) {}
2231019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower
2241019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower  void DoCompute(OpKernelContext* context,
2251019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower                 const ComputeOptions& options) override {
2261019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    const Tensor* input = options.input;
2271019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    const Tensor* scale = options.scale;
2281019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    Tensor* output = options.output;
2291019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    const int64 number_of_elements = input->NumElements();
2301019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    GPUDevice device = context->eigen_gpu_device();
2311019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    const auto stream = device.stream();
2321019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    OP_REQUIRES(context, stream, errors::Internal("No GPU stream available."));
2331019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    if (number_of_elements > 0) {
2341019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower      const float* input_data = input->flat<float>().data();
2351019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower      const float* scale_data = scale->flat<float>().data();
2361019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower      float* const output_data = output->flat<float>().data();
2371019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower      functor::AdjustSaturationGPU()(&device, number_of_elements, input_data,
2381019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower                                     scale_data, output_data);
2391019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower    }
2401019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower  }
2411019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower};
2421019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower
2431019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlowerREGISTER_KERNEL_BUILDER(Name("AdjustSaturation").Device(DEVICE_GPU),
2441019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower                        AdjustSaturationOp<GPUDevice>);
2451019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower
2461019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower#endif
2471019621df2b8e7f516be13de3fbb4fb2833a686aA. Unique TensorFlower
2483e265dbe37ea49dba02fa4de6bec34d14a2ac241A. Unique TensorFlower}  // namespace tensorflow
249