1 #include <iostream>
2 #include <vector>
3 #include <limits> // std::numeric_limits
4 #include "igs_color_rgb_hsv.h"
5 #include "igs_math_random.h"
6 #include "igs_ifx_common.h" // igs::image::rgba
7 namespace {
8 /*------ バッファをまとめて確保(return or throwで自動解放) ------*/
9 class noise_reference_ {
10 public:
noise_reference_(const int ww,const int hh,const double hue_range,const double sat_range,const double val_range,const double alp_range,const unsigned long random_seed,const double near_blur,const int camera_x,const int camera_y,const int camera_w,const int camera_h)11 noise_reference_(const int ww, const int hh, const double hue_range,
12 const double sat_range, const double val_range,
13 const double alp_range, const unsigned long random_seed,
14 const double near_blur, const int camera_x,
15 const int camera_y, const int camera_w, const int camera_h)
16 : w_(ww), h_(hh), nblur_(near_blur) {
17 if (0 == ww) {
18 return;
19 }
20 if (0 == hh) {
21 return;
22 }
23
24 /* 枚数ゼロ(rangeが全部ゼロ)なのでノイズかけない */
25 if ((0.0 == hue_range) && (0.0 == sat_range) && (0.0 == val_range) &&
26 (0.0 == alp_range)) {
27 return;
28 }
29
30 /* memory確保 */
31 const int sz = ww * hh;
32 if (0.0 != hue_range) {
33 this->hue_array_.resize(sz);
34 }
35 if (0.0 != sat_range) {
36 this->sat_array_.resize(sz);
37 }
38 if (0.0 != val_range) {
39 this->val_array_.resize(sz);
40 }
41 if (0.0 != alp_range) {
42 this->alp_array_.resize(sz);
43 }
44
45 /* タネを設定 */
46 igs::math::random hue_rand, sat_rand, val_rand, alp_rand;
47 unsigned long step = 0;
48 if (0.0 != hue_range) {
49 hue_rand.seed(random_seed + step++);
50 }
51 if (0.0 != sat_range) {
52 sat_rand.seed(random_seed + step++);
53 }
54 if (0.0 != val_range) {
55 val_rand.seed(random_seed + step++);
56 }
57 if (0.0 != alp_range) {
58 alp_rand.seed(random_seed + step++);
59 }
60 igs::math::random hue_rand_ext, sat_rand_ext, val_rand_ext, alp_rand_ext;
61 if (0.0 != hue_range) {
62 hue_rand_ext.seed(random_seed + step++);
63 }
64 if (0.0 != sat_range) {
65 sat_rand_ext.seed(random_seed + step++);
66 }
67 if (0.0 != val_range) {
68 val_rand_ext.seed(random_seed + step++);
69 }
70 if (0.0 != alp_range) {
71 alp_rand_ext.seed(random_seed + step++);
72 }
73
74 /* ノイズを書く */
75 /* -???_range/2〜???_range/2 */
76 const int x1 = camera_x;
77 const int y1 = camera_y;
78 const int x2 = camera_x + camera_w - 1;
79 const int y2 = camera_y + camera_h - 1;
80
81 /* マージンあるかないかでノイズパターンが変わってしまうため、
82 near_blur用に広げてはいけない */
83 // if (0.0 != near_blur) { x1-=1; x2+=1; y1-=1; y2+=1; }
84
85 if (0.0 != hue_range) {
86 int pos = 0;
87 for (int yy = 0; yy < hh; ++yy) {
88 for (int xx = 0; xx < ww; ++xx, ++pos) {
89 if ((xx < x1) || (x2 < xx) || (yy < y1) || (y2 < yy)) {
90 /* 計算用マージンがあったらそこは別のパターン */
91 this->hue_array_[pos] = hue_range * (hue_rand_ext.next_d() - 0.5);
92 } else {
93 /* 計算用マージン幅が変化してもその中のノイズパターンは
94 変わらないようにマージン内は別計算 */
95 this->hue_array_[pos] = hue_range * (hue_rand.next_d() - 0.5);
96 }
97 }
98 }
99 }
100 if (0.0 != sat_range) {
101 int pos = 0;
102 for (int yy = 0; yy < hh; ++yy) {
103 for (int xx = 0; xx < ww; ++xx, ++pos) {
104 if ((xx < x1) || (x2 < xx) || (yy < y1) || (y2 < yy)) {
105 this->sat_array_[pos] = sat_range * (sat_rand_ext.next_d() - 0.5);
106 } else {
107 this->sat_array_[pos] = sat_range * (sat_rand.next_d() - 0.5);
108 }
109 }
110 }
111 }
112 if (0.0 != val_range) {
113 int pos = 0;
114 for (int yy = 0; yy < hh; ++yy) {
115 for (int xx = 0; xx < ww; ++xx, ++pos) {
116 if ((xx < x1) || (x2 < xx) || (yy < y1) || (y2 < yy)) {
117 this->val_array_[pos] = val_range * (val_rand_ext.next_d() - 0.5);
118 } else {
119 this->val_array_[pos] = val_range * (val_rand.next_d() - 0.5);
120 }
121 }
122 }
123 }
124 if (0.0 != alp_range) {
125 int pos = 0;
126 for (int yy = 0; yy < hh; ++yy) {
127 for (int xx = 0; xx < ww; ++xx, ++pos) {
128 if ((xx < x1) || (x2 < xx) || (yy < y1) || (y2 < yy)) {
129 this->alp_array_[pos] = alp_range * (alp_rand_ext.next_d() - 0.5);
130 } else {
131 this->alp_array_[pos] = alp_range * (alp_rand.next_d() - 0.5);
132 }
133 }
134 }
135 }
136 }
hue_value(const int xx,const int yy)137 double hue_value(const int xx, const int yy) {
138 return this->noise_value_(this->hue_array_, this->w_, this->h_, xx, yy,
139 this->nblur_);
140 }
sat_value(const int xx,const int yy)141 double sat_value(const int xx, const int yy) {
142 return this->noise_value_(this->sat_array_, this->w_, this->h_, xx, yy,
143 this->nblur_);
144 }
val_value(const int xx,const int yy)145 double val_value(const int xx, const int yy) {
146 return this->noise_value_(this->val_array_, this->w_, this->h_, xx, yy,
147 this->nblur_);
148 }
alp_value(const int xx,const int yy)149 double alp_value(const int xx, const int yy) {
150 return this->noise_value_(this->alp_array_, this->w_, this->h_, xx, yy,
151 this->nblur_);
152 }
clear()153 void clear() {
154 this->alp_array_.clear();
155 this->val_array_.clear();
156 this->sat_array_.clear();
157 this->hue_array_.clear();
158 }
~noise_reference_()159 ~noise_reference_() { this->clear(); }
160
161 private:
162 const int w_;
163 const int h_;
164 const double nblur_;
165 std::vector<double> hue_array_;
166 std::vector<double> sat_array_;
167 std::vector<double> val_array_;
168 std::vector<double> alp_array_;
accum_in_(const double * noise_array,const int ww,const int hh,const int xx,const int yy,double & accum_val,int & accum_count)169 void accum_in_(const double *noise_array, const int ww, const int hh,
170 const int xx, const int yy, double &accum_val,
171 int &accum_count) {
172 if ((0 <= xx) && (xx < ww) && (0 <= yy) && (yy < hh)) {
173 accum_val += noise_array[yy * ww + xx];
174 ++accum_count;
175 }
176 }
noise_value_(const std::vector<double> & noise_vector,const int ww,const int hh,const int xx,const int yy,const double near_blur)177 double noise_value_(const std::vector<double> &noise_vector, const int ww,
178 const int hh, const int xx, const int yy,
179 const double near_blur) {
180 if (noise_vector.size() <= 0) {
181 return 0.0;
182 }
183 const double *noise_array = &noise_vector.at(0);
184 if (0.0 == near_blur) {
185 return noise_array[yy * ww + xx];
186 }
187
188 double accum_val = 0.0;
189 int accum_count = 0;
190 this->accum_in_(noise_array, ww, hh, xx - 1, yy - 1, accum_val,
191 accum_count);
192 this->accum_in_(noise_array, ww, hh, xx, yy - 1, accum_val, accum_count);
193 this->accum_in_(noise_array, ww, hh, xx + 1, yy - 1, accum_val,
194 accum_count);
195 this->accum_in_(noise_array, ww, hh, xx - 1, yy, accum_val, accum_count);
196 this->accum_in_(noise_array, ww, hh, xx + 1, yy, accum_val, accum_count);
197 this->accum_in_(noise_array, ww, hh, xx - 1, yy + 1, accum_val,
198 accum_count);
199 this->accum_in_(noise_array, ww, hh, xx, yy + 1, accum_val, accum_count);
200 this->accum_in_(noise_array, ww, hh, xx + 1, yy + 1, accum_val,
201 accum_count);
202 if (accum_count <= 0) {
203 return noise_array[yy * ww + xx];
204 }
205 accum_val /= static_cast<double>(accum_count);
206
207 /* 中心Pixelと廻り(1Pixel幅)の平均値とのバランスを返す */
208 return (near_blur * accum_val) +
209 ((1.0 - near_blur) * noise_array[yy * ww + xx]);
210 /*
211 ノイズをなじませるために、
212 8近傍ピクセルと対象ピクセルとの重み付けをする処理
213 +-----+-----+-----+
214 | p00 | p01 | p02 |
215 +-----+-----+-----+
216 | p10 | p11 | p12 |
217 +-----+-----+-----+
218 | p20 | p21 | p22 |
219 +-----+-----+-----+
220 対象ピクセル = p11
221 8近傍ピクセル = p00,p01,p02,p10,p12,p20,p21,p22
222 重み付け = near_blur = nb = 0...1
223 注意:対象ピクセルが画像のエッジにあると、8近傍ピクセルには、
224 存在しないピクセルがあるのでそれは除いて計算する
225 p00+p01+p02+p10+p12+p20+p21+p22
226 ------------------------------- x nb + p22 x (1 - nb)
227 8
228 nb
229 = (p00+p01+p02+p10+p12+p20+p21+p22) x -- + p22 x (1 - nb)
230 8
231 nb == 0のとき
232 --> 対象ピクセルの値
233 = p22
234 nb == 0.5のとき
235 --> 対象が半分、8近傍平均値が半分
236 = (p00+p01+p02+p10+p12+p20+p21+p22) / 16 + p22 / 2
237 nb == 0.888...(8/9)のとき
238 --> 対象と8近傍クセルの平均値
239 = (p00+p01+p02+p10+p12+p20+p21+p22) x 8 / 72 + p22 / 9
240 nb == 1のとき
241 --> 8近傍ピクセルのみの平均値
242 = (p00+p01+p02+p10+p12+p20+p21+p22) / 8
243 */
244 }
245
246 /* copy constructorを無効化 */
247 noise_reference_(const noise_reference_ &);
248
249 /* 代入演算子を無効化 */
250 noise_reference_ &operator=(const noise_reference_ &);
251 };
252 /*------ 端値を適度に調整する ------*/
253 class control_term_within_limits_ {
254 public:
control_term_within_limits_(const double effective_low,const double effective_high,const double center,const int type,const double noise_range)255 control_term_within_limits_(const double effective_low /* = 0.0 */
256 ,
257 const double effective_high /* = 0.0 */
258 ,
259 const double center /* = 0.5 */
260 ,
261 const int type /* = 0 */
262 ,
263 const double noise_range /* = 0.0 */
264 )
265 : effective_low_(effective_low)
266 , effective_high_(effective_high)
267 , center_(center)
268 , type_(static_cast<term_type_>(type))
269 , noise_range_(noise_range) {}
exec(const double current_value,double & noise,double & shift_value)270 void exec(const double current_value /* 0...1 */
271 ,
272 double &noise /* -noise_range/2...noise_range/2 */
273 ,
274 double &shift_value) {
275 if ((0.0 < this->effective_low_) && (current_value < this->center_)) {
276 const double cen = this->center_;
277 const double val = current_value;
278 const double ran = this->noise_range_;
279 const double eff = this->effective_low_;
280 switch (this->type_) {
281 case shift_all_:
282 shift_value = ((cen - val) / cen) * (ran / 2.0) * eff;
283 break;
284 case shift_term_:
285 if (val < ran) {
286 shift_value = (((cen < ran) ? cen : ran) - val) / 2.0 * eff;
287 }
288 break;
289 case decrease_all_: {
290 const double tmp = (cen - val) / cen * eff;
291 if (0.0 < tmp) {
292 noise *= 1.0 - tmp;
293 }
294 } break;
295 case decrease_term_:
296 if (val < (ran / 2.0)) {
297 const double stop = (cen < (ran / 2.0)) ? cen : ran / 2.0;
298 const double tmp = (stop - val) / stop * eff;
299 if (0.0 < tmp) {
300 noise *= 1.0 - tmp;
301 }
302 }
303 break;
304 }
305 }
306
307 if ((0.0 < this->effective_high_) && (this->center_ < current_value)) {
308 const double cen = this->center_;
309 const double val = current_value;
310 const double ran = this->noise_range_;
311 const double eff = this->effective_high_;
312 switch (this->type_) {
313 case shift_all_:
314 shift_value = ((cen - val) / (1.0 - cen)) * (ran / 2.0) * eff;
315 break;
316 case shift_term_:
317 if ((1.0 - ran) < val) {
318 const double ira = 1.0 - ran;
319 shift_value = (((cen < ira) ? ira : cen) - val) / 2.0 * eff;
320 }
321 break;
322 case decrease_all_: {
323 const double tmp = (val - cen) / (1.0 - cen) * eff;
324 if (0.0 < tmp) {
325 noise *= 1.0 - tmp;
326 }
327 } break;
328 case decrease_term_:
329 if ((1.0 - (ran / 2.0)) < val) {
330 const double rpos = 1.0 - (ran / 2.0);
331 const double stop = (cen < rpos) ? rpos : cen;
332 const double tmp = (val - stop) / (1.0 - stop) * eff;
333 if (0.0 < tmp) {
334 noise *= 1.0 - tmp;
335 }
336 }
337 break;
338 }
339 }
340 }
noise_range(void) const341 double noise_range(void) const { return this->noise_range_; }
342
343 private:
344 /* low,high両方ゼロ =exec()内処理せず =端値はカット =default */
345 const double effective_low_;
346 const double effective_high_;
347
348 const double center_;
349
350 enum term_type_ { /* 端値の調整方法 */
351 shift_all_ = 0, /* 0.全体的にノイズ位置がずれる */
352 shift_term_, /* 1.端のみでノイズ位置がずれる */
353 decrease_all_, /* 2.全体的にノイズ幅が減る */
354 decrease_term_, /* 3.端のみでノイズ幅が減る */
355 };
356 const term_type_ type_;
357
358 const double noise_range_;
359
360 /* copy constructorを無効化 */
361 control_term_within_limits_(const control_term_within_limits_ &);
362
363 /* 代入演算子を無効化 */
364 control_term_within_limits_ &operator=(const control_term_within_limits_ &);
365 };
366 /*------ RGB値にノイズをのせる ------*/
pixel_rgb_(const double red_in,const double gre_in,const double blu_in,const double alp_in,const double hue_noise,const double sat_noise,const double val_noise,control_term_within_limits_ & sat_term,control_term_within_limits_ & val_term,double & red_out,double & gre_out,double & blu_out)367 void pixel_rgb_(const double red_in, const double gre_in, const double blu_in,
368 const double alp_in, const double hue_noise,
369 const double sat_noise, const double val_noise,
370 control_term_within_limits_ &sat_term,
371 control_term_within_limits_ &val_term, double &red_out,
372 double &gre_out, double &blu_out) {
373 if (0.0 == alp_in) {
374 red_out = red_in;
375 gre_out = gre_in;
376 blu_out = blu_in;
377 return;
378 }
379 double hue, sat, val;
380 igs::color::rgb_to_hsv(red_in, gre_in, blu_in, hue, sat, val);
381 if (0.0 != hue_noise) {
382 hue += 360.0 * hue_noise * alp_in;
383 while (hue < 0.0) {
384 hue += 360.0;
385 }
386 while (360.0 <= hue) {
387 hue -= 360.0;
388 }
389 }
390 if (0.0 != sat_term.noise_range()) {
391 double shift_value = 0;
392 double satnoise = sat_noise;
393 sat_term.exec(sat, satnoise, shift_value);
394 sat += shift_value * alp_in;
395 sat += satnoise * alp_in;
396 if (sat < 0.0) {
397 sat = 0.0;
398 } else if (1.0 < sat) {
399 sat = 1.0;
400 }
401 // if( 0.0 == sat ) hue = -1.0; // hsv_to_rgb(-)
402 }
403 if (0.0 != val_term.noise_range()) {
404 double shift_value = 0;
405 double valnoise = val_noise;
406 val_term.exec(val, valnoise, shift_value);
407 val += shift_value * alp_in;
408 val += valnoise * alp_in;
409 if (val < 0.0) {
410 val = 0.0;
411 } else if (1.0 < val) {
412 val = 1.0;
413 }
414 }
415 igs::color::hsv_to_rgb(hue, sat, val, red_out, gre_out, blu_out);
416 }
417 /*------ Alpha値にノイズをのせる ------*/
pixel_a_(const double alp_in,const double alp_noise,control_term_within_limits_ & alp_term,double & alp_out)418 void pixel_a_(const double alp_in, const double alp_noise,
419 control_term_within_limits_ &alp_term, double &alp_out) {
420 // if (0.0 == alp_in) { return; }
421 double alpin = alp_in;
422 if (0.0 != alp_term.noise_range()) {
423 double shift_value = 0.0;
424 double alpnoise = alp_noise;
425 alp_term.exec(alpin, alpnoise, shift_value);
426 const double mask = alpin;
427 alpin += shift_value * mask;
428 alpin += alpnoise * mask;
429 if (alpin < 0.0) {
430 alpin = 0.0;
431 } else if (1.0 < alpin) {
432 alpin = 1.0;
433 }
434 }
435 alp_out = alpin;
436 }
437 /*------ raster画像にノイズをのせるtemplate ------*/
438 template <class IT, class RT>
change_template_(IT * image_array,const int width,const int height,const int channels,const RT * ref,const int ref_mode,noise_reference_ & noise,const double hue_range,control_term_within_limits_ & sat_term,control_term_within_limits_ & val_term,control_term_within_limits_ & alp_term,const bool add_blend_sw)439 void change_template_(
440 IT *image_array, const int width, const int height, const int channels
441
442 ,
443 const RT *ref /* 求める画像(out)と同じ高さ、幅、チャンネル数 */
444 ,
445 const int ref_mode /* 0=R,1=G,2=B,3=A,4=Luminance,5=Nothing */
446
447 ,
448 noise_reference_ &noise, const double hue_range,
449 control_term_within_limits_ &sat_term,
450 control_term_within_limits_ &val_term, control_term_within_limits_ &alp_term
451
452 ,
453 const bool add_blend_sw) {
454 const int t_max = std::numeric_limits<IT>::max();
455 const double div_val = static_cast<double>(t_max);
456 const double mul_val = static_cast<double>(t_max) + 0.999999;
457 const int r_max = std::numeric_limits<RT>::max();
458 if (igs::image::rgba::siz == channels) {
459 using namespace igs::image::rgba;
460 for (int yy = 0; yy < height; ++yy) {
461 for (int xx = 0; xx < width; ++xx, image_array += channels) {
462 /* 変化量初期値 */
463 double refv = 1.0;
464
465 /* 参照画像あればピクセル単位の画像変化量を得る */
466 if (ref != 0) {
467 refv *= igs::color::ref_value(ref, channels, r_max, ref_mode);
468 ref += channels; /* continue;の前に行うこと */
469 }
470 /* 加算合成で、Alpha値ゼロならRGB値を計算する必要はない */
471 if (add_blend_sw && (0 == image_array[alp])) {
472 continue;
473 }
474 /* 加算合成でなくAlpha合成の時は、
475 Alpha値がゼロでもRGB値は存在する(してもよい) */
476
477 /* マスクSWがON、なら変化をMask */
478 if (add_blend_sw && (image_array[alp] < t_max)) {
479 refv *= static_cast<double>(image_array[alp]) / div_val;
480 }
481
482 if (((0.0 != hue_range) || (0.0 != val_term.noise_range()) ||
483 (0.0 !=
484 sat_term.noise_range())) /* ノイズがhsvのどれか一つはある */
485 ) {
486 double rr1 = static_cast<double>(image_array[red]) / div_val,
487 gg1 = static_cast<double>(image_array[gre]) / div_val,
488 bb1 = static_cast<double>(image_array[blu]) / div_val,
489 aa1 = static_cast<double>(image_array[alp]) / div_val;
490 double rr2 = 0, gg2 = 0, bb2 = 0;
491 pixel_rgb_(rr1, gg1, bb1, aa1, noise.hue_value(xx, yy),
492 noise.sat_value(xx, yy), noise.val_value(xx, yy), sat_term,
493 val_term, rr2, gg2, bb2);
494 if (refv != 1.0) {
495 rr2 = (rr2 - rr1) * refv + rr1;
496 gg2 = (gg2 - gg1) * refv + gg1;
497 bb2 = (bb2 - bb1) * refv + bb1;
498 }
499 image_array[red] = static_cast<IT>(rr2 * mul_val);
500 image_array[gre] = static_cast<IT>(gg2 * mul_val);
501 image_array[blu] = static_cast<IT>(bb2 * mul_val);
502 }
503 if (0.0 != alp_term.noise_range()) {
504 double aa1 = static_cast<double>(image_array[alp]) / div_val;
505 double aa2 = 0;
506 pixel_a_(aa1, noise.alp_value(xx, yy), alp_term, aa2);
507 if (refv != 1.0) {
508 aa2 = (aa2 - aa1) * refv + aa1;
509 }
510 image_array[alp] = static_cast<IT>(aa2 * mul_val);
511 }
512 }
513 }
514 } else if (igs::image::rgb::siz == channels) {
515 using namespace igs::image::rgb;
516 if (((0.0 != hue_range) || (0.0 != sat_term.noise_range()) ||
517 (0.0 != val_term.noise_range())) /* ノイズがhsvのどれか一つはある */
518 ) {
519 for (int yy = 0; yy < height; ++yy) {
520 for (int xx = 0; xx < width; ++xx, image_array += channels) {
521 /* 変化量初期値 */
522 double refv = 1.0;
523
524 /* 参照画像あればピクセル単位の画像変化量を得る */
525 if (ref != 0) {
526 refv *= igs::color::ref_value(ref, channels, r_max, ref_mode);
527 ref += channels; /* continue;の前に行うこと */
528 }
529
530 double rr1 = static_cast<double>(image_array[red]) / div_val,
531 gg1 = static_cast<double>(image_array[gre]) / div_val,
532 bb1 = static_cast<double>(image_array[blu]) / div_val;
533 double rr2 = 0, gg2 = 0, bb2 = 0;
534 pixel_rgb_(rr1, gg1, bb1, 1.0, noise.hue_value(xx, yy),
535 noise.sat_value(xx, yy), noise.val_value(xx, yy), sat_term,
536 val_term, rr2, gg2, bb2);
537 if (refv != 1.0) {
538 rr2 = (rr2 - rr1) * refv + rr1;
539 gg2 = (gg2 - gg1) * refv + gg1;
540 bb2 = (bb2 - bb1) * refv + bb1;
541 }
542 image_array[red] = static_cast<IT>(rr2 * mul_val);
543 image_array[gre] = static_cast<IT>(gg2 * mul_val);
544 image_array[blu] = static_cast<IT>(bb2 * mul_val);
545 }
546 }
547 }
548 } else if (1 == channels) { /* grayscale */
549 if (0.0 != val_term.noise_range()) {
550 for (int yy = 0; yy < height; ++yy) {
551 for (int xx = 0; xx < width; ++xx, ++image_array) {
552 /* 変化量初期値 */
553 double refv = 1.0;
554
555 /* 参照画像あればピクセル単位の画像変化量を得る */
556 if (ref != 0) {
557 refv *= igs::color::ref_value(ref, channels, r_max, ref_mode);
558 ref += channels; /* continue;の前に行うこと */
559 }
560
561 double va1 = static_cast<double>(image_array[0]) / div_val;
562 double shift_value = 0;
563 double val_noise = noise.val_value(xx, yy);
564 val_term.exec(va1, val_noise, shift_value);
565
566 double va2 = va1;
567 va2 += shift_value;
568 va2 += val_noise;
569 va2 = (va2 < 0.0) ? 0.0 : ((1.0 < va2) ? 1.0 : va2);
570
571 if (refv != 1.0) {
572 va2 = va1 + (va2 - va1) * refv;
573 }
574
575 image_array[0] = static_cast<IT>(va2 * mul_val);
576 }
577 }
578 }
579 }
580 }
581 }
582 //--------------------------------------------------------------------
583
584 #include <stdexcept> // std::domain_error
585 #include "igs_hsv_noise.h"
change(unsigned char * image_array,const int height,const int width,const int channels,const int bits,const unsigned char * ref,const int ref_bits,const int ref_mode,const int camera_x,const int camera_y,const int camera_w,const int camera_h,const double hue_range,const double sat_range,const double val_range,const double alp_range,const unsigned long random_seed,const double near_blur,const double sat_effective,const double sat_center,const int sat_type,const double val_effective,const double val_center,const int val_type,const double alp_effective,const double alp_center,const int alp_type,const bool add_blend_sw)586 void igs::hsv_noise::change(
587 unsigned char *image_array
588
589 ,
590 const int height, const int width, const int channels, const int bits
591
592 ,
593 const unsigned char *ref /* 求める画像と同じ高、幅、channels数 */
594 ,
595 const int ref_bits /* refがゼロのときはここもゼロ */
596 ,
597 const int ref_mode /* 0=R,1=G,2=B,3=A,4=Luminance,5=Nothing */
598
599 /* image_arrayに余白が変化してもノイズパターンが変わらない
600 ようにするためにカメラエリアを指定する */
601 ,
602 const int camera_x, const int camera_y, const int camera_w,
603 const int camera_h
604
605 ,
606 const double hue_range, const double sat_range, const double val_range,
607 const double alp_range, const unsigned long random_seed,
608 const double near_blur
609
610 ,
611 const double sat_effective, const double sat_center, const int sat_type,
612 const double val_effective, const double val_center, const int val_type,
613 const double alp_effective, const double alp_center, const int alp_type
614
615 ,
616 const bool add_blend_sw) {
617 if ((0.0 == hue_range) && (0.0 == sat_range) && (0.0 == val_range) &&
618 (0.0 == alp_range)) {
619 return;
620 }
621
622 if ((igs::image::rgba::siz != channels) &&
623 (igs::image::rgb::siz != channels) && (1 != channels) /* grayscale */
624 ) {
625 throw std::domain_error("Bad channels,Not rgba/rgb/grayscale");
626 }
627
628 /* ノイズ参照画像を作成する */
629 noise_reference_ noise(width, height, hue_range, sat_range, val_range,
630 alp_range, random_seed, near_blur, camera_x, camera_y,
631 camera_w, camera_h);
632
633 /* 端値を適度に調整する設定 */
634 control_term_within_limits_ sat_term(sat_effective, sat_effective, sat_center,
635 sat_type, sat_range);
636 control_term_within_limits_ val_term(val_effective, val_effective, val_center,
637 val_type, val_range);
638 control_term_within_limits_ alp_term(alp_effective, alp_effective, alp_center,
639 alp_type, alp_range);
640
641 /* rgb(a)画像にhsv(a)でドットノイズを加える */
642 if ((std::numeric_limits<unsigned char>::digits == bits) &&
643 ((std::numeric_limits<unsigned char>::digits == ref_bits) ||
644 (0 == ref_bits))) {
645 change_template_(image_array, width, height, channels, ref, ref_mode, noise,
646 hue_range, sat_term, val_term, alp_term, add_blend_sw);
647 noise.clear(); /* ノイズ画像メモリ解放 */
648 } else if ((std::numeric_limits<unsigned short>::digits == bits) &&
649 ((std::numeric_limits<unsigned char>::digits == ref_bits) ||
650 (0 == ref_bits))) {
651 change_template_(reinterpret_cast<unsigned short *>(image_array), width,
652 height, channels, ref, ref_mode, noise, hue_range,
653 sat_term, val_term, alp_term, add_blend_sw);
654 noise.clear(); /* ノイズ画像メモリ解放 */
655 } else if ((std::numeric_limits<unsigned short>::digits == bits) &&
656 (std::numeric_limits<unsigned short>::digits == ref_bits)) {
657 change_template_(
658 reinterpret_cast<unsigned short *>(image_array), width, height,
659 channels, reinterpret_cast<const unsigned short *>(ref), ref_mode,
660 noise, hue_range, sat_term, val_term, alp_term, add_blend_sw);
661 noise.clear(); /* ノイズ画像メモリ解放 */
662 } else if ((std::numeric_limits<unsigned char>::digits == bits) &&
663 (std::numeric_limits<unsigned short>::digits == ref_bits)) {
664 change_template_(image_array, width, height, channels,
665 reinterpret_cast<const unsigned short *>(ref), ref_mode,
666 noise, hue_range, sat_term, val_term, alp_term,
667 add_blend_sw);
668 noise.clear(); /* ノイズ画像メモリ解放 */
669 } else {
670 throw std::domain_error("Bad bits,Not uchar/ushort");
671 }
672 }
673