BRL-CAD
filter.c
Go to the documentation of this file.
1 /* F I L T E R . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2013-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file libicv/filter.c
21  *
22  * This file contains routines for image filtering. This is done
23  * mainly using the convolution of images. Both Gray Scale and RGB
24  * images are taken care.
25  */
26 
27 #include "bu/log.h"
28 #include "bu/malloc.h"
29 #include "icv.h"
30 
31 #include "vmath.h"
32 
33 #define KERN_DEFAULT 3
34 
35 /* private functions */
36 
37 HIDDEN void
38 get_kernel(ICV_FILTER filter_type, double *kern, double *offset)
39 {
40  switch (filter_type) {
41  case ICV_FILTER_LOW_PASS :
42  kern[0] = 3.0/42.0; kern[1] = 5.0/42.0; kern[2] = 3.0/42.0;
43  kern[3] = 5.0/42.0; kern[4] = 10.0/42.0; kern[5] = 5.0/42.0;
44  kern[6] = 3.0/42.0; kern[7] = 5.0/42.0; kern[8] = 3.0/42.0;
45  *offset = 0;
46  break;
48  kern[0] = -1.0/16.0; kern[1] = -1.0/16.0; kern[2] = -1.0/16.0;
49  kern[3] = -1.0/16.0; kern[4] = 8.0/16.0; kern[5] = -1.0/16.0;
50  kern[6] = -1.0/16.0; kern[7] = -1.0/16.0; kern[8] = -1.0/16.0;
51  *offset = 0.5;
52  break;
54  kern[0] = 1.0/6.0; kern[1] = 0; kern[2] = -1.0/6.0;
55  kern[3] = 1.0/6.0; kern[4] = 0; kern[5] = -1.0/6.0;
56  kern[6] = 1.0/6.0; kern[7] = 0; kern[8] = -1.0/6.0;
57  *offset = 0.5;
58  break;
60  kern[0] = 1.0/6.0; kern[1] = 1.0/6.0; kern[2] = 1.0/6.0;
61  kern[3] = 0; kern[4] = 0; kern[5] = 0;
62  kern[6] = -1.0/6.0; kern[7] = -1.0/6.0; kern[8] = -1.0/6.0;
63  *offset = 0.5;
64  break;
66  kern[0] = -1.0; kern[1] = -2.0; kern[2] = -1.0;
67  kern[3] = -2.0; kern[4] = 13.0; kern[5] = -2.0;
68  kern[6] = -1.0; kern[7] = -2.0; kern[8] = -1.0;
69  *offset = 0;
70  break;
72  kern[0] = 1.0/9; kern[1] = 1.0/9; kern[2] = 1.0/9;
73  kern[3] = 1.0/9; kern[4] = 1.0/9; kern[5] = 1.0/9;
74  kern[6] = 1.0/9; kern[7] = 1.0/9; kern[8] = 1.0/9;
75  *offset = 0;
76  break;
77  case ICV_FILTER_NULL :
78  kern[0] = 0; kern[1] = 0; kern[2] = 0;
79  kern[3] = 0; kern[4] = 0; kern[5] = 0;
80  kern[6] = 0; kern[7] = 0; kern[8] = 0;
81  *offset = 0;
82  break;
83  default :
84  bu_log("Filter Type not Implemented.\n");
85  bu_free(kern, "Freeing Kernel, Wrong filter");
86  kern = NULL;
87  }
88  return;
89 }
90 
91 HIDDEN void
92 get_kernel3(ICV_FILTER3 filter_type, double *kern, double *offset)
93 {
94  switch (filter_type) {
96  kern[0] = 1.0/84; kern[1] = 3.0/84; kern[2] = 1.0/84;
97  kern[3] = 3.0/84; kern[4] = 5.0/84; kern[5] = 3.0/84;
98  kern[6] = 1.0/84; kern[7] = 3.0/84; kern[8] = 1.0/84;
99  kern[9] = 3.0/84; kern[10] = 5.0/84; kern[11] = 3.0/84;
100  kern[12] = 5.0/84; kern[13] = 10.0/84; kern[14] = 5.0/84;
101  kern[15] = 3.0/84; kern[16] = 5.0/84; kern[17] = 3.0/84;
102  kern[18] = 1.0/84; kern[19] = 3.0/84; kern[20] = 1.0/84;
103  kern[21] = 3.0/84; kern[22] = 5.0/84; kern[23] = 3.0/84;
104  kern[24] = 1.0/84; kern[25] = 3.0/84; kern[26] = 1.0/84;
105  *offset = 0;
106  break;
107  case ICV_FILTER3_HIGH_PASS :
108  kern[0] = -1.0; kern[1] = -2.0; kern[2] = -1.0;
109  kern[3] = -2.0; kern[4] = -4.0; kern[5] = -2.0;
110  kern[6] = -1.0; kern[7] = -2.0; kern[8] = -1.0;
111  kern[9] = -2.0; kern[10] = -4.0; kern[11] = -2.0;
112  kern[12] = -4.0; kern[13] = 56.0; kern[14] = -4.0;
113  kern[15] = -2.0; kern[16] = -4.0; kern[17] = -2.0;
114  kern[18] = -1.0; kern[19] = -2.0; kern[20] = -1.0;
115  kern[21] = -2.0; kern[22] = -4.0; kern[23] = -2.0;
116  kern[24] = -1.0; kern[25] = -2.0; kern[26] = -1.0;
117  *offset = 0;
118  break;
120  kern[0] = 1.0/53; kern[1] = 1.0/53; kern[2] = 1.0/53;
121  kern[3] = 1.0/53; kern[4] = 1.0/53; kern[5] = 1.0/53;
122  kern[6] = 1.0/53; kern[7] = 1.0/53; kern[8] = 1.0/53;
123  kern[9] = 1.0/53; kern[10] = 1.0/53; kern[11] = 1.0/53;
124  kern[12] = 1.0/53; kern[13] = 27.0/53; kern[14] = 1.0/53;
125  kern[15] = 1.0/53; kern[16] = 1.0/53; kern[17] = 1.0/53;
126  kern[18] = 1.0/53; kern[19] = 1.0/53; kern[20] = 1.0/53;
127  kern[21] = 1.0/53; kern[22] = 1.0/53; kern[23] = 1.0/53;
128  kern[24] = 1.0/53; kern[25] = 1.0/53; kern[26] = 1.0/53;
129  *offset = 0;
130  break;
132  kern[0] = 1.0/69; kern[1] = 1.0/69; kern[2] = 1.0/69;
133  kern[3] = 1.0/69; kern[4] = 1.0/69; kern[5] = 1.0/69;
134  kern[6] = 1.0/69; kern[7] = 1.0/69; kern[8] = 1.0/69;
135  kern[9] = 1.0/69; kern[10] = 1.0/69; kern[11] = 1.0/69;
136  kern[12] = 1.0/69; kern[13] = 1.0/69; kern[14] = 1.0/69;
137  kern[15] = 1.0/69; kern[16] = 1.0/69; kern[17] = 1.0/69;
138  kern[18] = 2.0/69; kern[19] = 2.0/69; kern[20] = 2.0/69;
139  kern[21] = 2.0/69; kern[22] = 35.0/69; kern[23] = 2.0/69;
140  kern[24] = 2.0/69; kern[25] = 2.0/69; kern[26] = 2.0/69;
141  *offset = 0;
142  break;
143  case ICV_FILTER3_NULL :
144  kern[0] = 0; kern[1] = 0; kern[2] = 0;
145  kern[3] = 0; kern[4] = 0; kern[5] = 0;
146  kern[6] = 0; kern[7] = 0; kern[8] = 0;
147  kern[9] = 0; kern[10] = 0; kern[11] = 0;
148  kern[12] = 0; kern[13] = 0; kern[14] = 0;
149  kern[15] = 0; kern[16] = 0; kern[17] = 0;
150  kern[18] = 0; kern[19] = 0; kern[20] = 0;
151  kern[21] = 0; kern[22] = 0; kern[23] = 0;
152  kern[24] = 0; kern[25] = 0; kern[26] = 0;
153  *offset = 0;
154  break;
155  default :
156  bu_log("Filter Type not Implemented.\n");
157  bu_free(kern, "Freeing Kernel, Wrong filter");
158  kern = NULL;
159  }
160  return;
161 }
162 
163 /* end of private functions */
164 
165 /* begin public functions */
166 
167 int
169 {
170  double *kern = NULL, *kern_p = NULL;
171  double c_val;
172  double *out_data, *in_data, *data_p;
173  double offset = 0;
174  int k_dim = KERN_DEFAULT, k_dim_half, k_dim_half_ceil;
175  long int size;
176  long int h, w, k, i;
177  long int widthstep;
178  long int index, n_index; /**< index is the index of the pixel in
179  * out image and n_index corresponds to
180  * the nearby pixel in input image
181  */
182 
183  /* TODO A new Functionality. Update the get_kernel function to
184  * accommodate the generalized kernel length. This can be based
185  * upon a library of filters or closed form definitions.
186  */
187 
188  ICV_IMAGE_VAL_INT(img);
189 
190  kern = (double *)bu_malloc(k_dim*k_dim*sizeof(double), "icv_filter : Kernel Allocation");
191  get_kernel(filter_type, kern, &offset);
192 
193  if (!kern)
194  return -1;
195 
196  widthstep = img->width*img->channels;
197 
198  in_data = img->data;
199  size = img->height*img->width*img->channels;
200  /* Replaces data pointer in place */
201  img->data = out_data = (double*)bu_malloc(size*sizeof(double), "icv_filter : out_image_data");
202 
203  index = -1;
204  /* Kernel Dimension is always considered to be odd*/
205  k_dim_half = k_dim/2*img->channels;
206  k_dim_half_ceil = (k_dim - k_dim/2)*img->channels;
207  index = 0;
208  for (h = 0; h < img->height; h++) {
209  VMOVEN(out_data, in_data+index, k_dim_half);
210  out_data+=k_dim_half;
211 
212  for (w = 0; w < widthstep - k_dim*img->channels; w++) {
213  c_val = 0;
214  kern_p = kern;
215 
216  for (k = -k_dim/2; k<=k_dim/2; k++) {
217  n_index = index + k*widthstep;
218  data_p = in_data + n_index;
219  for (i = 0; i<=k_dim; i++) {
220  /* Ensures that the arguments are given a zero value for
221  * out of bound pixels. Thus behaves similar to zero padding
222  */
223  if (n_index >= 0 && n_index < size) {
224  c_val += (*kern_p++)*(*data_p);
225  data_p += img->channels;
226  /* Ensures out bound in image */
227  n_index += img->channels;
228  }
229  }
230  }
231  *out_data = c_val + offset;
232  out_data++;
233  index++;
234  }
235  index = (h+1)*widthstep;
236  VMOVEN(out_data,in_data+index -k_dim_half_ceil*img->channels,k_dim_half_ceil*img->channels );
237  out_data+= k_dim_half_ceil;
238  }
239  bu_free(in_data, "icv:filter Input Image Data");
240  return 0;
241 }
242 
243 icv_image_t *
244 icv_filter3(icv_image_t *old_img, icv_image_t *curr_img, icv_image_t *new_img, ICV_FILTER3 filter_type)
245 {
246  icv_image_t *out_img;
247  double *kern = NULL;
248  double *kern_old, *kern_curr, *kern_new;
249  double c_val;
250  double *out_data;
251  double *old_data, *curr_data, *new_data;
252  double *old_data_p, *curr_data_p, *new_data_p;
253  double offset = 0;
254  int k_dim = KERN_DEFAULT;
255  long int size;
256  long int s, k, i;
257  long int widthstep;
258  long int index, n_index; /**< index is the index of the pixel in
259  * out image and n_index corresponds to
260  * the nearby pixel in input image
261  */
262 
263  ICV_IMAGE_VAL_PTR(old_img);
264  ICV_IMAGE_VAL_PTR(curr_img);
265  ICV_IMAGE_VAL_PTR(new_img);
266 
267  if ((old_img->width == curr_img->width && curr_img->width == new_img->width) && \
268  (old_img->height == curr_img->height && curr_img->height == new_img->height) && \
269  (old_img->channels == curr_img->channels && curr_img->channels == new_img->channels)) {
270  bu_log("icv_filter3 : Image Parameters not Equal");
271  return NULL;
272  }
273 
274  kern = (double *)bu_malloc(k_dim*k_dim*3*sizeof(double), "icv_filter3 : Kernel Allocation");
275  get_kernel3(filter_type, kern, &offset);
276 
277  if (!kern)
278  return NULL;
279 
280  widthstep = old_img->width*old_img->channels;
281 
282  old_data = old_img->data;
283  curr_data = curr_img->data;
284  new_data = new_img->data;
285 
286  size = old_img->height*old_img->width*old_img->channels;
287 
288  out_img = icv_create(old_img->width, old_img->height, old_img->color_space);
289 
290  out_data = out_img->data;
291 
292  index = -1;
293 
294  for (s = 0; s <= size; s++) {
295  index++;
296  c_val = 0;
297  kern_old = kern;
298  kern_curr = kern + k_dim*k_dim-1;
299  kern_new = kern + 2*k_dim*k_dim-1;
300  for (k = -k_dim/2; k<=k_dim/2; k++) {
301  n_index = index + k*widthstep;
302  old_data_p = old_data + n_index;
303  curr_data_p = curr_data + n_index;
304  new_data_p = new_data + n_index;
305  for (i = 0; i<=k_dim; i++) {
306  /* Ensures that the arguments are given a zero value for
307  out of bound pixels. Thus behaves similar to zero padding */
308  if (n_index >= 0 && n_index < size) {
309  c_val += (*kern_old++)*(*old_data_p);
310  c_val += (*kern_curr++)*(*curr_data_p);
311  c_val += (*kern_new++)*(*new_data_p);
312  old_data_p += old_img->channels;
313  curr_data_p += old_img->channels;
314  new_data_p += old_img->channels;
315  n_index += old_img->channels;
316  }
317  }
318  }
319  *out_data++ = c_val + offset;
320  }
321  return 0;
322 }
323 
324 
325 int
326 icv_fade(icv_image_t *img, double fraction)
327 {
328  size_t size;
329  double *data;
330 
331  ICV_IMAGE_VAL_INT(img);
332 
333  size= img->height*img->width*img->channels;
334 
335  if (size == 0)
336  return -1;
337 
338  if (fraction<0) {
339  bu_log("ERROR : Multiplier invalid. Image not Faded.");
340  return -1;
341  }
342 
343  data = img->data;
344 
345  while (size--) {
346  *data = *data*fraction;
347  if (*data > 1)
348  *data= 1.0;
349  data++;
350  }
351  return 0;
352 }
353 /*
354  * Local Variables:
355  * tab-width: 8
356  * mode: C
357  * indent-tabs-mode: t
358  * c-file-style: "stroustrup"
359  * End:
360  * ex: shiftwidth=4 tabstop=8
361  */
double * data
Definition: icv.h:89
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int icv_filter(icv_image_t *img, ICV_FILTER filter_type)
Definition: filter.c:168
int width
Definition: icv.h:91
int icv_fade(icv_image_t *img, double fraction)
Definition: filter.c:326
if lu s
Definition: nmg_mod.c:3860
HIDDEN void get_kernel3(ICV_FILTER3 filter_type, double *kern, double *offset)
Definition: filter.c:92
int channels
Definition: icv.h:91
Definition: icv.h:86
ICV_FILTER3
Definition: icv.h:495
int height
Definition: icv.h:91
#define HIDDEN
Definition: common.h:86
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
COMPLEX data[64]
Definition: fftest.c:34
#define ICV_IMAGE_VAL_PTR(_i)
Definition: icv.h:128
#define KERN_DEFAULT
Definition: filter.c:33
icv_image_t * icv_filter3(icv_image_t *old_img, icv_image_t *curr_img, icv_image_t *new_img, ICV_FILTER3 filter_type)
Definition: filter.c:244
HIDDEN void get_kernel(ICV_FILTER filter_type, double *kern, double *offset)
Definition: filter.c:38
ICV_COLOR_SPACE color_space
Definition: icv.h:88
icv_image_t * icv_create(int width, int height, ICV_COLOR_SPACE color_space)
Definition: fileformat.c:276
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
ICV_FILTER
Definition: icv.h:485
#define ICV_IMAGE_VAL_INT(_i)
Definition: icv.h:123