Changeset View
Changeset View
Standalone View
Standalone View
imagelib/effects/kpEffectToneEnhance.cpp
Show First 20 Lines • Show All 113 Lines • ▼ Show 20 Line(s) | |||||
114 | } | 114 | } | ||
115 | 115 | | |||
116 | //--------------------------------------------------------------------- | 116 | //--------------------------------------------------------------------- | ||
117 | 117 | | |||
118 | // protected | 118 | // protected | ||
119 | void kpEffectToneEnhanceApplier::DeleteToneMaps() | 119 | void kpEffectToneEnhanceApplier::DeleteToneMaps() | ||
120 | { | 120 | { | ||
121 | int nToneMaps = m_nToneMapGranularity * m_nToneMapGranularity; | 121 | int nToneMaps = m_nToneMapGranularity * m_nToneMapGranularity; | ||
122 | for(int i = 0; i < nToneMaps; i++) | 122 | for(int i = 0; i < nToneMaps; i++) { | ||
123 | delete[] m_pToneMaps[i]; | 123 | delete[] m_pToneMaps[i]; | ||
124 | } | ||||
124 | delete[] m_pToneMaps; | 125 | delete[] m_pToneMaps; | ||
125 | m_pToneMaps = nullptr; | 126 | m_pToneMaps = nullptr; | ||
126 | m_nToneMapGranularity = 0; | 127 | m_nToneMapGranularity = 0; | ||
127 | } | 128 | } | ||
128 | 129 | | |||
129 | //--------------------------------------------------------------------- | 130 | //--------------------------------------------------------------------- | ||
130 | 131 | | |||
131 | // protected | 132 | // protected | ||
132 | unsigned int* kpEffectToneEnhanceApplier::MakeToneMap(QImage* pImage, int u, int v, int nGranularity) | 133 | unsigned int* kpEffectToneEnhanceApplier::MakeToneMap(QImage* pImage, int u, int v, int nGranularity) | ||
133 | { | 134 | { | ||
134 | // Compute the region to make the tone map for | 135 | // Compute the region to make the tone map for | ||
135 | int xx, yy; | 136 | int xx, yy; | ||
136 | if(nGranularity > 1) | 137 | if(nGranularity > 1) | ||
137 | { | 138 | { | ||
138 | xx = u * (pImage->width() - 1) / (nGranularity - 1) - m_areaWid / 2; | 139 | xx = u * (pImage->width() - 1) / (nGranularity - 1) - m_areaWid / 2; | ||
139 | if(xx < 0) | 140 | if(xx < 0) { | ||
140 | xx = 0; | 141 | xx = 0; | ||
141 | else if(xx + m_areaWid > pImage->width()) | 142 | } | ||
143 | else if(xx + m_areaWid > pImage->width()) { | ||||
142 | xx = pImage->width() - m_areaWid; | 144 | xx = pImage->width() - m_areaWid; | ||
145 | } | ||||
146 | | ||||
143 | yy = v * (pImage->width() - 1) / (nGranularity - 1) - m_areaHgt / 2; | 147 | yy = v * (pImage->width() - 1) / (nGranularity - 1) - m_areaHgt / 2; | ||
144 | if(yy < 0) | 148 | | ||
149 | if(yy < 0) { | ||||
145 | yy = 0; | 150 | yy = 0; | ||
146 | else if(yy + m_areaHgt > pImage->height()) | 151 | } | ||
152 | else if(yy + m_areaHgt > pImage->height()) { | ||||
147 | yy = pImage->height() - m_areaHgt; | 153 | yy = pImage->height() - m_areaHgt; | ||
148 | } | 154 | } | ||
155 | } | ||||
149 | else | 156 | else | ||
150 | { | 157 | { | ||
151 | xx = 0; | 158 | xx = 0; | ||
152 | yy = 0; | 159 | yy = 0; | ||
153 | } | 160 | } | ||
154 | 161 | | |||
155 | // Make a tone histogram for the region | 162 | // Make a tone histogram for the region | ||
156 | memset(m_pHistogram, '\0', sizeof(unsigned int) * TONE_MAP_SIZE); | 163 | memset(m_pHistogram, '\0', sizeof(unsigned int) * TONE_MAP_SIZE); | ||
157 | int x, y; | 164 | int x, y; | ||
158 | unsigned int tone; | 165 | unsigned int tone; | ||
159 | for(y = 0; y < m_areaHgt; y++) | 166 | for(y = 0; y < m_areaHgt; y++) | ||
160 | { | 167 | { | ||
161 | for(x = 0; x < m_areaWid; x++) | 168 | for(x = 0; x < m_areaWid; x++) | ||
162 | { | 169 | { | ||
163 | tone = ComputeTone(pImage->pixel(xx + x, yy + y)); | 170 | tone = ComputeTone(pImage->pixel(xx + x, yy + y)); | ||
164 | m_pHistogram[tone >> TONE_DROP_BITS]++; | 171 | m_pHistogram[tone >> TONE_DROP_BITS]++; | ||
165 | } | 172 | } | ||
166 | } | 173 | } | ||
167 | 174 | | |||
168 | // Forward sum the tone histogram | 175 | // Forward sum the tone histogram | ||
169 | int i; | 176 | int i{}; | ||
170 | for(i = 1; i < TONE_MAP_SIZE; i++) | 177 | for(i = 1; i < TONE_MAP_SIZE; i++) { | ||
171 | m_pHistogram[i] += m_pHistogram[i - 1]; | 178 | m_pHistogram[i] += m_pHistogram[i - 1]; | ||
179 | } | ||||
172 | 180 | | |||
173 | // Compute the forward contribution to the tone map | 181 | // Compute the forward contribution to the tone map | ||
174 | unsigned int total = m_pHistogram[i - 1]; | 182 | auto total = m_pHistogram[i - 1]; | ||
175 | unsigned int* pToneMap = new unsigned int[TONE_MAP_SIZE]; | 183 | auto *pToneMap = new unsigned int[TONE_MAP_SIZE]; | ||
176 | for(i = 0; i < TONE_MAP_SIZE; i++) | 184 | for(i = 0; i < TONE_MAP_SIZE; i++) { | ||
177 | pToneMap[i] = static_cast<uint> (static_cast<unsigned long long int> (m_pHistogram[i] * MAX_TONE_VALUE / total)); | 185 | pToneMap[i] = static_cast<uint> (static_cast<unsigned long long int> (m_pHistogram[i] * MAX_TONE_VALUE / total)); | ||
186 | } | ||||
178 | /* | 187 | /* | ||
179 | // Undo the forward sum and reverse sum the tone histogram | 188 | // Undo the forward sum and reverse sum the tone histogram | ||
180 | m_pHistogram[TONE_MAP_SIZE - 1] -= m_pHistogram[TONE_MAP_SIZE - 2]; | 189 | m_pHistogram[TONE_MAP_SIZE - 1] -= m_pHistogram[TONE_MAP_SIZE - 2]; | ||
181 | for(i = TONE_MAP_SIZE - 2; i > 0; i--) | 190 | for(i = TONE_MAP_SIZE - 2; i > 0; i--) | ||
182 | { | 191 | { | ||
183 | m_pHistogram[i] -= m_pHistogram[i - 1]; | 192 | m_pHistogram[i] -= m_pHistogram[i - 1]; | ||
184 | m_pHistogram[i] += m_pHistogram[i + 1]; | 193 | m_pHistogram[i] += m_pHistogram[i + 1]; | ||
185 | } | 194 | } | ||
Show All 15 Lines | 204 | { | |||
201 | DeleteToneMaps(); | 210 | DeleteToneMaps(); | ||
202 | m_pToneMaps = new unsigned int*[nGranularity * nGranularity]; | 211 | m_pToneMaps = new unsigned int*[nGranularity * nGranularity]; | ||
203 | m_nToneMapGranularity = nGranularity; | 212 | m_nToneMapGranularity = nGranularity; | ||
204 | m_nComputedWid = static_cast<unsigned int> (pImage->width()); | 213 | m_nComputedWid = static_cast<unsigned int> (pImage->width()); | ||
205 | m_nComputedHgt = static_cast<unsigned int> (pImage->height()); | 214 | m_nComputedHgt = static_cast<unsigned int> (pImage->height()); | ||
206 | int u, v; | 215 | int u, v; | ||
207 | for(v = 0; v < nGranularity; v++) | 216 | for(v = 0; v < nGranularity; v++) | ||
208 | { | 217 | { | ||
209 | for(u = 0; u < nGranularity; u++) | 218 | for(u = 0; u < nGranularity; u++) { | ||
210 | m_pToneMaps[nGranularity * v + u] = MakeToneMap(pImage, u, v, nGranularity); | 219 | m_pToneMaps[nGranularity * v + u] = MakeToneMap(pImage, u, v, nGranularity); | ||
211 | } | 220 | } | ||
212 | } | 221 | } | ||
222 | } | ||||
213 | 223 | | |||
214 | //--------------------------------------------------------------------- | 224 | //--------------------------------------------------------------------- | ||
215 | 225 | | |||
216 | // protected | 226 | // protected | ||
217 | unsigned int kpEffectToneEnhanceApplier::InterpolateNewTone(QImage* pImage, unsigned int oldTone, int x, int y, int nGranularity) | 227 | unsigned int kpEffectToneEnhanceApplier::InterpolateNewTone(QImage* pImage, unsigned int oldTone, int x, int y, int nGranularity) | ||
218 | { | 228 | { | ||
219 | oldTone = (oldTone >> TONE_DROP_BITS); | 229 | oldTone = (oldTone >> TONE_DROP_BITS); | ||
220 | if(m_nToneMapGranularity <= 1) | 230 | if(m_nToneMapGranularity <= 1) { | ||
221 | return m_pToneMaps[0][oldTone]; | 231 | return m_pToneMaps[0][oldTone]; | ||
222 | int u = x * (nGranularity - 1) / pImage->width(); | 232 | } | ||
223 | int v = y * (nGranularity - 1) / pImage->height(); | 233 | auto u = x * (nGranularity - 1) / pImage->width(); | ||
224 | unsigned int x1y1 = m_pToneMaps[m_nToneMapGranularity * v + u][oldTone]; | 234 | auto v = y * (nGranularity - 1) / pImage->height(); | ||
225 | unsigned int x2y1 = m_pToneMaps[m_nToneMapGranularity * v + u + 1][oldTone]; | 235 | auto x1y1 = m_pToneMaps[m_nToneMapGranularity * v + u][oldTone]; | ||
226 | unsigned int x1y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u][oldTone]; | 236 | auto x2y1 = m_pToneMaps[m_nToneMapGranularity * v + u + 1][oldTone]; | ||
227 | unsigned int x2y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u + 1][oldTone]; | 237 | auto x1y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u][oldTone]; | ||
228 | int hFac = x - (u * (pImage->width() - 1) / (nGranularity - 1)); | 238 | auto x2y2 = m_pToneMaps[m_nToneMapGranularity * (v + 1) + u + 1][oldTone]; | ||
229 | if(hFac > m_areaWid) | 239 | auto hFac = x - (u * (pImage->width() - 1) / (nGranularity - 1)); | ||
240 | if(hFac > m_areaWid) { | ||||
230 | hFac = m_areaWid; | 241 | hFac = m_areaWid; | ||
242 | } | ||||
231 | unsigned int y1 = (x1y1 * (static_cast<unsigned int> (m_areaWid) - static_cast<unsigned int> (hFac)) | 243 | unsigned int y1 = (x1y1 * (static_cast<unsigned int> (m_areaWid) - static_cast<unsigned int> (hFac)) | ||
232 | + x2y1 * static_cast<unsigned int> (hFac)) / static_cast<unsigned int> (m_areaWid); | 244 | + x2y1 * static_cast<unsigned int> (hFac)) / static_cast<unsigned int> (m_areaWid); | ||
233 | 245 | | |||
234 | unsigned int y2 = (x1y2 * (static_cast<unsigned int> (m_areaWid) - static_cast<unsigned int> (hFac)) | 246 | unsigned int y2 = (x1y2 * (static_cast<unsigned int> (m_areaWid) - static_cast<unsigned int> (hFac)) | ||
235 | + x2y2 * static_cast<unsigned int> (hFac)) / static_cast<unsigned int> (m_areaWid); | 247 | + x2y2 * static_cast<unsigned int> (hFac)) / static_cast<unsigned int> (m_areaWid); | ||
236 | 248 | | |||
237 | int vFac = y - (v * (pImage->height() - 1) / (nGranularity - 1)); | 249 | int vFac = y - (v * (pImage->height() - 1) / (nGranularity - 1)); | ||
238 | if(vFac > m_areaHgt) | 250 | if(vFac > m_areaHgt) { | ||
239 | vFac = m_areaHgt; | 251 | vFac = m_areaHgt; | ||
252 | } | ||||
240 | return (y1 * (static_cast<unsigned int> (m_areaHgt) - static_cast<unsigned int> (vFac)) | 253 | return (y1 * (static_cast<unsigned int> (m_areaHgt) - static_cast<unsigned int> (vFac)) | ||
241 | + y2 * static_cast<unsigned int> (vFac)) / static_cast<unsigned int> (m_areaHgt); | 254 | + y2 * static_cast<unsigned int> (vFac)) / static_cast<unsigned int> (m_areaHgt); | ||
242 | } | 255 | } | ||
243 | 256 | | |||
244 | //--------------------------------------------------------------------- | 257 | //--------------------------------------------------------------------- | ||
245 | 258 | | |||
246 | // public | 259 | // public | ||
247 | void kpEffectToneEnhanceApplier::BalanceImageTone(QImage* pImage, double granularity, double amount) | 260 | void kpEffectToneEnhanceApplier::BalanceImageTone(QImage* pImage, double granularity, double amount) | ||
248 | { | 261 | { | ||
249 | if(pImage->width() < MIN_IMAGE_DIM || pImage->height() < MIN_IMAGE_DIM) | 262 | if(pImage->width() < MIN_IMAGE_DIM || pImage->height() < MIN_IMAGE_DIM) { | ||
250 | return; // the image is not big enough to perform this operation | 263 | return; // the image is not big enough to perform this operation | ||
264 | } | ||||
251 | int nGranularity = static_cast<int> (granularity * (MAX_GRANULARITY - 2)) + 1; | 265 | int nGranularity = static_cast<int> (granularity * (MAX_GRANULARITY - 2)) + 1; | ||
252 | m_areaWid = pImage->width() / nGranularity; | 266 | m_areaWid = pImage->width() / nGranularity; | ||
253 | if(m_areaWid < MIN_IMAGE_DIM) | 267 | if(m_areaWid < MIN_IMAGE_DIM) { | ||
254 | m_areaWid = MIN_IMAGE_DIM; | 268 | m_areaWid = MIN_IMAGE_DIM; | ||
269 | } | ||||
255 | m_areaHgt = pImage->height() / nGranularity; | 270 | m_areaHgt = pImage->height() / nGranularity; | ||
256 | if(m_areaHgt < MIN_IMAGE_DIM) | 271 | if(m_areaHgt < MIN_IMAGE_DIM) { | ||
257 | m_areaHgt = MIN_IMAGE_DIM; | 272 | m_areaHgt = MIN_IMAGE_DIM; | ||
273 | } | ||||
258 | ComputeToneMaps(pImage, nGranularity); | 274 | ComputeToneMaps(pImage, nGranularity); | ||
259 | int x, y; | 275 | int x, y; | ||
260 | unsigned int oldTone, newTone, col; | 276 | unsigned int oldTone, newTone, col; | ||
261 | for(y = 0; y < pImage->height(); y++) | 277 | for(y = 0; y < pImage->height(); y++) | ||
262 | { | 278 | { | ||
263 | for(x = 0; x < pImage->width(); x++) | 279 | for(x = 0; x < pImage->width(); x++) | ||
264 | { | 280 | { | ||
265 | col = pImage->pixel(x, y); | 281 | col = pImage->pixel(x, y); | ||
266 | oldTone = ComputeTone(col); | 282 | oldTone = ComputeTone(col); | ||
267 | newTone = InterpolateNewTone(pImage, oldTone, x, y, nGranularity); | 283 | newTone = InterpolateNewTone(pImage, oldTone, x, y, nGranularity); | ||
268 | pImage->setPixel(x, y, AdjustTone(col, oldTone, newTone, amount)); | 284 | pImage->setPixel(x, y, AdjustTone(col, oldTone, newTone, amount)); | ||
269 | } | 285 | } | ||
270 | } | 286 | } | ||
271 | } | 287 | } | ||
272 | 288 | | |||
273 | //--------------------------------------------------------------------- | 289 | //--------------------------------------------------------------------- | ||
274 | 290 | | |||
275 | // public static | 291 | // public static | ||
276 | kpImage kpEffectToneEnhance::applyEffect (const kpImage &image, | 292 | kpImage kpEffectToneEnhance::applyEffect (const kpImage &image, | ||
277 | double granularity, double amount) | 293 | double granularity, double amount) | ||
278 | { | 294 | { | ||
279 | if (amount == 0.0) | 295 | if (amount == 0.0) { | ||
280 | return image; | 296 | return image; | ||
297 | } | ||||
281 | 298 | | |||
282 | QImage qimage(image); | 299 | QImage qimage(image); | ||
283 | 300 | | |||
284 | // OPT: Cache the calculated values? | 301 | // OPT: Cache the calculated values? | ||
285 | kpEffectToneEnhanceApplier applier; | 302 | kpEffectToneEnhanceApplier applier; | ||
286 | applier.BalanceImageTone (&qimage, granularity, amount); | 303 | applier.BalanceImageTone (&qimage, granularity, amount); | ||
287 | 304 | | |||
288 | return qimage; | 305 | return qimage; | ||
289 | } | 306 | } | ||
290 | 307 | | |||
291 | //--------------------------------------------------------------------- | 308 | //--------------------------------------------------------------------- |