• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016-2020 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "src/core/NEON/kernels/NECumulativeDistributionKernel.h"
25 
26 #include "arm_compute/core/Error.h"
27 #include "arm_compute/core/Helpers.h"
28 #include "arm_compute/core/IDistribution1D.h"
29 #include "arm_compute/core/ILut.h"
30 #include "arm_compute/core/ITensor.h"
31 #include "arm_compute/core/Types.h"
32 #include "arm_compute/core/Validate.h"
33 #include "src/core/helpers/AutoConfiguration.h"
34 #include "src/core/helpers/WindowHelpers.h"
35 
36 #include <algorithm>
37 #include <cmath>
38 #include <numeric>
39 
40 using namespace arm_compute;
41 
NECumulativeDistributionKernel()42 NECumulativeDistributionKernel::NECumulativeDistributionKernel()
43     : _input(nullptr), _distribution(nullptr), _cumulative_sum(nullptr), _output(nullptr)
44 {
45 }
46 
is_parallelisable() const47 bool NECumulativeDistributionKernel::is_parallelisable() const
48 {
49     return false;
50 }
51 
configure(const IImage * input,const IDistribution1D * distribution,IDistribution1D * cumulative_sum,ILut * output)52 void NECumulativeDistributionKernel::configure(const IImage *input, const IDistribution1D *distribution, IDistribution1D *cumulative_sum, ILut *output)
53 {
54     ARM_COMPUTE_ERROR_ON_NULLPTR(input, distribution, cumulative_sum, output);
55     ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input);
56 
57     set_format_if_unknown(*input->info(), Format::U8);
58 
59     ARM_COMPUTE_ERROR_ON(distribution->num_bins() != cumulative_sum->num_bins());
60     ARM_COMPUTE_ERROR_ON(distribution->num_bins() != output->num_elements());
61     ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8);
62     ARM_COMPUTE_ERROR_ON(input->info()->data_type() != output->type());
63 
64     _input          = input;
65     _distribution   = distribution;
66     _cumulative_sum = cumulative_sum;
67     _output         = output;
68 
69     INEKernel::configure(calculate_max_window(*input->info()));
70 }
71 
run(const Window & window,const ThreadInfo & info)72 void NECumulativeDistributionKernel::run(const Window &window, const ThreadInfo &info)
73 {
74     ARM_COMPUTE_UNUSED(info);
75     ARM_COMPUTE_UNUSED(window);
76     ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
77     ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
78     ARM_COMPUTE_ERROR_ON(_distribution->buffer() == nullptr);
79     ARM_COMPUTE_ERROR_ON(_cumulative_sum->buffer() == nullptr);
80     ARM_COMPUTE_ERROR_ON(_output->buffer() == nullptr);
81     ARM_COMPUTE_ERROR_ON_MSG(_distribution->num_bins() < 256, "Distribution must have 256 bins");
82 
83     // Calculate the cumulative distribution (summed histogram).
84     const uint32_t *hist           = _distribution->buffer();
85     uint32_t       *cumulative_sum = _cumulative_sum->buffer();
86     uint8_t        *output         = _output->buffer();
87 
88     // Calculate cumulative distribution
89     std::partial_sum(hist, hist + _histogram_size, cumulative_sum);
90 
91     // Get the number of pixels that have the lowest value in the input image
92     const uint32_t cd_min = *std::find_if(hist, hist + _histogram_size, [](const uint32_t &v)
93     {
94         return v > 0;
95     });
96     const uint32_t image_size = cumulative_sum[_histogram_size - 1];
97 
98     ARM_COMPUTE_ERROR_ON(cd_min > image_size);
99 
100     // Create mapping lookup table
101     if(image_size == cd_min)
102     {
103         std::iota(output, output + _histogram_size, 0);
104     }
105     else
106     {
107         const float diff = image_size - cd_min;
108 
109         for(unsigned int x = 0; x < _histogram_size; ++x)
110         {
111             output[x] = lround((cumulative_sum[x] - cd_min) / diff * 255.0f);
112         }
113     }
114 }
115