r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / blur / blur.C
blob9ed5d05a12d3db02d9eec6df74e1335410cdd4e3
1 #include "filexml.h"
2 #include "blur.h"
3 #include "blurwindow.h"
4 #include "defaults.h"
5 #include "keyframe.h"
6 #include "picon_png.h"
7 #include "vframe.h"
9 #include <math.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <libintl.h>
13 #define _(String) gettext(String)
14 #define gettext_noop(String) String
15 #define N_(String) gettext_noop (String)
23 BlurConfig::BlurConfig()
25         vertical = 1;
26         horizontal = 1;
27         radius = 5;
28         a = r = g = b = 1;
31 int BlurConfig::equivalent(BlurConfig &that)
33         return (vertical == that.vertical && 
34                 horizontal == that.horizontal && 
35                 radius == that.radius &&
36                 a == that.a &&
37                 r == that.r &&
38                 g == that.g &&
39                 b == that.b);
42 void BlurConfig::copy_from(BlurConfig &that)
44         vertical = that.vertical;
45         horizontal = that.horizontal;
46         radius = that.radius;
47         a = that.a;
48         r = that.r;
49         g = that.g;
50         b = that.b;
53 void BlurConfig::interpolate(BlurConfig &prev, 
54         BlurConfig &next, 
55         int64_t prev_frame, 
56         int64_t next_frame, 
57         int64_t current_frame)
59         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
60         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
63 //printf("BlurConfig::interpolate %d %d %d\n", prev_frame, next_frame, current_frame);
64         this->vertical = (int)(prev.vertical * prev_scale + next.vertical * next_scale);
65         this->horizontal = (int)(prev.horizontal * prev_scale + next.horizontal * next_scale);
66         this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale);
67         a = prev.a;
68         r = prev.r;
69         g = prev.g;
70         b = prev.b;
78 REGISTER_PLUGIN(BlurMain)
87 BlurMain::BlurMain(PluginServer *server)
88  : PluginVClient(server)
90         defaults = 0;
91         temp = 0;
92         need_reconfigure = 1;
93         engine = 0;
94         PLUGIN_CONSTRUCTOR_MACRO
97 BlurMain::~BlurMain()
99 //printf("BlurMain::~BlurMain 1\n");
100         PLUGIN_DESTRUCTOR_MACRO
102         if(temp) delete temp;
103         if(engine)
104         {
105                 for(int i = 0; i < (PluginClient::smp + 1); i++)
106                         delete engine[i];
107                 delete [] engine;
108         }
111 char* BlurMain::plugin_title() { return _("Blur"); }
112 int BlurMain::is_realtime() { return 1; }
115 NEW_PICON_MACRO(BlurMain)
117 SHOW_GUI_MACRO(BlurMain, BlurThread)
119 SET_STRING_MACRO(BlurMain)
121 RAISE_WINDOW_MACRO(BlurMain)
123 LOAD_CONFIGURATION_MACRO(BlurMain, BlurConfig)
128 int BlurMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
130         int i, j, k, l;
131         unsigned char **input_rows, **output_rows;
133         this->input = input_ptr;
134         this->output = output_ptr;
135         need_reconfigure |= load_configuration();
138 //printf("BlurMain::process_realtime 1 %d %d\n", need_reconfigure, config.radius);
139         if(need_reconfigure)
140         {
141                 int y1, y2, y_increment;
143                 if(!engine)
144                 {
145                         y_increment = input->get_h() / (smp + 1);
146                         y1 = 0;
148                         engine = new BlurEngine*[(PluginClient::smp + 1)];
149                         for(int i = 0; i < (PluginClient::smp + 1); i++)
150                         {
151                                 y2 = y1 + y_increment;
152                                 if(i == (PluginClient::smp + 1) - 1 && 
153                                         y2 < input->get_h() - 1) 
154                                         y2 = input->get_h() - 1;
156                                 engine[i] = new BlurEngine(this, y1, y2);
157                                 engine[i]->start();
158                                 y1 += y_increment;
159                         }
160                 }
162                 for(i = 0; i < (PluginClient::smp + 1); i++)
163                         engine[i]->reconfigure();
164                 need_reconfigure = 0;
165         }
168         if(temp && 
169                 (temp->get_w() != input_ptr->get_w() ||
170                 temp->get_h() != input_ptr->get_h()))
171         {
172                 delete temp;
173                 temp = 0;
174         }
176         if(!temp)
177                 temp = new VFrame(0,
178                         input_ptr->get_w(),
179                         input_ptr->get_h(),
180                         input_ptr->get_color_model());
182         input_rows = input_ptr->get_rows();
183         output_rows = output_ptr->get_rows();
185         if(config.radius < 2 || 
186                 (!config.vertical && !config.horizontal))
187         {
188 // Data never processed so copy if necessary
189 //printf("BlurMain::process_realtime 2 %d\n", radius);
190                 if(input_rows[0] != output_rows[0])
191                 {
192                         output_ptr->copy_from(input_ptr);
193                 }
194         }
195         else
196         {
197 // Process blur
198 // TODO
199 // Can't blur recursively.  Need to blur to a temp and 
200 // horizontally to the output in 2 discrete passes.
201 //printf("BlurMain::process_realtime 3 %d\n", (smp + 1));
202                 for(i = 0; i < (smp + 1); i++)
203                 {
204                         engine[i]->start_process_frame(output_ptr, input_ptr);
205                 }
207                 for(i = 0; i < (smp + 1); i++)
208                 {
209                         engine[i]->wait_process_frame();
210                 }
211         }
213         return 0;
217 void BlurMain::update_gui()
219         if(thread)
220         {
221                 load_configuration();
222                 thread->window->lock_window();
223                 thread->window->horizontal->update(config.horizontal);
224                 thread->window->vertical->update(config.vertical);
225                 thread->window->radius->update(config.radius);
226                 thread->window->a->update(config.a);
227                 thread->window->r->update(config.r);
228                 thread->window->g->update(config.g);
229                 thread->window->b->update(config.b);
230                 thread->window->unlock_window();
231         }
235 int BlurMain::load_defaults()
237         char directory[1024], string[1024];
238 // set the default directory
239         sprintf(directory, "%sblur.rc", BCASTDIR);
241 // load the defaults
242         defaults = new Defaults(directory);
243         defaults->load();
245         config.vertical = defaults->get("VERTICAL", config.vertical);
246         config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
247         config.radius = defaults->get("RADIUS", config.radius);
248         config.r = defaults->get("R", config.r);
249         config.g = defaults->get("G", config.g);
250         config.b = defaults->get("B", config.b);
251         config.a = defaults->get("A", config.a);
252         return 0;
256 int BlurMain::save_defaults()
258         defaults->update("VERTICAL", config.vertical);
259         defaults->update("HORIZONTAL", config.horizontal);
260         defaults->update("RADIUS", config.radius);
261         defaults->update("R", config.r);
262         defaults->update("G", config.g);
263         defaults->update("B", config.b);
264         defaults->update("A", config.a);
265         defaults->save();
266         return 0;
271 void BlurMain::save_data(KeyFrame *keyframe)
273         FileXML output;
275 // cause data to be stored directly in text
276         output.set_shared_string(keyframe->data, MESSAGESIZE);
277         output.tag.set_title("BLUR");
278         output.tag.set_property("VERTICAL", config.vertical);
279         output.tag.set_property("HORIZONTAL", config.horizontal);
280         output.tag.set_property("RADIUS", config.radius);
281         output.tag.set_property("R", config.r);
282         output.tag.set_property("G", config.g);
283         output.tag.set_property("B", config.b);
284         output.tag.set_property("A", config.a);
285         output.append_tag();
286         output.terminate_string();
289 void BlurMain::read_data(KeyFrame *keyframe)
291         FileXML input;
293         input.set_shared_string(keyframe->data, strlen(keyframe->data));
295         int result = 0;
297         while(!result)
298         {
299                 result = input.read_tag();
301                 if(!result)
302                 {
303                         if(input.tag.title_is("BLUR"))
304                         {
305                                 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
306                                 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
307                                 config.radius = input.tag.get_property("RADIUS", config.radius);
308 //printf("BlurMain::read_data 1 %d %d %s\n", get_source_position(), keyframe->position, keyframe->data);
309                                 config.r = input.tag.get_property("R", config.r);
310                                 config.g = input.tag.get_property("G", config.g);
311                                 config.b = input.tag.get_property("B", config.b);
312                                 config.a = input.tag.get_property("A", config.a);
313                         }
314                 }
315         }
326 BlurEngine::BlurEngine(BlurMain *plugin, int start_out, int end_out)
327  : Thread()
329         int size = plugin->input->get_w() > plugin->input->get_h() ? 
330                 plugin->input->get_w() : plugin->input->get_h();
331         this->plugin = plugin;
332         this->start_out = start_out;
333         this->end_out = end_out;
334         last_frame = 0;
335         val_p = new pixel_f[size];
336         val_m = new pixel_f[size];
337         src = new pixel_f[size];
338         dst = new pixel_f[size];
339         set_synchronous(1);
340         input_lock.lock();
341         output_lock.lock();
344 BlurEngine::~BlurEngine()
346         last_frame = 1;
347         input_lock.unlock();
348         join();
351 int BlurEngine::start_process_frame(VFrame *output, VFrame *input)
353         this->output = output;
354         this->input = input;
355         input_lock.unlock();
356         return 0;
359 int BlurEngine::wait_process_frame()
361         output_lock.lock();
362         return 0;
365 void BlurEngine::run()
367         int i, j, k, l;
368         int strip_size;
370         while(1)
371         {
372                 input_lock.lock();
373                 if(last_frame)
374                 {
375                         output_lock.unlock();
376                         return;
377                 }
379                 start_in = start_out - plugin->config.radius;
380                 end_in = end_out + plugin->config.radius;
381                 if(start_in < 0) start_in = 0;
382                 if(end_in > plugin->input->get_h()) end_in = plugin->input->get_h();
383                 strip_size = end_in - start_in;
384                 color_model = input->get_color_model();
385                 int w = input->get_w();
386                 int h = input->get_h();
392 #define BLUR(type, max, components) \
393 { \
394         type **input_rows = (type **)input->get_rows(); \
395         type **output_rows = (type **)output->get_rows(); \
396         type **current_input = input_rows; \
397         type **current_output = output_rows; \
398         vmax = max; \
400         if(plugin->config.vertical) \
401         { \
402 /* Vertical pass */ \
403                 if(plugin->config.horizontal) \
404                 { \
405                         current_output = (type **)plugin->temp->get_rows(); \
406                 } \
408                 for(j = 0; j < w; j++) \
409                 { \
410                         bzero(val_p, sizeof(pixel_f) * (end_in - start_in)); \
411                         bzero(val_m, sizeof(pixel_f) * (end_in - start_in)); \
413                         for(l = 0, k = start_in; k < end_in; l++, k++) \
414                         { \
415                                 if(plugin->config.r) src[l].r = (float)current_input[k][j * components]; \
416                                 if(plugin->config.g) src[l].g = (float)current_input[k][j * components + 1]; \
417                                 if(plugin->config.b) src[l].b = (float)current_input[k][j * components + 2]; \
418                                 if(components == 4) \
419                                         if(plugin->config.a) src[l].a = (float)current_input[k][j * components + 3]; \
420                         } \
422                         if(components == 4) \
423                                 blur_strip4(strip_size); \
424                         else \
425                                 blur_strip3(strip_size); \
427                         for(l = start_out - start_in, k = start_out; k < end_out; l++, k++) \
428                         { \
429                                 if(plugin->config.r) current_output[k][j * components] = (type)dst[l].r; \
430                                 if(plugin->config.g) current_output[k][j * components + 1] = (type)dst[l].g; \
431                                 if(plugin->config.b) current_output[k][j * components + 2] = (type)dst[l].b; \
432                                 if(components == 4) \
433                                         if(plugin->config.a) current_output[k][j * components + 3] = (type)dst[l].a; \
434                         } \
435                 } \
437                 current_input = current_output; \
438                 current_output = output_rows; \
439         } \
442         if(plugin->config.horizontal) \
443         { \
444 /* Horizontal pass */ \
445                 for(j = start_out; j < end_out; j++) \
446                 { \
447                         bzero(val_p, sizeof(pixel_f) * w); \
448                         bzero(val_m, sizeof(pixel_f) * w); \
450                         for(k = 0; k < w; k++) \
451                         { \
452                                 if(plugin->config.r) src[k].r = (float)current_input[j][k * components]; \
453                                 if(plugin->config.g) src[k].g = (float)current_input[j][k * components + 1]; \
454                                 if(plugin->config.b) src[k].b = (float)current_input[j][k * components + 2]; \
455                                 if(components == 4) \
456                                         if(plugin->config.a) src[k].a = (float)current_input[j][k * components + 3]; \
457                         } \
459                         if(components == 4) \
460                                 blur_strip4(w); \
461                         else \
462                                 blur_strip3(w); \
464                         for(k = 0; k < w; k++) \
465                         { \
466                                 if(plugin->config.r) current_output[j][k * components] = (type)dst[k].r; \
467                                 if(plugin->config.g) current_output[j][k * components + 1] = (type)dst[k].g; \
468                                 if(plugin->config.b) current_output[j][k * components + 2] = (type)dst[k].b; \
469                                 if(components == 4) \
470                                         if(plugin->config.a) current_output[j][k * components + 3] = (type)dst[k].a; \
471                         } \
472                 } \
473         } \
478                 switch(color_model)
479                 {
480                         case BC_RGB888:
481                         case BC_YUV888:
482                                 BLUR(unsigned char, 0xff, 3);
483                                 break;
484                         case BC_RGBA8888:
485                         case BC_YUVA8888:
486                                 BLUR(unsigned char, 0xff, 4);
487                                 break;
488                         case BC_RGB161616:
489                         case BC_YUV161616:
490                                 BLUR(uint16_t, 0xffff, 3);
491                                 break;
492                         case BC_RGBA16161616:
493                         case BC_YUVA16161616:
494                                 BLUR(uint16_t, 0xffff, 4);
495                                 break;
496                 }
498                 output_lock.unlock();
499         }
502 int BlurEngine::reconfigure()
504         std_dev = sqrt(-(double)(plugin->config.radius * plugin->config.radius) / 
505                 (2 * log (1.0 / 255.0)));
506         get_constants();
509 int BlurEngine::get_constants()
511         int i;
512         double constants[8];
513         double div;
515         div = sqrt(2 * M_PI) * std_dev;
516         constants[0] = -1.783 / std_dev;
517         constants[1] = -1.723 / std_dev;
518         constants[2] = 0.6318 / std_dev;
519         constants[3] = 1.997  / std_dev;
520         constants[4] = 1.6803 / div;
521         constants[5] = 3.735 / div;
522         constants[6] = -0.6803 / div;
523         constants[7] = -0.2598 / div;
525         n_p[0] = constants[4] + constants[6];
526         n_p[1] = exp(constants[1]) *
527                                 (constants[7] * sin(constants[3]) -
528                                 (constants[6] + 2 * constants[4]) * cos(constants[3])) +
529                                 exp(constants[0]) *
530                                 (constants[5] * sin(constants[2]) -
531                                 (2 * constants[6] + constants[4]) * cos(constants[2]));
533         n_p[2] = 2 * exp(constants[0] + constants[1]) *
534                                 ((constants[4] + constants[6]) * cos(constants[3]) * 
535                                 cos(constants[2]) - constants[5] * 
536                                 cos(constants[3]) * sin(constants[2]) -
537                                 constants[7] * cos(constants[2]) * sin(constants[3])) +
538                                 constants[6] * exp(2 * constants[0]) +
539                                 constants[4] * exp(2 * constants[1]);
541         n_p[3] = exp(constants[1] + 2 * constants[0]) *
542                                 (constants[7] * sin(constants[3]) - 
543                                 constants[6] * cos(constants[3])) +
544                                 exp(constants[0] + 2 * constants[1]) *
545                                 (constants[5] * sin(constants[2]) - constants[4] * 
546                                 cos(constants[2]));
547         n_p[4] = 0.0;
549         d_p[0] = 0.0;
550         d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) -
551                                 2 * exp(constants[0]) * cos(constants[2]);
553         d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) * 
554                                 exp(constants[0] + constants[1]) +
555                                 exp(2 * constants[1]) + exp (2 * constants[0]);
557         d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) -
558                                 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]);
560         d_p[4] = exp(2 * constants[0] + 2 * constants[1]);
562         for(i = 0; i < 5; i++) d_m[i] = d_p[i];
564         n_m[0] = 0.0;
565         for(i = 1; i <= 4; i++)
566                 n_m[i] = n_p[i] - d_p[i] * n_p[0];
568         double sum_n_p, sum_n_m, sum_d;
569         double a, b;
571         sum_n_p = 0.0;
572         sum_n_m = 0.0;
573         sum_d = 0.0;
574         for(i = 0; i < 5; i++)
575         {
576                 sum_n_p += n_p[i];
577                 sum_n_m += n_m[i];
578                 sum_d += d_p[i];
579         }
581         a = sum_n_p / (1 + sum_d);
582         b = sum_n_m / (1 + sum_d);
584         for (i = 0; i < 5; i++)
585         {
586                 bd_p[i] = d_p[i] * a;
587                 bd_m[i] = d_m[i] * b;
588         }
589         return 0;
592 #define BOUNDARY(x) if((x) > vmax) (x) = vmax; else if((x) < 0) (x) = 0;
594 int BlurEngine::transfer_pixels(pixel_f *src1, pixel_f *src2, pixel_f *dest, int size)
596         int i;
597         float sum;
599 // printf("BlurEngine::transfer_pixels %d %d %d %d\n", 
600 // plugin->config.r, 
601 // plugin->config.g, 
602 // plugin->config.b, 
603 // plugin->config.a);
605         for(i = 0; i < size; i++)
606     {
607                 sum = src1[i].r + src2[i].r;
608                 BOUNDARY(sum);
609                 dest[i].r = sum;
610                 sum = src1[i].g + src2[i].g;
611                 BOUNDARY(sum);
612                 dest[i].g = sum;
613                 sum = src1[i].b + src2[i].b;
614                 BOUNDARY(sum);
615                 dest[i].b = sum;
616                 sum = src1[i].a + src2[i].a;
617                 BOUNDARY(sum);
618                 dest[i].a = sum;
619     }
620         return 0;
624 int BlurEngine::multiply_alpha(pixel_f *row, int size)
626         register int i;
627         register float alpha;
629 //      for(i = 0; i < size; i++)
630 //      {
631 //              alpha = (float)row[i].a / vmax;
632 //              row[i].r *= alpha;
633 //              row[i].g *= alpha;
634 //              row[i].b *= alpha;
635 //      }
636         return 0;
639 int BlurEngine::separate_alpha(pixel_f *row, int size)
641         register int i;
642         register float alpha;
643         register float result;
644         
645 //      for(i = 0; i < size; i++)
646 //      {
647 //              if(row[i].a > 0 && row[i].a < vmax)
648 //              {
649 //                      alpha = (float)row[i].a / vmax;
650 //                      result = (float)row[i].r / alpha;
651 //                      row[i].r = (result > vmax ? vmax : result);
652 //                      result = (float)row[i].g / alpha;
653 //                      row[i].g = (result > vmax ? vmax : result);
654 //                      result = (float)row[i].b / alpha;
655 //                      row[i].b = (result > vmax ? vmax : result);
656 //              }
657 //      }
658         return 0;
661 int BlurEngine::blur_strip3(int &size)
663         multiply_alpha(src, size);
665         sp_p = src;
666         sp_m = src + size - 1;
667         vp = val_p;
668         vm = val_m + size - 1;
670         initial_p = sp_p[0];
671         initial_m = sp_m[0];
673         int l;
674         for(int k = 0; k < size; k++)
675         {
676                 terms = (k < 4) ? k : 4;
677                 for(l = 0; l <= terms; l++)
678                 {
679                         if(plugin->config.r)
680                         {
681                                 vp->r += n_p[l] * sp_p[-l].r - d_p[l] * vp[-l].r;
682                                 vm->r += n_m[l] * sp_m[l].r - d_m[l] * vm[l].r;
683                         }
684                         if(plugin->config.g)
685                         {
686                                 vp->g += n_p[l] * sp_p[-l].g - d_p[l] * vp[-l].g;
687                                 vm->g += n_m[l] * sp_m[l].g - d_m[l] * vm[l].g;
688                         }
689                         if(plugin->config.b)
690                         {
691                                 vp->b += n_p[l] * sp_p[-l].b - d_p[l] * vp[-l].b;
692                                 vm->b += n_m[l] * sp_m[l].b - d_m[l] * vm[l].b;
693                         }
694                 }
695                 for( ; l <= 4; l++)
696                 {
697                         if(plugin->config.r)
698                         {
699                                 vp->r += (n_p[l] - bd_p[l]) * initial_p.r;
700                                 vm->r += (n_m[l] - bd_m[l]) * initial_m.r;
701                         }
702                         if(plugin->config.g)
703                         {
704                                 vp->g += (n_p[l] - bd_p[l]) * initial_p.g;
705                                 vm->g += (n_m[l] - bd_m[l]) * initial_m.g;
706                         }
707                         if(plugin->config.b)
708                         {
709                                 vp->b += (n_p[l] - bd_p[l]) * initial_p.b;
710                                 vm->b += (n_m[l] - bd_m[l]) * initial_m.b;
711                         }
712                 }
713                 sp_p++;
714                 sp_m--;
715                 vp++;
716                 vm--;
717         }
718         transfer_pixels(val_p, val_m, dst, size);
719         separate_alpha(dst, size);
720         return 0;
724 int BlurEngine::blur_strip4(int &size)
726         multiply_alpha(src, size);
728         sp_p = src;
729         sp_m = src + size - 1;
730         vp = val_p;
731         vm = val_m + size - 1;
733         initial_p = sp_p[0];
734         initial_m = sp_m[0];
736         int l;
737         for(int k = 0; k < size; k++)
738         {
739                 terms = (k < 4) ? k : 4;
741                 for(l = 0; l <= terms; l++)
742                 {
743                         if(plugin->config.r)
744                         {
745                                 vp->r += n_p[l] * sp_p[-l].r - d_p[l] * vp[-l].r;
746                                 vm->r += n_m[l] * sp_m[l].r - d_m[l] * vm[l].r;
747                         }
748                         if(plugin->config.g)
749                         {
750                                 vp->g += n_p[l] * sp_p[-l].g - d_p[l] * vp[-l].g;
751                                 vm->g += n_m[l] * sp_m[l].g - d_m[l] * vm[l].g;
752                         }
753                         if(plugin->config.b)
754                         {
755                                 vp->b += n_p[l] * sp_p[-l].b - d_p[l] * vp[-l].b;
756                                 vm->b += n_m[l] * sp_m[l].b - d_m[l] * vm[l].b;
757                         }
758                         if(plugin->config.a)
759                         {
760                                 vp->a += n_p[l] * sp_p[-l].a - d_p[l] * vp[-l].a;
761                                 vm->a += n_m[l] * sp_m[l].a - d_m[l] * vm[l].a;
762                         }
763                 }
765                 for( ; l <= 4; l++)
766                 {
767                         if(plugin->config.r)
768                         {
769                                 vp->r += (n_p[l] - bd_p[l]) * initial_p.r;
770                                 vm->r += (n_m[l] - bd_m[l]) * initial_m.r;
771                         }
772                         if(plugin->config.g)
773                         {
774                                 vp->g += (n_p[l] - bd_p[l]) * initial_p.g;
775                                 vm->g += (n_m[l] - bd_m[l]) * initial_m.g;
776                         }
777                         if(plugin->config.b)
778                         {
779                                 vp->b += (n_p[l] - bd_p[l]) * initial_p.b;
780                                 vm->b += (n_m[l] - bd_m[l]) * initial_m.b;
781                         }
782                         if(plugin->config.a)
783                         {
784                                 vp->a += (n_p[l] - bd_p[l]) * initial_p.a;
785                                 vm->a += (n_m[l] - bd_m[l]) * initial_m.a;
786                         }
787                 }
789                 sp_p++;
790                 sp_m--;
791                 vp++;
792                 vm--;
793         }
794         transfer_pixels(val_p, val_m, dst, size);
795         separate_alpha(dst, size);
796         return 0;