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