/work/vvenc/source/Lib/EncoderLib/SEIFilmGrainAnalyzer.h
Line | Count | Source |
1 | | /* ----------------------------------------------------------------------------- |
2 | | The copyright in this software is being made available under the Clear BSD |
3 | | License, included below. No patent rights, trademark rights and/or |
4 | | other Intellectual Property Rights other than the copyrights concerning |
5 | | the Software are granted under this license. |
6 | | |
7 | | The Clear BSD License |
8 | | |
9 | | Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V. & The VVenC Authors. |
10 | | All rights reserved. |
11 | | |
12 | | Redistribution and use in source and binary forms, with or without modification, |
13 | | are permitted (subject to the limitations in the disclaimer below) provided that |
14 | | the following conditions are met: |
15 | | |
16 | | * Redistributions of source code must retain the above copyright notice, |
17 | | this list of conditions and the following disclaimer. |
18 | | |
19 | | * Redistributions in binary form must reproduce the above copyright |
20 | | notice, this list of conditions and the following disclaimer in the |
21 | | documentation and/or other materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the copyright holder nor the names of its |
24 | | contributors may be used to endorse or promote products derived from this |
25 | | software without specific prior written permission. |
26 | | |
27 | | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY |
28 | | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
29 | | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
31 | | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
32 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
33 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
34 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
35 | | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
36 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
37 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
38 | | POSSIBILITY OF SUCH DAMAGE. |
39 | | |
40 | | |
41 | | ------------------------------------------------------------------------------------------- */ |
42 | | |
43 | | |
44 | | #ifndef __SEIFILMGRAINANALYZER__ |
45 | | #define __SEIFILMGRAINANALYZER__ |
46 | | |
47 | | #pragma once |
48 | | |
49 | | #include "CommonLib/Picture.h" |
50 | | #include "CommonLib/SEI.h" |
51 | | |
52 | | #include <numeric> |
53 | | #include <cmath> |
54 | | #include <algorithm> |
55 | | #include <fstream> // Include this for std::ofstream |
56 | | |
57 | | //using namespace vvenc; |
58 | | namespace vvenc { |
59 | | |
60 | | #if defined(TARGET_SIMD_X86) && ENABLE_SIMD_OPT_FGA |
61 | | using namespace x86_simd; |
62 | | #endif |
63 | | |
64 | | static constexpr double PI = 3.14159265358979323846; |
65 | | static constexpr double PI_2 = 3.14159265358979323846 / 2.0; |
66 | | static constexpr double pi_8 = PI / 8.0; |
67 | | static constexpr double pi_3_8 = 3.0 * PI / 8.0; |
68 | | static constexpr double pi_5_8 = 5.0 * PI / 8.0; |
69 | | static constexpr double pi_7_8 = 7.0 * PI / 8.0; |
70 | | |
71 | | static constexpr int DATA_BASE_SIZE = 64; |
72 | | static constexpr int INTERVAL_SIZE = 16; |
73 | | static constexpr int MAX_INTERVAL_NUMBER = (1 << 16) / INTERVAL_SIZE; |
74 | | static constexpr int MAXPAIRS = 256; |
75 | | |
76 | | static constexpr int KERNELSIZE = 3; // Dilation and erosion kernel size |
77 | | static constexpr int CONV_WIDTH_S = 3; |
78 | | static constexpr int CONV_HEIGHT_S = 3; |
79 | | // ==================================================================================================================== |
80 | | // Class definition |
81 | | // ==================================================================================================================== |
82 | | |
83 | | class Canny |
84 | | { |
85 | | public: |
86 | | Canny( bool enableOpt = true ); |
87 | | ~Canny(); |
88 | | |
89 | | unsigned int m_convWidthG = 5, m_convHeightG = 5; // Pixel's row and col positions for Gauss filtering |
90 | | |
91 | | void init ( unsigned int width, |
92 | | unsigned int height, |
93 | | ChromaFormat inputChroma ); |
94 | | |
95 | | void destroy (); |
96 | | |
97 | | void detect_edges ( const PelStorage* orig, |
98 | | PelStorage* dest, |
99 | | unsigned int uiBitDepth, |
100 | | ComponentID compID ); |
101 | | |
102 | | // Sobel gradient of a plane: the edge magnitude replaces the samples of buff1, and the quantized edge direction |
103 | | // goes to buff2. tmpBuf1 and tmpBuf2 hold the two Sobel responses (Gx and Gy of gradient_core) meanwhile. |
104 | | void (*gradient) ( PelStorage* buff1, |
105 | | PelStorage* buff2, |
106 | | PelStorage *tmpBuf1, |
107 | | PelStorage *tmpBuf2, |
108 | | unsigned int width, |
109 | | unsigned int height, |
110 | | unsigned int bitDepth, |
111 | | ComponentID compID); |
112 | | |
113 | | private: |
114 | | double m_lowThresholdRatio = 0.1; // low threshold rato |
115 | | int m_highThresholdRatio = 3; // high threshold rato |
116 | | |
117 | | PelStorage *m_orientationBuf = nullptr; |
118 | | PelStorage* m_gradientBufX = nullptr; |
119 | | PelStorage* m_gradientBufY = nullptr; |
120 | | |
121 | | void suppressNonMax ( PelStorage* buff1, |
122 | | PelStorage* buff2, |
123 | | unsigned int width, |
124 | | unsigned int height, |
125 | | ComponentID compID ); |
126 | | |
127 | | void doubleThreshold ( PelStorage *buff, |
128 | | unsigned int width, |
129 | | unsigned int height, |
130 | | unsigned int bitDepth, |
131 | | ComponentID compID ); |
132 | | |
133 | | void edgeTracking ( PelStorage* buff1, |
134 | | unsigned int width, |
135 | | unsigned int height, |
136 | | unsigned int windowWidth, |
137 | | unsigned int windowHeight, |
138 | | unsigned int bitDepth, |
139 | | ComponentID compID ); |
140 | | |
141 | | #if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_X86 ) |
142 | | void initFGACannyX86(); |
143 | | template <X86_VEXT vext> |
144 | | void _initFGACannyX86(); |
145 | | #endif |
146 | | }; |
147 | | |
148 | | class Morph |
149 | | { |
150 | | public: |
151 | | Morph( bool enableOpt = true ); |
152 | | ~Morph(); |
153 | | |
154 | | void init ( uint32_t width, |
155 | | uint32_t height ); |
156 | | |
157 | | void destroy (); |
158 | | |
159 | | int (*dilation) ( PelStorage *buff, |
160 | | PelStorage *Wbuf, |
161 | | uint32_t bitDepth, |
162 | | ComponentID compID, |
163 | | int numIter, |
164 | | int iter, |
165 | | Pel Value ); |
166 | | |
167 | | #if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_X86 ) |
168 | | void initFGAMorphX86(); |
169 | | template <X86_VEXT vext> |
170 | | void _initFGAMorphX86(); |
171 | | #endif |
172 | | #if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_ARM ) |
173 | | void initFGAMorphARM(); |
174 | | template <ARM_VEXT vext> |
175 | | void _initFGAMorphARM(); |
176 | | #endif |
177 | | |
178 | | PelStorage* m_dilationBuf = nullptr; |
179 | | PelStorage* m_dilationBuf2 = nullptr; |
180 | | PelStorage* m_dilationBuf4 = nullptr; |
181 | | }; |
182 | | |
183 | | |
184 | | class FGAnalyzer |
185 | | { |
186 | | public: |
187 | | FGAnalyzer( bool enableOpt = true ); |
188 | | ~FGAnalyzer(); |
189 | | |
190 | | int prevAnalysisPoc = -1; |
191 | | |
192 | | void init( const int width, |
193 | | const int height, |
194 | | const ChromaFormat inputChroma, |
195 | | const int *outputBitDepths, |
196 | | const bool doAnalysis[] ); |
197 | | void destroy (); |
198 | | |
199 | | void estimateGrainParameters ( Picture* pic ); |
200 | | |
201 | 0 | int getLog2scaleFactor() { return m_log2ScaleFactor; }; |
202 | | |
203 | 0 | SeiFgc::CompModel getCompModel( int idx ) { return m_compModel[idx]; }; |
204 | | |
205 | | double (*calcVar) ( const Pel* org, |
206 | | const ptrdiff_t origStride, |
207 | | const int w, |
208 | | const int h ); |
209 | | |
210 | | int (*calcMean) ( const Pel* org, |
211 | | const ptrdiff_t origStride, |
212 | | const int w, |
213 | | const int h ); |
214 | | |
215 | | void (*fastDCT2_64) ( const TCoeff* src, |
216 | | TCoeff* dst, |
217 | | int shift, |
218 | | int line, |
219 | | int iSkipLine, |
220 | | int iSkipLine2 ); |
221 | | |
222 | | private: |
223 | | int *m_bitDepths; |
224 | | ChromaFormat m_inputChromaFormat; |
225 | | bool m_doAnalysis[ComponentID::MAX_NUM_COMP] = { true, true, true }; |
226 | | |
227 | | Canny m_edgeDetector; |
228 | | Morph m_morphOperation; |
229 | | double m_lowIntensityRatio = 0.1; // supress everything below 0.1*maxIntensityOffset |
230 | | |
231 | | CoeffBuf * m_dctGrainBlockList; |
232 | | TCoeff * m_coeffBuf; |
233 | | int m_numDctGrainBlocks; |
234 | | |
235 | | std::vector<double> coeffs; |
236 | | std::vector<double> scalingVec; |
237 | | std::vector<int> quantVec; |
238 | | |
239 | | std::vector<int> vecMean; |
240 | | std::vector<int> vecVar; |
241 | | |
242 | | double meanSquaredDctGrain[DATA_BASE_SIZE][DATA_BASE_SIZE]; |
243 | | |
244 | | /* Interval points for fitFunction */ |
245 | | std::vector<int> vec_mean_intensity; |
246 | | std::vector<int> vec_variance_intensity; |
247 | | std::vector<int> element_number_per_interval; |
248 | | std::vector<int> tmp_data_x; |
249 | | std::vector<int> tmp_data_y; |
250 | | |
251 | | static constexpr double m_tapFilter[3] = { 1, 2, 1 }; |
252 | | static constexpr double m_normTap = 4.0; |
253 | | |
254 | | // fg model parameters |
255 | | int m_log2ScaleFactor; |
256 | | std::vector<std::array<int, 3>> finalIntervalsandScalingFactors; // lower_bound, upper_bound, scaling_factor |
257 | | SeiFgc::CompModel m_compModel[ComponentID::MAX_NUM_COMP]; |
258 | | |
259 | | const PelStorage *m_originalBuf = nullptr; |
260 | | const PelStorage *m_workingBuf = nullptr; |
261 | | PelStorage *m_maskBuf = nullptr; |
262 | | PelStorage *m_grainEstimateBuf = nullptr; |
263 | | PelStorage *m_workingBufSubsampled2 = nullptr; |
264 | | PelStorage *m_maskSubsampled2 = nullptr; |
265 | | PelStorage *m_workingBufSubsampled4 = nullptr; |
266 | | PelStorage *m_maskSubsampled4 = nullptr; |
267 | | PelStorage *m_maskUpsampled = nullptr; |
268 | | // for DCT |
269 | | TCoeff *m_DCTinout = nullptr; |
270 | | TCoeff *m_DCTtemp = nullptr; |
271 | | |
272 | | void findMask ( ComponentID compID ); |
273 | | |
274 | | void blockTransform ( CoeffBuf& currentCoeffBuf, |
275 | | int offsetX, |
276 | | int offsetY, |
277 | | uint32_t bitDepth, |
278 | | ComponentID compId ); |
279 | | |
280 | | void adaptiveSampling ( int bins, |
281 | | double threshold, |
282 | | std::vector<int>& significantIndices, |
283 | | bool isRow, |
284 | | int startIdx ); |
285 | | |
286 | | void estimateCutoffFreqAdaptive ( ComponentID compID ); |
287 | | |
288 | | void estimateScalingFactors ( uint32_t bitDepth, |
289 | | ComponentID compID ); |
290 | | |
291 | | bool fitFunction ( int order, |
292 | | int bitDepth, |
293 | | bool second_pass ); |
294 | | |
295 | | void avgScalingVec ( int bitDepth ); |
296 | | |
297 | | bool lloydMax ( double& distortion, |
298 | | int bitDepth ); |
299 | | |
300 | | void quantize ( std::vector<double>& quantizedVec, |
301 | | double& distortion, |
302 | | double partition[], |
303 | | double codebook[] ); |
304 | | |
305 | | void extendPoints ( int bitDepth ); |
306 | | |
307 | | void setEstimatedParameters ( uint32_t bitDepth, |
308 | | ComponentID compID ); |
309 | | |
310 | | void defineIntervalsAndScalings ( int bitDepth ); |
311 | | |
312 | | void scaleDown ( int bitDepth ); |
313 | | |
314 | | void confirmIntervals ( ); |
315 | | |
316 | | long double ldpow ( long double n, |
317 | | unsigned p ); |
318 | | |
319 | | int countEdges ( int windowSize, |
320 | | int offsetX, |
321 | | int offsetY, |
322 | | ComponentID compID ); |
323 | | |
324 | | void subsample ( PelStorage& output, |
325 | | const int factor = 2, |
326 | | const int padding = 0, |
327 | | ComponentID compID = COMP_Y ) const; |
328 | | |
329 | | void upsample ( const PelStorage& input, |
330 | | const int factor = 2, |
331 | | const int padding = 0, |
332 | | ComponentID compID = COMP_Y ) const; |
333 | | |
334 | | void combineMasks ( ComponentID compId ); |
335 | | |
336 | | void suppressLowIntensity ( const PelStorage& buff1, |
337 | | PelStorage& buff2, |
338 | | uint32_t bitDepth, |
339 | | ComponentID compId ); |
340 | | |
341 | | #if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_X86 ) |
342 | | void initFGAnalyzerX86(); |
343 | | template <X86_VEXT vext> |
344 | | void _initFGAnalyzerX86(); |
345 | | #endif |
346 | | #if ENABLE_SIMD_OPT_FGA && defined( TARGET_SIMD_ARM ) |
347 | | void initFGAnalyzerARM(); |
348 | | template <ARM_VEXT vext> |
349 | | void _initFGAnalyzerARM(); |
350 | | #endif |
351 | | }; |
352 | | |
353 | | } // namespace vvenc |
354 | | |
355 | | // Scalar reference for Morph::dilation. Global (not vvenc::) because this |
356 | | // header's .cpp only does "using namespace vvenc;" rather than wrapping its |
357 | | // definitions in the namespace. SIMD dilation implementations that need a |
358 | | // fallback for widths their vectorized path can't handle delegate to it |
359 | | // directly instead of duplicating the 3x3 test. |
360 | | int dilation_core( vvenc::PelStorage* buff, vvenc::PelStorage* Wbuf, uint32_t bitDepth, vvenc::ComponentID compID, |
361 | | int numIter, int iter, vvenc::Pel Value ); |
362 | | |
363 | | // Scalar reference for Canny::gradient, global for the same reason. The x86 SIMD gradient falls back to it for |
364 | | // widths its vectorized path can't handle. |
365 | | void gradient_core( vvenc::PelStorage* buff1, vvenc::PelStorage* buff2, vvenc::PelStorage* tmpBuf1, |
366 | | vvenc::PelStorage* tmpBuf2, uint32_t width, uint32_t height, uint32_t bitDepth, |
367 | | vvenc::ComponentID compID ); |
368 | | |
369 | | #endif // __SEIFILMGRAINANALYZER__ |
370 | | |
371 | | |