Commit | Line | Data |
---|---|---|
80f575fc DM |
1 | /* |
2 | * boxblur.c | |
3 | * | |
4 | * Copyright (C) Georg Martius - July 2010 | |
5 | * georg dot martius at web dot de | |
6 | * | |
7 | * This file is part of vid.stab video stabilization library | |
8 | * | |
9 | * vid.stab is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License, | |
11 | * as published by the Free Software Foundation; either version 2, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * vid.stab is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with GNU Make; see the file COPYING. If not, write to | |
21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | * | |
23 | */ | |
24 | ||
25 | #include "boxblur.h" | |
26 | #include "vidstabdefines.h" | |
27 | ||
28 | ||
29 | void boxblur_hori_C(unsigned char* dest, const unsigned char* src, | |
30 | int width, int height, int dest_strive, int src_strive, int size); | |
31 | void boxblur_vert_C(unsigned char* dest, const unsigned char* src, | |
32 | int width, int height, int dest_strive, int src_strive, int size); | |
33 | ||
34 | /* | |
35 | The algorithm: | |
36 | box filter: kernel has only 1's | |
37 | a good blur is obtained for multiple runs of boxblur | |
38 | - 2 runs: tent kernel, infinity -> gaussian | |
39 | but for our purposes is the tent kernel enough. | |
40 | ||
41 | horizontal and vertical 1D boxfilters can be used | |
42 | ||
43 | accumulator: acc = acc + new - old, pixel = acc/size | |
44 | */ | |
45 | ||
46 | void boxblurPlanar(VSFrame* dest, const VSFrame* src, | |
47 | VSFrame* buffer, const VSFrameInfo* fi, | |
48 | unsigned int size, BoxBlurColorMode colormode){ | |
49 | int localbuffer=0; | |
50 | int size2; | |
51 | if(size<2){ | |
52 | if(dest!=src) | |
53 | vsFrameCopy(dest,src,fi); | |
54 | return; | |
55 | } | |
56 | VSFrame buf; | |
57 | if(buffer==0){ | |
58 | vsFrameAllocate(&buf,fi); | |
59 | localbuffer=1; | |
60 | }else{ | |
61 | buf = *buffer; | |
62 | } | |
63 | // odd and larger than 2 and maximally half of smaller image dimension | |
64 | size = VS_CLAMP((size/2)*2+1,3,VS_MIN(fi->height/2,fi->width/2)); | |
65 | //printf("%i\n",size); | |
66 | ||
67 | // luminance | |
68 | boxblur_hori_C(buf.data[0], src->data[0], | |
69 | fi->width, fi->height, buf.linesize[0],src->linesize[0], size); | |
70 | boxblur_vert_C(dest->data[0], buf.data[0], | |
71 | fi->width, fi->height, dest->linesize[0], buf.linesize[0], size); | |
72 | ||
73 | size2 = size/2+1; // odd and larger than 0 | |
74 | int plane; | |
75 | switch (colormode){ | |
76 | case BoxBlurColor: | |
77 | // color | |
78 | if(size2>1){ | |
79 | for(plane=1; plane<fi->planes; plane++){ | |
80 | boxblur_hori_C(buf.data[plane], src->data[plane], | |
81 | fi->width >> vsGetPlaneWidthSubS(fi,plane), | |
82 | fi->height >> vsGetPlaneHeightSubS(fi,plane), | |
83 | buf.linesize[plane], src->linesize[plane], size2); | |
84 | boxblur_vert_C(dest->data[plane], buf.data[plane], | |
85 | fi->width >> vsGetPlaneWidthSubS(fi,plane), | |
86 | fi->height >> vsGetPlaneHeightSubS(fi,plane), | |
87 | dest->linesize[plane], buf.linesize[plane], size2); | |
88 | } | |
89 | } | |
90 | break; | |
91 | case BoxBlurKeepColor: | |
92 | // copy both color channels | |
93 | for(plane=1; plane<fi->planes; plane++){ | |
94 | vsFrameCopyPlane(dest, src, fi, plane); | |
95 | } | |
96 | case BoxBlurNoColor: // do nothing | |
97 | default: | |
98 | break; | |
99 | } | |
100 | ||
101 | if(localbuffer) | |
102 | vsFrameFree(&buf); | |
103 | } | |
104 | ||
105 | /* /\* */ | |
106 | /* The algorithm: */ | |
107 | /* see boxblurPlanar but here we for Packed */ | |
108 | ||
109 | /* we add the 3 bytes of one pixel as if they where one number */ | |
110 | /* *\/ */ | |
111 | /* void boxblurPacked(const unsigned char* src, unsigned char* dest, */ | |
112 | /* unsigned char* buffer, const VSFrameInfo* fi, */ | |
113 | /* unsigned int size){ */ | |
114 | /* int localbuffer=0; */ | |
115 | /* if(buffer==0){ */ | |
116 | /* buffer=(unsigned char*) vs_malloc(fi->framesize); */ | |
117 | /* localbuffer=1; */ | |
118 | /* } */ | |
119 | /* // odd and larger than 2 and maximal half of smaller image dimension */ | |
120 | /* // (and not larger than 256, because otherwise we can get an overflow) */ | |
121 | /* size = VS_CLAMP((size/2)*2+1,3,VS_MIN(256,VS_MIN(fi->height/2,fi->width/2))); */ | |
122 | ||
123 | /* // we need a different version of these functions for Packed */ | |
124 | /* boxblur_hori_C(src, buffer, fi->width, fi->height, fi->strive, size); */ | |
125 | /* boxblur_vert_C(buffer, dest, fi->width, fi->height, fi->strive, size); */ | |
126 | ||
127 | /* if(localbuffer) */ | |
128 | /* vs_free(buffer); */ | |
129 | /* } */ | |
130 | ||
131 | ||
132 | void boxblur_hori_C(unsigned char* dest, const unsigned char* src, | |
133 | int width, int height, int dest_strive, int src_strive, int size){ | |
134 | ||
135 | int i,j,k; | |
136 | unsigned int acc; | |
137 | const unsigned char *start, *end; // start and end of kernel | |
138 | unsigned char *current; // current destination pixel | |
139 | int size2 = size/2; // size of one side of the kernel without center | |
140 | // #pragma omp parallel for private(acc),schedule(guided,2) (no speedup) | |
141 | for(j=0; j< height; j++){ | |
142 | // for(j=100; j< 101; j++){ | |
143 | start = end = src + j*src_strive; | |
144 | current = dest + j*dest_strive; | |
145 | // initialize accumulator | |
146 | acc= (*start)*(size2+1); // left half of kernel with first pixel | |
147 | for(k=0; k<size2; k++){ // right half of kernel | |
148 | acc+=(*end); | |
149 | end++; | |
150 | } | |
151 | // go through the image | |
152 | for(i=0; i< width; i++){ | |
153 | acc = acc + (*end) - (*start); | |
154 | if(i > size2) start++; | |
155 | if(i < width - size2 - 1) end++; | |
156 | (*current) = acc/size; | |
157 | current++; | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | void boxblur_vert_C(unsigned char* dest, const unsigned char* src, | |
163 | int width, int height, int dest_strive, int src_strive, int size){ | |
164 | ||
165 | int i,j,k; | |
166 | int acc; | |
167 | const unsigned char *start, *end; // start and end of kernel | |
168 | unsigned char *current; // current destination pixel | |
169 | int size2 = size/2; // size of one side of the kernel without center | |
170 | for(i=0; i< width; i++){ | |
171 | start = end = src + i; | |
172 | current = dest + i; | |
173 | // initialize accumulator | |
174 | acc= (*start)*(size2+1); // left half of kernel with first pixel | |
175 | for(k=0; k<size2; k++){ // right half of kernel | |
176 | acc+=(*end); | |
177 | end+=src_strive; | |
178 | } | |
179 | // go through the image | |
180 | for(j=0; j< height; j++){ | |
181 | acc = acc - (*start) + (*end); | |
182 | if(j > size2) start+=src_strive; | |
183 | if(j < height - size2 - 1) end+=src_strive; | |
184 | *current = acc/size; | |
185 | current+=dest_strive; | |
186 | } | |
187 | } | |
188 | } |