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