Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
ppg.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2023, 2025-2026 Aurélien PIERRE.
4
5 Ansel 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 Ansel 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 Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19
21#ifdef _OPENMP
22 #pragma omp declare simd aligned(in, out)
23#endif
24static int demosaic_ppg(float *const out, const float *const in, const dt_iop_roi_t *const roi_out,
25 const dt_iop_roi_t *const roi_in, const uint32_t filters, const float thrs)
26{
27 // these may differ a little, if you're unlucky enough to split a bayer block with cropping or similar.
28 // we never want to access the input out of bounds though:
29 assert(roi_in->width >= roi_out->width);
30 assert(roi_in->height >= roi_out->height);
31 // border interpolate
32 float sum[8];
33 for(int j = 0; j < roi_out->height; j++)
34 for(int i = 0; i < roi_out->width; i++)
35 {
36 if(i == 3 && j >= 3 && j < roi_out->height - 3) i = roi_out->width - 3;
37 if(i == roi_out->width) break;
38 memset(sum, 0, sizeof(float) * 8);
39 for(int y = j - 1; y != j + 2; y++)
40 for(int x = i - 1; x != i + 2; x++)
41 {
42 const int yy = y + roi_out->y, xx = x + roi_out->x;
43 if((yy >= 0) && (xx >= 0) && (yy < roi_in->height) && (xx < roi_in->width))
44 {
45 const int f = FC(y, x, filters);
46 sum[f] += in[(size_t)yy * roi_in->width + xx];
47 sum[f + 4]++;
48 }
49 }
50 const int f = FC(j, i, filters);
51 for(int c = 0; c < 3; c++)
52 {
53 if(c != f && sum[c + 4] > 0.0f)
54 out[4 * ((size_t)j * roi_out->width + i) + c] = sum[c] / sum[c + 4];
55 else
56 out[4 * ((size_t)j * roi_out->width + i) + c]
57 = in[((size_t)j + roi_out->y) * roi_in->width + i + roi_out->x];
58 }
59 }
60 const int median = thrs > 0.0f;
61 // if(median) fbdd_green(out, in, roi_out, roi_in, filters);
62 const float *input = in;
63 if(median)
64 {
65 float *med_in = (float *)dt_pixelpipe_cache_alloc_align_float_cache((size_t)roi_in->height * roi_in->width, 0);
66 if(med_in == NULL) return 1;
67 pre_median(med_in, in, roi_in, filters, 1, thrs);
68 input = med_in;
69 }
70// for all pixels except those in the 3 pixel border:
71// interpolate green from input into out float array, or copy color.
72#ifdef _OPENMP
73#pragma omp parallel for default(none) \
74 dt_omp_firstprivate(filters, out, roi_in, roi_out) \
75 shared(input) \
76 schedule(static)
77#endif
78 for(int j = 3; j < roi_out->height - 3; j++)
79 {
80 float *buf = out + (size_t)4 * roi_out->width * j + 4 * 3;
81 const float *buf_in = input + (size_t)roi_in->width * (j + roi_out->y) + 3 + roi_out->x;
82 for(int i = 3; i < roi_out->width - 3; i++)
83 {
84 const int c = FC(j, i, filters);
85 dt_aligned_pixel_t color;
86 const float pc = buf_in[0];
87 // if(__builtin_expect(c == 0 || c == 2, 1))
88 if(c == 0 || c == 2)
89 {
90 color[c] = pc;
91 // get stuff (hopefully from cache)
92 const float pym = buf_in[-roi_in->width * 1];
93 const float pym2 = buf_in[-roi_in->width * 2];
94 const float pym3 = buf_in[-roi_in->width * 3];
95 const float pyM = buf_in[+roi_in->width * 1];
96 const float pyM2 = buf_in[+roi_in->width * 2];
97 const float pyM3 = buf_in[+roi_in->width * 3];
98 const float pxm = buf_in[-1];
99 const float pxm2 = buf_in[-2];
100 const float pxm3 = buf_in[-3];
101 const float pxM = buf_in[+1];
102 const float pxM2 = buf_in[+2];
103 const float pxM3 = buf_in[+3];
104
105 const float guessx = (pxm + pc + pxM) * 2.0f - pxM2 - pxm2;
106 const float diffx = (fabsf(pxm2 - pc) + fabsf(pxM2 - pc) + fabsf(pxm - pxM)) * 3.0f
107 + (fabsf(pxM3 - pxM) + fabsf(pxm3 - pxm)) * 2.0f;
108 const float guessy = (pym + pc + pyM) * 2.0f - pyM2 - pym2;
109 const float diffy = (fabsf(pym2 - pc) + fabsf(pyM2 - pc) + fabsf(pym - pyM)) * 3.0f
110 + (fabsf(pyM3 - pyM) + fabsf(pym3 - pym)) * 2.0f;
111 if(diffx > diffy)
112 {
113 // use guessy
114 const float m = fminf(pym, pyM);
115 const float M = fmaxf(pym, pyM);
116 color[1] = fmaxf(fminf(guessy * .25f, M), m);
117 }
118 else
119 {
120 const float m = fminf(pxm, pxM);
121 const float M = fmaxf(pxm, pxM);
122 color[1] = fmaxf(fminf(guessx * .25f, M), m);
123 }
124 }
125 else
126 color[1] = pc;
127
128 color[3] = 0.0f;
129 // write using MOVNTPS (write combine omitting caches)
130 // _mm_stream_ps(buf, col);
131 memcpy(buf, color, sizeof(float) * 4);
132 buf += 4;
133 buf_in++;
134 }
135 }
136
137// for all pixels except the outermost row/column:
138// interpolate colors using out as input into float out array
139#ifdef _OPENMP
140#pragma omp parallel for default(none) \
141 dt_omp_firstprivate(filters, out, roi_out) \
142 schedule(static)
143#endif
144 for(int j = 1; j < roi_out->height - 1; j++)
145 {
146 float *buf = out + (size_t)4 * roi_out->width * j + 4;
147 for(int i = 1; i < roi_out->width - 1; i++)
148 {
149 // also prefetch direct nbs top/bottom
150 const int c = FC(j, i, filters);
151 dt_aligned_pixel_t color = { buf[0], buf[1], buf[2], buf[3] };
152
153 // fill all four pixels with correctly interpolated stuff: r/b for green1/2
154 // b for r and r for b
155 if(__builtin_expect(c & 1, 1)) // c == 1 || c == 3)
156 {
157 // calculate red and blue for green pixels:
158 // need 4-nbhood:
159 const float *nt = buf - 4 * roi_out->width;
160 const float *nb = buf + 4 * roi_out->width;
161 const float *nl = buf - 4;
162 const float *nr = buf + 4;
163 if(FC(j, i + 1, filters) == 0) // red nb in same row
164 {
165 color[2] = (nt[2] + nb[2] + 2.0f * color[1] - nt[1] - nb[1]) * .5f;
166 color[0] = (nl[0] + nr[0] + 2.0f * color[1] - nl[1] - nr[1]) * .5f;
167 }
168 else
169 {
170 // blue nb
171 color[0] = (nt[0] + nb[0] + 2.0f * color[1] - nt[1] - nb[1]) * .5f;
172 color[2] = (nl[2] + nr[2] + 2.0f * color[1] - nl[1] - nr[1]) * .5f;
173 }
174 }
175 else
176 {
177 // get 4-star-nbhood:
178 const float *ntl = buf - 4 - 4 * roi_out->width;
179 const float *ntr = buf + 4 - 4 * roi_out->width;
180 const float *nbl = buf - 4 + 4 * roi_out->width;
181 const float *nbr = buf + 4 + 4 * roi_out->width;
182
183 if(c == 0)
184 {
185 // red pixel, fill blue:
186 const float diff1 = fabsf(ntl[2] - nbr[2]) + fabsf(ntl[1] - color[1]) + fabsf(nbr[1] - color[1]);
187 const float guess1 = ntl[2] + nbr[2] + 2.0f * color[1] - ntl[1] - nbr[1];
188 const float diff2 = fabsf(ntr[2] - nbl[2]) + fabsf(ntr[1] - color[1]) + fabsf(nbl[1] - color[1]);
189 const float guess2 = ntr[2] + nbl[2] + 2.0f * color[1] - ntr[1] - nbl[1];
190 if(diff1 > diff2)
191 color[2] = guess2 * .5f;
192 else if(diff1 < diff2)
193 color[2] = guess1 * .5f;
194 else
195 color[2] = (guess1 + guess2) * .25f;
196 }
197 else // c == 2, blue pixel, fill red:
198 {
199 const float diff1 = fabsf(ntl[0] - nbr[0]) + fabsf(ntl[1] - color[1]) + fabsf(nbr[1] - color[1]);
200 const float guess1 = ntl[0] + nbr[0] + 2.0f * color[1] - ntl[1] - nbr[1];
201 const float diff2 = fabsf(ntr[0] - nbl[0]) + fabsf(ntr[1] - color[1]) + fabsf(nbl[1] - color[1]);
202 const float guess2 = ntr[0] + nbl[0] + 2.0f * color[1] - ntr[1] - nbl[1];
203 if(diff1 > diff2)
204 color[0] = guess2 * .5f;
205 else if(diff1 < diff2)
206 color[0] = guess1 * .5f;
207 else
208 color[0] = (guess1 + guess2) * .25f;
209 }
210 }
211 // _mm_stream_ps(buf, col);
212 memcpy(buf, color, sizeof(float) * 4);
213 buf += 4;
214 }
215 }
216 // _mm_sfence();
218 return 0;
219}
220
221// clang-format off
222// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
223// vim: shiftwidth=2 expandtab tabstop=2 cindent
224// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
225// clang-format on
#define m
Definition basecurve.c:277
static void pre_median(float *out, const float *const in, const dt_iop_roi_t *const roi, const uint32_t filters, const int num_passes, const float threshold)
Definition basic.c:194
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const double thrs
Definition chart/main.c:54
const float i
Definition colorspaces_inline_conversions.h:669
const float c
Definition colorspaces_inline_conversions.h:1365
const dt_aligned_pixel_t f
Definition colorspaces_inline_conversions.h:256
static const dt_colormatrix_t M
Definition colorspaces_inline_conversions.h:933
static const dt_colormatrix_t dt_aligned_pixel_t out
Definition colorspaces_inline_conversions.h:184
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:371
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:377
static int FC(const int row, const int col, const unsigned int filters)
Definition data/kernels/common.h:47
static const float x
Definition iop_profile.h:239
#define median(a, n)
Definition noiseprofile.c:73
static int demosaic_ppg(float *const out, const float *const in, const dt_iop_roi_t *const roi_out, const dt_iop_roi_t *const roi_in, const uint32_t filters, const float thrs)
Definition ppg.c:24
Definition imageop.h:67
int x
Definition imageop.h:68
int width
Definition imageop.h:68
int height
Definition imageop.h:68
int y
Definition imageop.h:68