1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "post_proc_slr.h"
17
18 #include <cstdint>
19 #include <memory>
20 #include <unistd.h>
21 #include <vector>
22 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
23 #include "ffrt.h"
24 #endif
25 #include "image_log.h"
26 #include "image_trace.h"
27 #include "image_utils.h"
28 #include "memory_manager.h"
29
30 namespace OHOS {
31 namespace Media {
32 using namespace std;
33
34 constexpr float PI = 3.14159265;
35 constexpr float EPSILON = 1e-6;
36 constexpr int FFRT_THREAD_LIMIT = 8;
37
GetSLRFactor(float x,int a)38 float GetSLRFactor(float x, int a)
39 {
40 if (a <= 0) {
41 return 1.0f;
42 }
43 if (std::fabs(x) < EPSILON) {
44 return 1.0f;
45 }
46 if (x > a || x < -a) {
47 return 0.0f;
48 }
49
50 x *= PI;
51 return a * std::sin(x) * std::sin(x / a) / (x * x);
52 }
53
GetWeights(float coeff,int n)54 SLRWeightMat SLRProc::GetWeights(float coeff, int n)
55 {
56 if (std::fabs(coeff) < EPSILON || coeff < .0f || n <= 0) {
57 return nullptr;
58 }
59 float tao = 1.0f / coeff;
60 int a = std::max(2, static_cast<int>(std::floor(tao))); // 2 max SLR box size
61 SLRWeightMat weights = std::make_shared<SLRWeightVec>(n, std::vector<float>(2 * a, 0));
62 float beta = 1.0f;
63 if (coeff > 0.8999f && coeff < 1.0f) { // 0.8999f adjust low pass filter
64 beta = 1.2f; // 1.2f adjust low pass filter
65 } else if (coeff < 0.9f && coeff > 0.8f) { // 0.9f adjust low pass filter
66 beta = 1.1f; // 1.1f adjust low pass filter
67 }
68 float scale = coeff > 1.0f ? 1.0f : coeff;
69
70 for (int i = 0; i < n; i++) {
71 float etaf = (i + 0.5) / coeff - 0.5;
72 int eta = std::floor(etaf);
73 for (int k = eta - a + 1; k < eta + a + 1; k++) {
74 float factor = GetSLRFactor(scale / beta * (etaf - k), a);
75 (*weights)[i][k - eta + a - 1] = factor;
76 }
77 }
78 std::vector<float> rowSum(n, 0);
79 for (int i = 0; i < n; i++) {
80 for (int j = 0; j < 2 * a; j++) { // 2 max SLR box size
81 rowSum[i] += (*weights)[i][j];
82 }
83 if (std::fabs(rowSum[i]) < EPSILON) {
84 rowSum[i] = 1.0f; // 1.0f default weight
85 }
86 for (int j = 0; j < 2 * a; j++) { // 2 max SLR box size
87 (*weights)[i][j] /= rowSum[i];
88 }
89 }
90 return weights;
91 }
92
SLRCheck(const SLRMat & src,const SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)93 bool SLRCheck(const SLRMat &src, const SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
94 {
95 if (x == nullptr || y == nullptr) {
96 return false;
97 }
98 if (src.size_.width == 0 || src.size_.height == 0) {
99 return false;
100 }
101 if (dst.size_.width == 0 || dst.size_.height == 0) {
102 return false;
103 }
104 return true;
105 }
106
SLRCast(float v)107 inline uint32_t SLRCast(float v)
108 {
109 v = std::clamp(v, 0.0f, 255.0f); // 255.0f rgba max value
110 uint32_t uv = static_cast<uint32_t>(v);
111 return uv;
112 }
113
114 struct SLRSliceKey {
SLRSliceKeyOHOS::Media::SLRSliceKey115 SLRSliceKey(int v1, int v2) : x(v1), y(v2) {}
116 int x;
117 int y;
118 };
119
SLRBoxCheck(const SLRSliceKey & key,const SLRMat & src,const SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)120 bool SLRBoxCheck(const SLRSliceKey &key, const SLRMat &src, const SLRMat &dst, const SLRWeightMat &x,
121 const SLRWeightMat &y)
122 {
123 if (key.x < 0 || key.y < 0) {
124 IMAGE_LOGE("SLRBoxCheck Key error:%{public}d, %{public}d", key.x, key.y);
125 return false;
126 }
127 uint32_t* srcArr = static_cast<uint32_t*>(src.data_);
128 if (srcArr == nullptr) {
129 IMAGE_LOGE("SLRBoxCheck srcArr null");
130 return false;
131 }
132 uint32_t* dstArr = static_cast<uint32_t*>(dst.data_);
133 if (dstArr == nullptr) {
134 IMAGE_LOGE("SLRBoxCheck dstArr null");
135 return false;
136 }
137 int srcM = src.size_.height;
138 int srcN = src.size_.width;
139 int dstM = dst.size_.height;
140 int dstN = dst.size_.width;
141 float coeffX = static_cast<float>(dstM) / srcM;
142 float coeffY = static_cast<float>(dstN) / srcN;
143 float taoX = 1 / coeffX;
144 float taoY = 1 / coeffY;
145 int aX = std::max(2, static_cast<int>(std::floor(taoX)));
146 int aY = std::max(2, static_cast<int>(std::floor(taoY))); // 2 default size
147 if (static_cast<int>((*x).size()) < key.y || static_cast<int>((*x)[0].size()) < 2 * aY) { // 2 max slr box size
148 IMAGE_LOGE("SLRBoxCheck h_y error:%{public}zu, %{public}d", (*x).size(), aY);
149 return false;
150 }
151 if (static_cast<int>((*y).size()) < key.x || static_cast<int>((*y)[0].size()) < 2 * aX) { // 2 max slr box size
152 IMAGE_LOGE("SLRBoxCheck h_x error:%{public}zu, %{public}d", (*y).size(), aX);
153 return false;
154 }
155 int dstIndex = key.x * dst.rowStride_ + key.y;
156 int maxDstSize = dstM * dstN;
157 if (dstIndex >= maxDstSize) {
158 IMAGE_LOGE("SLRBoxCheck dst index error:%{public}d, %{public}d", dstIndex, maxDstSize);
159 return false;
160 }
161 return true;
162 }
163
SLRBox(const SLRSliceKey & key,const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)164 void SLRBox(const SLRSliceKey &key, const SLRMat &src, SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
165 {
166 if (!SLRBoxCheck(key, src, dst, x, y)) {
167 return;
168 }
169 uint32_t* srcArr = static_cast<uint32_t*>(src.data_);
170 uint32_t* dstArr = static_cast<uint32_t*>(dst.data_);
171 int srcM = src.size_.height;
172 int srcN = src.size_.width;
173 int dstM = dst.size_.height;
174 int dstN = dst.size_.width;
175 float coeffX = static_cast<float>(dstM) / srcM;
176 float coeffY = static_cast<float>(dstN) / srcN;
177 float taoX = 1 / coeffX;
178 float taoY = 1 / coeffY;
179 int aX = std::max(2, static_cast<int>(std::floor(taoX)));
180 int aY = std::max(2, static_cast<int>(std::floor(taoY))); // 2 default size
181 int etaI = static_cast<int>((key.x + 0.5) * taoX - 0.5); // 0.5 middle index
182 int etaJ = static_cast<int>((key.y + 0.5) * taoY - 0.5); // 0.5 middle index
183 int rStart = etaI - aX + 1;
184 int rEnd = etaI + aX;
185 int cStart = etaJ - aY + 1;
186 int cEnd = etaJ + aY;
187 float rgba[4]{ .0f, .0f, .0f, .0f };
188 int maxSrcSize = srcM * srcN;
189 for (int r = rStart; r <= rEnd; ++r) {
190 int nR = min(max(0, r), srcM - 1);
191 for (int c = cStart; c <= cEnd; ++c) {
192 int nC = min(max(0, c), srcN - 1);
193 auto w = (*x)[key.y][c - cStart];
194 w *= (*y)[key.x][r - rStart];
195 int srcIndex = nR * src.rowStride_ + nC;
196 if (srcIndex < 0 || srcIndex >= maxSrcSize) {
197 IMAGE_LOGE("SLRBox src index error:%{public}d, %{public}d", srcIndex, maxSrcSize);
198 return;
199 }
200 uint32_t color = *(srcArr + srcIndex);
201 rgba[0] += ((color >> 24) & 0xFF) * w; // 24 rgba r
202 rgba[1] += ((color >> 16) & 0xFF) * w; // 16 rgba g
203 rgba[2] += ((color >> 8) & 0xFF) * w; // 2 8 rgba b
204 rgba[3] += (color & 0xFF) * w; // 3 rgba a
205 }
206 }
207 uint32_t r = SLRCast(rgba[0]);
208 uint32_t g = SLRCast(rgba[1]);
209 uint32_t b = SLRCast(rgba[2]); // 2 rgba
210 uint32_t a = SLRCast(rgba[3]); // 3 rgba
211 dstArr[key.x * dst.rowStride_ + key.y] = (r << 24) | (g << 16) | (b << 8) | a; // 24 16 8 rgba
212 }
213
Laplacian(SLRMat & srcMat,void * data,float alpha)214 void SLRProc::Laplacian(SLRMat &srcMat, void* data, float alpha)
215 {
216 IMAGE_LOGD("Laplacian pixelMap SLR:width=%{public}d,height=%{public}d,alpha=%{public}f", srcMat.size_.width,
217 srcMat.size_.height, alpha);
218 if (data == nullptr) {
219 IMAGE_LOGE("SLRProc::Laplacian create memory failed");
220 return;
221 }
222 const int m = srcMat.size_.height;
223 const int n = srcMat.size_.width;
224 const int stride = srcMat.rowStride_;
225 uint32_t* srcArr = static_cast<uint32_t*>(srcMat.data_);
226 uint32_t* dstArr = static_cast<uint32_t*>(data);
227
228 auto getPixel = [&](int i, int j) ->uint32_t {
229 i = std::clamp(i, 0, m - 1);
230 j = std::clamp(j, 0, n - 1);
231 return *(srcArr + i * stride + j);
232 };
233
234 auto extract = [](uint32_t color, int shift) -> uint32_t {
235 return (color >> shift) & 0xFF;
236 };
237 for (int i = 0; i < m; i++) {
238 for (int j = 0; j < n; j++) {
239 const uint32_t pixels[5] = {
240 getPixel(i, j), // center
241 getPixel(i, j - 1), // left
242 getPixel(i, j + 1), // right
243 getPixel(i - 1, j), // up
244 getPixel(i + 1, j) // down
245 };
246 const uint32_t cr = extract(pixels[0], 24); // 24 r
247 const uint32_t cg = extract(pixels[0], 16); // 16 g
248 const uint32_t cb = extract(pixels[0], 8); // 8 b
249 const uint32_t ca = pixels[0] & 0xFF;
250
251 auto delta = [&](uint32_t c, int shift) -> uint32_t {
252 return 4 * c
253 - extract(pixels[1], shift) // l left
254 - extract(pixels[2], shift) // 2 right
255 - extract(pixels[3], shift) // 3 up
256 - extract(pixels[4], shift); // 4 down
257 };
258 dstArr[i * stride + j] =
259 (SLRCast(cr + alpha * delta(cr, 24)) << 24) | // 24 r
260 (SLRCast(cg + alpha * delta(cg, 16)) << 16) | // 16 g
261 (SLRCast(cb + alpha * delta(cb, 8)) << 8) | // 8 b
262 ca;
263 }
264 }
265 }
266
Serial(const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)267 void SLRProc::Serial(const SLRMat &src, SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
268 {
269 if (!SLRCheck(src, dst, x, y)) {
270 IMAGE_LOGE("SLRProc::Serial param error");
271 return;
272 }
273
274 int m = dst.size_.height;
275 int n = dst.size_.width;
276 for (int i = 0; i < m; i++) {
277 for (int j = 0; j < n; j++) {
278 SLRSliceKey key(i, j);
279 SLRBox(key, src, dst, x, y);
280 }
281 }
282 }
283
SLRSubtask(const SLRSliceKey & key,const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)284 inline void SLRSubtask(const SLRSliceKey &key, const SLRMat &src, SLRMat &dst,
285 const SLRWeightMat &x, const SLRWeightMat &y)
286 {
287 int start = key.x;
288 int end = key.y;
289 int n = dst.size_.width;
290 for (int i = start; i < end; i++) {
291 for (int j = 0; j < n; j++) {
292 SLRSliceKey boxKey(i, j);
293 SLRBox(boxKey, src, dst, x, y);
294 }
295 }
296 }
297
Parallel(const SLRMat & src,SLRMat & dst,const SLRWeightMat & x,const SLRWeightMat & y)298 void SLRProc::Parallel(const SLRMat &src, SLRMat &dst, const SLRWeightMat &x, const SLRWeightMat &y)
299 {
300 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
301 if (!SLRCheck(src, dst, x, y)) {
302 IMAGE_LOGE("SLRProc::Parallel param error");
303 return;
304 }
305 const int maxThread = 16; // 16 max thread size
306 int m = dst.size_.height;
307 int n = dst.size_.width;
308 int step = m / maxThread;
309 int stepMod = (m % maxThread == 0) ? 1 : 0;
310 std::vector<ffrt::dependence> ffrtHandles;
311 std::vector<ffrt::dependence> ffrtHandles1;
312 for (int k = 0; k < maxThread - stepMod; k++) {
313 int start = k * step;
314 int end = (k + 1) * step;
315 auto func = [&src, &dst, &x, &y, start, end, n] {
316 SLRSliceKey key(start, end);
317 SLRSubtask(key, src, dst, x, y);
318 };
319 auto handler = ffrt::submit_h(func, {}, {}, ffrt::task_attr().qos(5)); // 5 max ffrt qos value
320 if (ffrtHandles.size() < FFRT_THREAD_LIMIT) {
321 ffrtHandles.emplace_back(handler);
322 } else {
323 ffrtHandles1.emplace_back(handler);
324 }
325 }
326
327 for (int i = (maxThread - stepMod) * step; i < m; i++) {
328 for (int j = 0; j < n; j++) {
329 SLRSliceKey key(i, j);
330 SLRBox(key, src, dst, x, y);
331 }
332 }
333
334 ffrt::wait(ffrtHandles);
335 ffrt::wait(ffrtHandles1);
336 #else
337 SLRProc::Serial(src, dst, x, y);
338 #endif
339 }
340 } // namespace Media
341 } // namespace OHOS
342