@@ -74,179 +74,96 @@ std::shared_ptr<Frame> Blur::GetFrame(std::shared_ptr<Frame> frame, int64_t fram
7474 float sigma_value = sigma.GetValue (frame_number);
7575 int iteration_value = iterations.GetInt (frame_number);
7676
77+ int w = frame_image->width ();
78+ int h = frame_image->height ();
7779
78- // Declare arrays for each color channel
79- unsigned char *red = new unsigned char [frame_image->width () * frame_image->height ()]();
80- unsigned char *green = new unsigned char [frame_image->width () * frame_image->height ()]();
81- unsigned char *blue = new unsigned char [frame_image->width () * frame_image->height ()]();
82- unsigned char *alpha = new unsigned char [frame_image->width () * frame_image->height ()]();
83- // Create empty target RGBA arrays (for the results of our blur)
84- unsigned char *blur_red = new unsigned char [frame_image->width () * frame_image->height ()]();
85- unsigned char *blur_green = new unsigned char [frame_image->width () * frame_image->height ()]();
86- unsigned char *blur_blue = new unsigned char [frame_image->width () * frame_image->height ()]();
87- unsigned char *blur_alpha = new unsigned char [frame_image->width () * frame_image->height ()]();
88-
89- // Loop through pixels and split RGBA channels into separate arrays
90- unsigned char *pixels = (unsigned char *) frame_image->bits ();
91- for (int pixel = 0 , byte_index=0 ; pixel < frame_image->width () * frame_image->height (); pixel++, byte_index+=4 )
92- {
93- // Get the RGBA values from each pixel
94- unsigned char R = pixels[byte_index];
95- unsigned char G = pixels[byte_index + 1 ];
96- unsigned char B = pixels[byte_index + 2 ];
97- unsigned char A = pixels[byte_index + 3 ];
98-
99- // Split channels into their own arrays
100- red[pixel] = R;
101- green[pixel] = G;
102- blue[pixel] = B;
103- alpha[pixel] = A;
104- }
105-
106- // Init target RGBA arrays
107- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) blur_red[i] = red[i];
108- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) blur_green[i] = green[i];
109- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) blur_blue[i] = blue[i];
110- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) blur_alpha[i] = alpha[i];
80+ // Grab two copies of the image pixel data
81+ QImage image_copy = frame_image->copy ();
82+ std::shared_ptr<QImage> frame_image_2 = std::make_shared<QImage>(image_copy);
11183
11284 // Loop through each iteration
113- for (int iteration = 0 ; iteration < iteration_value; iteration++ )
85+ for (int iteration = 0 ; iteration < iteration_value; ++iteration )
11486 {
11587 // HORIZONTAL BLUR (if any)
11688 if (horizontal_radius_value > 0.0 ) {
117- // Init boxes for computing blur
118- int *bxs = initBoxes (sigma_value, horizontal_radius_value);
119-
12089 // Apply horizontal blur to target RGBA channels
121- boxBlurH (red, blur_red, frame_image->width (), frame_image->height (), horizontal_radius_value);
122- boxBlurH (green, blur_green, frame_image->width (), frame_image->height (), horizontal_radius_value);
123- boxBlurH (blue, blur_blue, frame_image->width (), frame_image->height (), horizontal_radius_value);
124- boxBlurH (alpha, blur_alpha, frame_image->width (), frame_image->height (), horizontal_radius_value);
125-
126- // Remove boxes
127- delete[] bxs;
128-
129- // Copy blur_<chan> back to <chan> for vertical blur or next iteration
130- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) red[i] = blur_red[i];
131- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) green[i] = blur_green[i];
132- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) blue[i] = blur_blue[i];
133- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) alpha[i] = blur_alpha[i];
90+ boxBlurH (frame_image->bits (), frame_image_2->bits (), w, h, horizontal_radius_value);
91+
92+ // Swap output image back to input
93+ frame_image.swap (frame_image_2);
13494 }
13595
13696 // VERTICAL BLUR (if any)
13797 if (vertical_radius_value > 0.0 ) {
138- // Init boxes for computing blur
139- int *bxs = initBoxes (sigma_value, vertical_radius_value);
140-
14198 // Apply vertical blur to target RGBA channels
142- boxBlurT (red, blur_red, frame_image->width (), frame_image->height (), vertical_radius_value);
143- boxBlurT (green, blur_green, frame_image->width (), frame_image->height (), vertical_radius_value);
144- boxBlurT (blue, blur_blue, frame_image->width (), frame_image->height (), vertical_radius_value);
145- boxBlurT (alpha, blur_alpha, frame_image->width (), frame_image->height (), vertical_radius_value);
146-
147- // Remove boxes
148- delete[] bxs;
149-
150- // Copy blur_<chan> back to <chan> for vertical blur or next iteration
151- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) red[i] = blur_red[i];
152- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) green[i] = blur_green[i];
153- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) blue[i] = blur_blue[i];
154- for (int i = 0 ; i < (frame_image->width () * frame_image->height ()); i++) alpha[i] = blur_alpha[i];
155- }
156- }
99+ boxBlurT (frame_image->bits (), frame_image_2->bits (), w, h, vertical_radius_value);
157100
158- // Copy RGBA channels back to original image
159- for (int pixel = 0 , byte_index=0 ; pixel < frame_image->width () * frame_image->height (); pixel++, byte_index+=4 )
160- {
161- // Get the RGB values from the pixel
162- unsigned char R = blur_red[pixel];
163- unsigned char G = blur_green[pixel];
164- unsigned char B = blur_blue[pixel];
165- unsigned char A = blur_alpha[pixel];
166-
167- // Split channels into their own arrays
168- pixels[byte_index] = R;
169- pixels[byte_index + 1 ] = G;
170- pixels[byte_index + 2 ] = B;
171- pixels[byte_index + 3 ] = A;
101+ // Swap output image back to input
102+ frame_image.swap (frame_image_2);
103+ }
172104 }
173105
174- // Delete channel arrays
175- delete[] red;
176- delete[] green;
177- delete[] blue;
178- delete[] alpha;
179- delete[] blur_red;
180- delete[] blur_green;
181- delete[] blur_blue;
182- delete[] blur_alpha;
183-
184106 // return the modified frame
185107 return frame;
186108}
187109
188110// Credit: http://blog.ivank.net/fastest-gaussian-blur.html (MIT License)
189- int * Blur::initBoxes (float sigma, int n) // standard deviation, number of boxes
190- {
191- float wIdeal = sqrt ((12.0 * sigma * sigma / n) + 1.0 ); // Ideal averaging filter width
192- int wl = floor (wIdeal);
193- if (wl % 2 == 0 ) wl--;
194- int wu = wl + 2 ;
195-
196- float mIdeal = (12.0 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4.0 * wl - 4 );
197- int m = round (mIdeal );
198-
199- int *sizes = new int [n]();
200- for (int i = 0 ; i < n; i++) sizes[i] = i < m ? wl : wu;
201- return sizes;
202- }
203-
204- // Credit: http://blog.ivank.net/fastest-gaussian-blur.html (MIT License)
111+ // Modified to process all four channels in a pixel array
205112void Blur::boxBlurH (unsigned char *scl, unsigned char *tcl, int w, int h, int r) {
206113 float iarr = 1.0 / (r + r + 1 );
207- for (int i = 0 ; i < h; i++) {
208- int ti = i * w, li = ti, ri = ti + r;
209- int fv = scl[ti], lv = scl[ti + w - 1 ], val = (r + 1 ) * fv;
210- for (int j = 0 ; j < r; j++) val += scl[ti + j];
211- for (int j = 0 ; j <= r; j++) {
212- val += scl[ri++] - fv;
213- tcl[ti++] = round (val * iarr);
214- }
215- for (int j = r + 1 ; j < w - r; j++) {
216- val += scl[ri++] - scl[li++];
217- tcl[ti++] = round (val * iarr);
218- }
219- for (int j = w - r; j < w; j++) {
220- val += lv - scl[li++];
221- tcl[ti++] = round (val * iarr);
114+
115+ #pragma omp parallel for shared (scl, tcl)
116+ for (int i = 0 ; i < h; ++i) {
117+ for (int ch = 0 ; ch < 4 ; ++ch) {
118+ int ti = i * w, li = ti, ri = ti + r;
119+ int fv = scl[ti * 4 + ch], lv = scl[(ti + w - 1 ) * 4 + ch], val = (r + 1 ) * fv;
120+ for (int j = 0 ; j < r; ++j) {
121+ val += scl[(ti + j) * 4 + ch];
122+ }
123+ for (int j = 0 ; j <= r; ++j) {
124+ val += scl[ri++ * 4 + ch] - fv;
125+ tcl[ti++ * 4 + ch] = round (val * iarr);
126+ }
127+ for (int j = r + 1 ; j < w - r; ++j) {
128+ val += scl[ri++ * 4 + ch] - scl[li++ * 4 + ch];
129+ tcl[ti++ * 4 + ch] = round (val * iarr);
130+ }
131+ for (int j = w - r; j < w; ++j) {
132+ val += lv - scl[li++ * 4 + ch];
133+ tcl[ti++ * 4 + ch] = round (val * iarr);
134+ }
222135 }
223136 }
224137}
225138
226139void Blur::boxBlurT (unsigned char *scl, unsigned char *tcl, int w, int h, int r) {
227140 float iarr = 1.0 / (r + r + 1 );
141+
142+ #pragma omp parallel for shared (scl, tcl)
228143 for (int i = 0 ; i < w; i++) {
229- int ti = i, li = ti, ri = ti + r * w;
230- int fv = scl[ti], lv = scl[ti + w * (h - 1 )], val = (r + 1 ) * fv;
231- for (int j = 0 ; j < r; j++) val += scl[ti + j * w];
232- for (int j = 0 ; j <= r; j++) {
233- val += scl[ri] - fv;
234- tcl[ti] = round (val * iarr);
235- ri += w;
236- ti += w;
237- }
238- for (int j = r + 1 ; j < h - r; j++) {
239- val += scl[ri] - scl[li];
240- tcl[ti] = round (val * iarr);
241- li += w;
242- ri += w;
243- ti += w;
244- }
245- for (int j = h - r; j < h; j++) {
246- val += lv - scl[li];
247- tcl[ti] = round (val * iarr);
248- li += w;
249- ti += w;
144+ for (int ch = 0 ; ch < 4 ; ++ch) {
145+ int ti = i, li = ti, ri = ti + r * w;
146+ int fv = scl[ti * 4 + ch], lv = scl[(ti + w * (h - 1 )) * 4 + ch], val = (r + 1 ) * fv;
147+ for (int j = 0 ; j < r; j++) val += scl[(ti + j * w) * 4 + ch];
148+ for (int j = 0 ; j <= r; j++) {
149+ val += scl[ri * 4 + ch] - fv;
150+ tcl[ti * 4 + ch] = round (val * iarr);
151+ ri += w;
152+ ti += w;
153+ }
154+ for (int j = r + 1 ; j < h - r; j++) {
155+ val += scl[ri * 4 + ch] - scl[li * 4 + ch];
156+ tcl[ti * 4 + ch] = round (val * iarr);
157+ li += w;
158+ ri += w;
159+ ti += w;
160+ }
161+ for (int j = h - r; j < h; j++) {
162+ val += lv - scl[li * 4 + ch];
163+ tcl[ti * 4 + ch] = round (val * iarr);
164+ li += w;
165+ ti += w;
166+ }
250167 }
251168 }
252169}
0 commit comments