1 #include <vector>
2 #include <stdexcept> /* std::domain_error(-) */
3 #include <limits> /* std::numeric_limits */
4 #include <cmath> /* pow(-),abs(-) */
5 #include <cstring> /* memmove */
6 #include "igs_ifx_common.h" /* igs::image::rgba */
7 #include "igs_motion_blur.h"
8
9 // #include <numeric> /* std::accumulate(-) */
10 #if 0 //------comment out-----------------------------------------------
11 namespace {
12 void dda_array_(
13 const int dx, /* = abs(x_vector = x2 - x1) */
14 const int dy, /* = abs(y_vector = y2 - y1) = array_size - 1 */
15 std::vector<int>&y_array /* array_size(0...dy)個ある */
16 ) {
17 /* ここではy方向に傾いている場合(dx <= dy)のみ扱う
18 y + *
19 (dy)| *
20 | *
21 | *
22 OUT + *
23 | *
24 | *
25 |*
26 0 +---+---+---+
27 0 x(dx)
28 IN
29 */
30 if (dy < dx) { return; } /* x方向に傾いていると処理できない */
31 if (dy <= 0) { return; } /* y長さがないと処理しない */
32
33 y_array.at(0) = 0; /* 始めは原点なのでインクリメントはゼロ */
34
35 /* 線分ループ */
36 const int incr1 = 2 * dx;
37 const int incr2 = 2 * (dx - dy);
38 int dd = (2 * dx) - dy;
39 for (int ii = 1; ii <= dy; ++ii) {
40 if (dd < 0) { dd += incr1; y_array.at(ii) = 0; }
41 else { dd += incr2; y_array.at(ii) = 1; }
42 }
43 }
44 }
45 namespace {
46 void set_position_(
47 const int x_vector,
48 const int y_vector,/* 絶対値の大きいほうが"size-1" */
49 std::vector<int>&x_array,
50 std::vector<int>&y_array /* 位置格納配列size個ある */
51 ) {
52 int dx = abs(x_vector);/* 線分の幅、ゼロ以上の大きさの数 */
53 int dy = abs(y_vector);/* 線分の高さ、ゼロ以上の大きさの数 */
54 int count = 0;
55
56 /* x方向に傾いている場合(dy < dx)
57 y + *
58 (dy)| *
59 | *
60 | *
61 OUT + *
62 | *
63 | *
64 |*
65 0 +---+---+---+
66 0 x(dx)
67 IN
68 */
69 if (dy < dx) {
70 for (int ii=0;ii<=dx;++ii) {x_array.at(ii) = ii;}
71 dda_array_( dy, dx, y_array );
72 for (int ii=1;ii<=dx;++ii) {y_array.at(ii)+=y_array.at(ii-1);}
73 count = dx;
74 }
75
76 /* y方向に傾いている場合(dx <= dy)
77 y + *
78 (dy)| *
79 | *
80 | *
81 OUT + *
82 | *
83 | *
84 |*
85 0 +---+---+---+
86 0 x(dx)
87 IN
88 */
89 else {
90 for (int ii=0;ii<=dy;++ii) {y_array.at(ii) = ii;}
91 dda_array_( dx, dy, x_array );
92 for (int ii=1;ii<=dy;++ii) {x_array.at(ii)+=x_array.at(ii-1);}
93 count = dy;
94 }
95
96 /* マイナス方向の場合は反転 */
97 if (x_vector < 0) {
98 for (int ii=1;ii<=count;++ii){x_array.at(ii)=-x_array.at(ii);}
99 }
100 if (y_vector < 0) {
101 for (int ii=1;ii<=count;++ii){y_array.at(ii)=-y_array.at(ii);}
102 }
103 }
104 void set_ratio_(
105 const double curve,
106 std::vector<double>&ratio_array
107 ) {
108 const int size = ratio_array.size();
109 /* リニア配置をする */
110 for (int ii = 0; ii < size; ++ii) {
111 ratio_array.at(ii) = ((double)(size-ii))/(double)(size);
112 }
113 /* カーブを設定(ガンマ計算) */
114 if (curve <= 0.0) {
115 for (int ii = 1; ii < size; ++ii) { ratio_array.at(ii) = 0.0; }
116 } else
117 if (1.0 != curve) {
118 for (int ii = 1; ii < size; ++ii) {
119 ratio_array.at(ii)=pow(ratio_array.at(ii),1.0/curve);
120 }
121 }
122 /* 正規化 */
123 double accum = 0;
124 for (int ii = 0; ii < size; ++ii) { accum+=ratio_array.at(ii);}
125 for (int ii = 0; ii < size; ++ii) { ratio_array.at(ii)/=accum;}
126 }
127 }
128 namespace {
129 void set_jaggy_(
130 const double x_vector,
131 const double y_vector,
132 const double vector_scale,
133 const double curve,
134 std::vector<double>&ratio_array,
135 std::vector<int>&x_array,
136 std::vector<int>&y_array
137 ) {
138 if (curve <= 0.0) { return; } /* blur効果なしならなにもしない */
139
140 int xv = static_cast<int>(x_vector * vector_scale + 0.5);
141 int yv = static_cast<int>(y_vector * vector_scale + 0.5);
142
143 int size;
144 if (abs(xv) <= abs(yv)) { size = abs(yv) + 1; }
145 else { size = abs(xv) + 1; }
146
147 ratio_array.resize(size);
148 x_array.resize(size);
149 y_array.resize(size);
150
151 set_ratio_( curve, ratio_array );
152 set_position_( xv, yv, x_array,y_array );
153 }
154 }
155 #endif //------comment out----------------------------------------------
156
157 namespace {
158 #ifndef M_PI
159 #define M_PI 3.14159265358979323846
160 #endif
vec_poi_to_len_pos_(const double xv,const double yv,const double xp,const double yp,double & len,double & pos)161 void vec_poi_to_len_pos_(
162 const double xv, const double yv, /* vector */
163 const double xp, const double yp, /* point */
164 double &len, /* vectorからpointまでの距離 */
165 double &pos /* vector方向でvector原点からpointまでの距離 */
166 ) {
167 /*
168 * ベクトルの角度を求める
169 */
170
171 double radian = 0.0;
172 /* ゼロエラー */
173 if ((0.0 == xv) && (0.0 == yv)) {
174 len = 0.0;
175 pos = 0.0;
176 return;
177 }
178 /* 第1象限(0 <= degree < 90)*/
179 else if ((0.0 < xv) && (0.0 <= yv)) {
180 radian = atan(yv / xv);
181 }
182 /* 第2象限(90 <= degree < 180) */
183 else if ((xv <= 0.0) && (0.0 < yv)) {
184 radian = atan(-xv / yv) + M_PI / 2.0;
185 }
186 /* 第3象限(180 <= degree < 270) */
187 else if ((xv < 0.0) && (yv <= 0.0)) {
188 radian = atan(yv / xv) + M_PI;
189 }
190 /* 第4象限(270 <= degree < 360(=0)) */
191 else if ((0.0 <= xv) && (yv < 0.0)) {
192 radian = atan(xv / -yv) + M_PI + M_PI / 2.0;
193 }
194
195 /*
196 * 逆回転し、ベクトルを+X軸上に置く
197 */
198
199 /* ベクトルを逆回転し、x軸プラス上に置く */
200 double xv_rot = xv * cos(-radian) - yv * sin(-radian);
201 // double yv_rot = xv * sin(-radian) + yv * cos(-radian);
202 /* ターゲット点も同様に逆回転する */
203 double xp_rot = xp * cos(-radian) - yp * sin(-radian);
204 double yp_rot = xp * sin(-radian) + yp * cos(-radian);
205
206 /*
207 * vectorからpointまでの距離
208 */
209
210 /* マイナス(原点より小さい)の場合、ベクトル始点からの距離 */
211 if (xp_rot < 0.0) {
212 len = sqrt((xp * xp) + (yp * yp));
213 }
214 /* ベクトルより大きい場合、ベクトル終点からの距離 */
215 else if (xv_rot < xp_rot) {
216 len = sqrt((xp - xv) * (xp - xv) + (yp - yv) * (yp - yv));
217 }
218 /* ベクトルの横範囲内なら、上下位置が距離となる */
219 else {
220 len = fabs(yp_rot);
221 }
222
223 /*
224 * vector方向でvector原点からpointまでの距離
225 */
226
227 pos = xp_rot;
228 }
229 }
230
231 namespace {
232 /* ベクトルからの指定範囲でサブピクセルがどのくらい含むかカウントする
233 ピクセルの位置は以下の図参照
234 y
235 ^
236 |
237 |
238 |
239 |
240 +---+
241 | | |
242 | +-|-------------------> x
243 | |
244 +---+
245 */
count_nearly_vector_(const double xv,const double yv,const double x_tgt,const double y_tgt,const long x_div,const long y_div,const double valid_len)246 int count_nearly_vector_(
247 const double xv, const double yv, /* vector */
248 const double x_tgt,
249 const double y_tgt, /* 調査(vectorの原点からの)pixel位置 */
250 const long x_div, const long y_div, /* 調査pixelを分割する(サブpixel)数 */
251 const double valid_len /* vectorからの有効距離 */
252 ) {
253 int count = 0;
254 for (int yy = 0; yy < y_div; ++yy) {
255 for (int xx = 0; xx < x_div; ++xx) {
256 double xp = x_tgt + (double)xx / x_div - (0.5 - 0.5 / x_div);
257 double yp = y_tgt + (double)yy / y_div - (0.5 - 0.5 / y_div);
258 double len = 0.0;
259 double pos = 0.0;
260 vec_poi_to_len_pos_(xv, yv, xp, yp, len, pos);
261 if (len < valid_len) {
262 ++count;
263 }
264 }
265 }
266 return count;
267 }
268 /* リニア減衰計算 */
liner_decrement_(const double xv,const double yv,const double x_tgt,const double y_tgt,const long x_div,const long y_div,const double valid_len)269 double liner_decrement_(
270 const double xv, const double yv, /* vector */
271 const double x_tgt,
272 const double y_tgt, /* 調査(vectorの原点からの)pixel位置 */
273 const long x_div, const long y_div, /* 調査pixelを分割する(サブpixel)数 */
274 const double valid_len /* vectorからの有効距離 */
275 ) {
276 int count = 0;
277 double accum = 0.0;
278 const double line_len = sqrt(xv * xv + yv * yv) + valid_len;
279 for (int yy = 0; yy < y_div; ++yy) {
280 for (int xx = 0; xx < x_div; ++xx) {
281 double xp = x_tgt + (double)xx / x_div - (0.5 - 0.5 / x_div);
282 double yp = y_tgt + (double)yy / y_div - (0.5 - 0.5 / y_div);
283 double len = 0.0;
284 double pos = 0.0;
285 vec_poi_to_len_pos_(xv, yv, xp, yp, len, pos);
286 if (len < valid_len) {
287 ++count;
288 /* 下の式ではマイナスにはならない */
289 accum += 1.0 - fabs(pos) / line_len;
290 }
291 }
292 }
293 if (count <= 0) {
294 return 0.0;
295 } /* 念のためチェック */
296 return accum / (double)count;
297 }
298 /* ぶれ画像計算 */
bure_decrement_(const double xv,const double yv,const double x_tgt,const double y_tgt,const long x_div,const long y_div,const double valid_len,const int zanzo_length)299 double bure_decrement_(
300 const double xv, const double yv, /* vector */
301 const double x_tgt,
302 const double y_tgt, /* 調査(vectorの原点からの)pixel位置 */
303 const long x_div, const long y_div, /* 調査pixelを分割する(サブpixel)数 */
304 const double valid_len, /* vectorからの有効距離 */
305 const int zanzo_length) {
306 long count_in = 0;
307 long count_out = 0;
308 double pos = 0.0;
309 for (int yy = 0; yy < y_div; ++yy) {
310 for (int xx = 0; xx < x_div; ++xx) {
311 double xp = x_tgt + (double)xx / x_div - (0.5 - 0.5 / x_div);
312 double yp = y_tgt + (double)yy / y_div - (0.5 - 0.5 / y_div);
313 double len = 0.0;
314 pos = 0.0;
315 vec_poi_to_len_pos_(xv, yv, xp, yp, len, pos);
316 if (len < valid_len) {
317 if (0 == ((int)pos % zanzo_length)) {
318 ++count_in;
319 } else {
320 ++count_out;
321 }
322 }
323 }
324 }
325
326 /* 有効距離内にない場合ゼロを返す。念のためチェック */
327 if ((count_in + count_out) <= 0) {
328 return 0.0;
329 }
330
331 /* 距離で計算するのでマイナス位置では意味がない */
332 if (pos < 0.0) {
333 pos = -pos;
334 }
335
336 /*
337 pos が line_len より大きい場合がある。
338 そのため、pos / line_lenが、1より大きくなり、
339 それゆえ、1.0 - pos / line_lenが、マイナスとなる。
340 マイナスを返してはいけないのでそのための処理
341 */
342 const double line_len = sqrt(xv * xv + yv * yv) + valid_len;
343 if (line_len < pos) {
344 pos = line_len;
345 }
346
347 /* ????????????????? */
348 return (double)count_in / (count_in + count_out) * (1.0 - pos / line_len);
349 }
350 }
351
352 namespace {
set_smooth_(const double x_vector,const double y_vector,const double vector_scale,const double curve,const int zanzo_length,const double zanzo_power,std::vector<double> & ratio_array,std::vector<int> & x_array,std::vector<int> & y_array)353 void set_smooth_(const double x_vector, const double y_vector,
354 const double vector_scale, const double curve,
355 const int zanzo_length, const double zanzo_power,
356 std::vector<double> &ratio_array, std::vector<int> &x_array,
357 std::vector<int> &y_array) {
358 /* blur効果なしならなにもしない */
359 if (curve <= 0.0) {
360 return;
361 }
362
363 /* ベクトルの実の長さ */
364 double xv = x_vector * vector_scale;
365 double yv = y_vector * vector_scale;
366
367 /* vectorの長さがゼロならなにもしない */
368 if ((0.0 == xv) && (0.0 == yv)) {
369 return;
370 }
371
372 /* vectorの始点と終点のpixel位置 */
373 int x1, y1, x2, y2;
374 if (0.0 <= xv) {
375 x1 = 0;
376 x2 = (int)xv + 2;
377 } else {
378 x1 = (int)xv - 2;
379 x2 = 0;
380 }
381 if (0.0 <= yv) {
382 y1 = 0;
383 y2 = (int)yv + 2;
384 } else {
385 y1 = (int)yv - 2;
386 y2 = 0;
387 }
388
389 /* smooth線にかかるsubpixel数をカウント */
390 int size = 0;
391 for (int yy = y1; yy <= y2; ++yy) {
392 for (int xx = x1; xx <= x2; ++xx) {
393 if (0 <
394 count_nearly_vector_(xv, yv, (double)xx, (double)yy, 16, 16, 0.5)) {
395 ++size;
396 }
397 }
398 }
399
400 /* カウント0以下では、blur効果がない */
401 if (size <= 0) {
402 return;
403 }
404
405 /* バッファメモリ確保 */
406 ratio_array.resize(size);
407 x_array.resize(size);
408 y_array.resize(size);
409
410 /* 位置とピクセル値(0<val<=1)を格納 */
411 int ii = 0;
412 for (int yy = y1; yy <= y2; ++yy) {
413 for (int xx = x1; xx <= x2; ++xx) {
414 const int count =
415 count_nearly_vector_(xv, yv, (double)xx, (double)yy, 16, 16, 0.5);
416 if (0 < count) {
417 ratio_array.at(ii) = (double)count / (16 * 16);
418 x_array.at(ii) = xx;
419 y_array.at(ii) = yy;
420 ++ii;
421 }
422 }
423 }
424
425 /* リニア減衰効果 */
426 for (unsigned int ii = 0; ii < ratio_array.size(); ++ii) {
427 ratio_array.at(ii) *=
428 liner_decrement_(xv, yv, (double)(x_array.at(ii)),
429 (double)(y_array.at(ii)), 16, 16, 0.5);
430 }
431
432 /* 段々の分割指定があれば設定する */
433 if (0 < zanzo_length) {
434 /* ぶれ残像減衰効果 */
435 for (unsigned int ii = 0; ii < ratio_array.size(); ++ii) {
436 ratio_array.at(ii) =
437 (1.0 - zanzo_power) * ratio_array.at(ii) +
438 zanzo_power * bure_decrement_(xv, yv, (double)(x_array.at(ii)),
439 (double)(y_array.at(ii)), 16, 16, 0.5,
440 zanzo_length);
441 }
442 }
443
444 /* vector始点は1とする */
445 for (unsigned int ii = 0; ii < ratio_array.size(); ++ii) {
446 if ((0 == x_array.at(ii)) && (0 == y_array.at(ii))) {
447 ratio_array.at(ii) = 1.0;
448 break;
449 }
450 }
451
452 /* ガンマ強弱計算 */
453 if (1.0 != curve) { /* 0.0以下の値のとき既にreturnしてる */
454 for (unsigned int ii = 0; ii < ratio_array.size(); ++ii) {
455 ratio_array.at(ii) = pow(ratio_array.at(ii), 1.0 / curve);
456 }
457 }
458 /* 正規化 */
459 double d_accum = 0.0;
460 for (unsigned int ii = 0; ii < ratio_array.size(); ++ii) {
461 d_accum += ratio_array.at(ii);
462 }
463 for (unsigned int ii = 0; ii < ratio_array.size(); ++ii) {
464 ratio_array.at(ii) /= d_accum;
465 }
466 }
467 }
468
469 namespace {
470 template <class T>
pixel_value(const T * image_array,const int height,const int width,const int channels,const int xx,const int yy,const int zz,const std::vector<double> & ratio_array,const std::vector<int> & x_array,const std::vector<int> & y_array)471 T pixel_value(const T *image_array, const int height, const int width,
472 const int channels, const int xx, const int yy, const int zz,
473 const std::vector<double> &ratio_array,
474 const std::vector<int> &x_array,
475 const std::vector<int> &y_array) {
476 double ratio_accum = 0.0;
477 double accum = 0.0;
478 for (unsigned int ii = 0; ii < ratio_array.size(); ++ii) {
479 const int xp = xx + x_array.at(ii);
480 const int yp = yy + y_array.at(ii);
481
482 if (xp < 0) {
483 continue;
484 }
485 if (yp < 0) {
486 continue;
487 }
488 if (width <= xp) {
489 continue;
490 }
491 if (height <= yp) {
492 continue;
493 }
494
495 ratio_accum += ratio_array.at(ii);
496 accum += ratio_array.at(ii) *
497 static_cast<double>(
498 *(image_array + channels * width * yp + channels * xp + zz));
499 }
500
501 /* can not calculate */
502 if (0.0 == ratio_accum) {
503 return 0;
504 }
505
506 /* overflowはありえない(ratio_arrayを正規化してあるため) */
507 /*if ((accum/ratio_accum) <= 0.0) { return 0; }
508 if ((USHORT)0xffff <= (USHORT)(accum/ratio_accum)) {
509 return (unsigned short)0xffff;
510 }*/
511
512 return static_cast<T>(accum / ratio_accum + 0.5);
513 }
514 template <class T>
convert_template_(const T * in,T * image_out,const int hh,const int ww,const int cc,const std::vector<double> & ra,const std::vector<int> & xa,const std::vector<int> & ya,const bool alpha_rend_sw)515 void convert_template_(const T *in, T *image_out, const int hh, const int ww,
516 const int cc, const std::vector<double> &ra,
517 const std::vector<int> &xa, const std::vector<int> &ya,
518 const bool alpha_rend_sw) {
519 /* 効果なしならimageをcopyして終る */
520 if (ra.size() <= 0) {
521 memmove(image_out, in, hh * ww * cc * sizeof(T));
522 return;
523 }
524
525 if (igs::image::rgba::siz == cc) { /* Alphaがある */
526 using namespace igs::image::rgba;
527 if (alpha_rend_sw) { /* Alphaも処理する */
528 const T *p_in = in;
529 T *pout = image_out;
530 for (int yy = 0; yy < hh; ++yy) {
531 for (int xx = 0; xx < ww; ++xx, p_in += cc, pout += cc) {
532 /*Alpha処理-->*/ pout[alp] =
533 pixel_value(in, hh, ww, cc, xx, yy, alp, ra, xa, ya);
534 if (0 == pout[alp]) { /* AlphaがゼロならRGB処理しない */
535 pout[red] = p_in[red];
536 pout[gre] = p_in[gre];
537 pout[blu] = p_in[blu];
538 } else { /* AlphaがゼロでないときRGB処理する */
539 pout[red] = pixel_value(in, hh, ww, cc, xx, yy, red, ra, xa, ya);
540 pout[gre] = pixel_value(in, hh, ww, cc, xx, yy, gre, ra, xa, ya);
541 pout[blu] = pixel_value(in, hh, ww, cc, xx, yy, blu, ra, xa, ya);
542 }
543 }
544 }
545 } else { /* Alpha処理せず保存のみ */
546 const T *p_in = in;
547 T *pout = image_out;
548 const unsigned int val_max = std::numeric_limits<T>::max();
549 for (int yy = 0; yy < hh; ++yy) {
550 for (int xx = 0; xx < ww; ++xx, p_in += cc, pout += cc) {
551 /*Alpha保存-->*/ pout[alp] = p_in[alp];
552 if (0 == pout[alp]) { /* AlphaがゼロならRGB処理しない */
553 pout[red] = p_in[red];
554 pout[gre] = p_in[gre];
555 pout[blu] = p_in[blu];
556 } else { /* AlphaがゼロでないときRGB処理する */
557 pout[red] = pixel_value(in, hh, ww, cc, xx, yy, red, ra, xa, ya);
558 pout[gre] = pixel_value(in, hh, ww, cc, xx, yy, gre, ra, xa, ya);
559 pout[blu] = pixel_value(in, hh, ww, cc, xx, yy, blu, ra, xa, ya);
560 /* Alphaが0より大きくMaxより小さいとき増分をMaskする */
561 if (p_in[alp] < val_max) {
562 const unsigned int aa = static_cast<unsigned int>(p_in[alp]);
563 if (p_in[red] < pout[red]) { /* 増分のみMask! */
564 const unsigned int dif =
565 static_cast<unsigned int>(pout[red] - p_in[red]);
566 pout[red] = static_cast<T>(p_in[red] + dif * aa / val_max);
567 }
568 if (p_in[gre] < pout[gre]) { /* 増分のみMask! */
569 const unsigned int dif =
570 static_cast<unsigned int>(pout[gre] - p_in[gre]);
571 pout[gre] = static_cast<T>(p_in[gre] + dif * aa / val_max);
572 }
573 if (p_in[blu] < pout[blu]) { /* 増分のみMask! */
574 const unsigned int dif =
575 static_cast<unsigned int>(pout[blu] - p_in[blu]);
576 pout[blu] = static_cast<T>(p_in[blu] + dif * aa / val_max);
577 }
578 }
579 }
580 }
581 }
582 }
583 } else { /* Alphaがない, RGB/Grayscale... */
584 T *pout = image_out;
585 for (int yy = 0; yy < hh; ++yy) {
586 for (int xx = 0; xx < ww; ++xx, pout += cc) {
587 for (int zz = 0; zz < cc; ++zz) {
588 pout[zz] = pixel_value(in, hh, ww, cc, xx, yy, zz, ra, xa, ya);
589 }
590 }
591 }
592 }
593 }
594 }
convert(const unsigned char * image_in,unsigned char * image_out,const int height,const int width,const int channels,const int bits,const double x_vector,const double y_vector,const double vector_scale,const double curve,const int zanzo_length,const double zanzo_power,const bool alpha_rend_sw)595 void igs::motion_blur::convert(const unsigned char *image_in,
596 unsigned char *image_out,
597
598 const int height, const int width,
599 const int channels, const int bits,
600
601 const double x_vector, const double y_vector,
602 const double vector_scale, const double curve,
603 const int zanzo_length, const double zanzo_power,
604 const bool alpha_rend_sw) {
605 std::vector<double> ratio_array;
606 std::vector<int> x_array;
607 std::vector<int> y_array;
608
609 set_smooth_(x_vector, y_vector, vector_scale, curve, zanzo_length,
610 zanzo_power, ratio_array, x_array, y_array);
611 /***set_jaggy_(
612 x_vector, y_vector, vector_scale, curve,
613 ratio_array, x_array, y_array
614 );***/
615
616 if (std::numeric_limits<unsigned char>::digits == bits) {
617 convert_template_(image_in, image_out, height, width, channels, ratio_array,
618 x_array, y_array, alpha_rend_sw);
619 y_array.clear();
620 x_array.clear();
621 ratio_array.clear();
622 } else if (std::numeric_limits<unsigned short>::digits == bits) {
623 convert_template_(reinterpret_cast<const unsigned short *>(image_in),
624 reinterpret_cast<unsigned short *>(image_out), height,
625 width, channels, ratio_array, x_array, y_array,
626 alpha_rend_sw);
627 y_array.clear();
628 x_array.clear();
629 ratio_array.clear();
630 } else {
631 throw std::domain_error("Bad bits,Not uchar/ushort");
632 }
633 }
634