0aa8e1616537ea40fa923cfec8045c9b47c22b12
2 * Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com>
4 * This file is part of Libav.
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libav is distributed in the hope that it will be useful,
12 * but 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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * Codebook Generator using the ELBG algorithm
28 #include "libavutil/common.h"
29 #include "libavutil/lfg.h"
33 #define DELTA_ERR_MAX 0.1 ///< Precision of the ELBG algorithm (as percentual error)
36 * In the ELBG jargon, a cell is the set of points that are closest to a
37 * codebook entry. Not to be confused with a RoQ Video cell. */
38 typedef struct cell_s
{
60 static inline int distance_limited(int *a
, int *b
, int dim
, int limit
)
63 for (i
=0; i
<dim
; i
++) {
64 dist
+= (a
[i
] - b
[i
])*(a
[i
] - b
[i
]);
72 static inline void vect_division(int *res
, int *vect
, int div
, int dim
)
77 res
[i
] = ROUNDED_DIV(vect
[i
],div
);
79 memcpy(res
, vect
, dim
*sizeof(int));
83 static int eval_error_cell(elbg_data
*elbg
, int *centroid
, cell
*cells
)
86 for (; cells
; cells
=cells
->next
)
87 error
+= distance_limited(centroid
, elbg
->points
+ cells
->index
*elbg
->dim
, elbg
->dim
, INT_MAX
);
92 static int get_closest_codebook(elbg_data
*elbg
, int index
)
94 int i
, pick
=0, diff
, diff_min
= INT_MAX
;
95 for (i
=0; i
<elbg
->numCB
; i
++)
97 diff
= distance_limited(elbg
->codebook
+ i
*elbg
->dim
, elbg
->codebook
+ index
*elbg
->dim
, elbg
->dim
, diff_min
);
98 if (diff
< diff_min
) {
106 static int get_high_utility_cell(elbg_data
*elbg
)
109 /* Using linear search, do binary if it ever turns to be speed critical */
110 int r
= av_lfg_get(elbg
->rand_state
)%elbg
->utility_inc
[elbg
->numCB
-1] + 1;
111 while (elbg
->utility_inc
[i
] < r
)
114 assert(elbg
->cells
[i
]);
120 * Implementation of the simple LBG algorithm for just two codebooks
122 static int simple_lbg(elbg_data
*elbg
,
130 int numpoints
[2] = {0,0};
131 int *newcentroid
[2] = {
132 elbg
->scratchbuf
+ 3*dim
,
133 elbg
->scratchbuf
+ 4*dim
137 memset(newcentroid
[0], 0, 2 * dim
* sizeof(*newcentroid
[0]));
142 for (tempcell
= cells
; tempcell
; tempcell
=tempcell
->next
) {
143 idx
= distance_limited(centroid
[0], points
+ tempcell
->index
*dim
, dim
, INT_MAX
)>=
144 distance_limited(centroid
[1], points
+ tempcell
->index
*dim
, dim
, INT_MAX
);
146 for (i
=0; i
<dim
; i
++)
147 newcentroid
[idx
][i
] += points
[tempcell
->index
*dim
+ i
];
150 vect_division(centroid
[0], newcentroid
[0], numpoints
[0], dim
);
151 vect_division(centroid
[1], newcentroid
[1], numpoints
[1], dim
);
153 for (tempcell
= cells
; tempcell
; tempcell
=tempcell
->next
) {
154 int dist
[2] = {distance_limited(centroid
[0], points
+ tempcell
->index
*dim
, dim
, INT_MAX
),
155 distance_limited(centroid
[1], points
+ tempcell
->index
*dim
, dim
, INT_MAX
)};
156 int idx
= dist
[0] > dist
[1];
157 newutility
[idx
] += dist
[idx
];
160 return newutility
[0] + newutility
[1];
163 static void get_new_centroids(elbg_data
*elbg
, int huc
, int *newcentroid_i
,
167 int *min
= newcentroid_i
;
168 int *max
= newcentroid_p
;
171 for (i
=0; i
< elbg
->dim
; i
++) {
176 for (tempcell
= elbg
->cells
[huc
]; tempcell
; tempcell
= tempcell
->next
)
177 for(i
=0; i
<elbg
->dim
; i
++) {
178 min
[i
]=FFMIN(min
[i
], elbg
->points
[tempcell
->index
*elbg
->dim
+ i
]);
179 max
[i
]=FFMAX(max
[i
], elbg
->points
[tempcell
->index
*elbg
->dim
+ i
]);
182 for (i
=0; i
<elbg
->dim
; i
++) {
183 int ni
= min
[i
] + (max
[i
] - min
[i
])/3;
184 int np
= min
[i
] + (2*(max
[i
] - min
[i
]))/3;
185 newcentroid_i
[i
] = ni
;
186 newcentroid_p
[i
] = np
;
191 * Add the points in the low utility cell to its closest cell. Split the high
192 * utility cell, putting the separed points in the (now empty) low utility
195 * @param elbg Internal elbg data
196 * @param indexes {luc, huc, cluc}
197 * @param newcentroid A vector with the position of the new centroids
199 static void shift_codebook(elbg_data
*elbg
, int *indexes
,
203 cell
**pp
= &elbg
->cells
[indexes
[2]];
208 *pp
= elbg
->cells
[indexes
[0]];
210 elbg
->cells
[indexes
[0]] = NULL
;
211 tempdata
= elbg
->cells
[indexes
[1]];
212 elbg
->cells
[indexes
[1]] = NULL
;
215 cell
*tempcell2
= tempdata
->next
;
216 int idx
= distance_limited(elbg
->points
+ tempdata
->index
*elbg
->dim
,
217 newcentroid
[0], elbg
->dim
, INT_MAX
) >
218 distance_limited(elbg
->points
+ tempdata
->index
*elbg
->dim
,
219 newcentroid
[1], elbg
->dim
, INT_MAX
);
221 tempdata
->next
= elbg
->cells
[indexes
[idx
]];
222 elbg
->cells
[indexes
[idx
]] = tempdata
;
223 tempdata
= tempcell2
;
227 static void evaluate_utility_inc(elbg_data
*elbg
)
231 for (i
=0; i
< elbg
->numCB
; i
++) {
232 if (elbg
->numCB
*elbg
->utility
[i
] > elbg
->error
)
233 inc
+= elbg
->utility
[i
];
234 elbg
->utility_inc
[i
] = inc
;
239 static void update_utility_and_n_cb(elbg_data
*elbg
, int idx
, int newutility
)
243 elbg
->utility
[idx
] = newutility
;
244 for (tempcell
=elbg
->cells
[idx
]; tempcell
; tempcell
=tempcell
->next
)
245 elbg
->nearest_cb
[tempcell
->index
] = idx
;
249 * Evaluate if a shift lower the error. If it does, call shift_codebooks
250 * and update elbg->error, elbg->utility and elbg->nearest_cb.
252 * @param elbg Internal elbg data
253 * @param idx {luc (low utility cell, huc (high utility cell), cluc (closest cell to low utility cell)}
255 static void try_shift_candidate(elbg_data
*elbg
, int idx
[3])
257 int j
, k
, olderror
=0, newerror
, cont
=0;
259 int *newcentroid
[3] = {
261 elbg
->scratchbuf
+ elbg
->dim
,
262 elbg
->scratchbuf
+ 2*elbg
->dim
267 olderror
+= elbg
->utility
[idx
[j
]];
269 memset(newcentroid
[2], 0, elbg
->dim
*sizeof(int));
272 for (tempcell
=elbg
->cells
[idx
[2*k
]]; tempcell
; tempcell
=tempcell
->next
) {
274 for (j
=0; j
<elbg
->dim
; j
++)
275 newcentroid
[2][j
] += elbg
->points
[tempcell
->index
*elbg
->dim
+ j
];
278 vect_division(newcentroid
[2], newcentroid
[2], cont
, elbg
->dim
);
280 get_new_centroids(elbg
, idx
[1], newcentroid
[0], newcentroid
[1]);
282 newutility
[2] = eval_error_cell(elbg
, newcentroid
[2], elbg
->cells
[idx
[0]]);
283 newutility
[2] += eval_error_cell(elbg
, newcentroid
[2], elbg
->cells
[idx
[2]]);
285 newerror
= newutility
[2];
287 newerror
+= simple_lbg(elbg
, elbg
->dim
, newcentroid
, newutility
, elbg
->points
,
288 elbg
->cells
[idx
[1]]);
290 if (olderror
> newerror
) {
291 shift_codebook(elbg
, idx
, newcentroid
);
293 elbg
->error
+= newerror
- olderror
;
296 update_utility_and_n_cb(elbg
, idx
[j
], newutility
[j
]);
298 evaluate_utility_inc(elbg
);
303 * Implementation of the ELBG block
305 static void do_shiftings(elbg_data
*elbg
)
309 evaluate_utility_inc(elbg
);
311 for (idx
[0]=0; idx
[0] < elbg
->numCB
; idx
[0]++)
312 if (elbg
->numCB
*elbg
->utility
[idx
[0]] < elbg
->error
) {
313 if (elbg
->utility_inc
[elbg
->numCB
-1] == 0)
316 idx
[1] = get_high_utility_cell(elbg
);
317 idx
[2] = get_closest_codebook(elbg
, idx
[0]);
319 if (idx
[1] != idx
[0] && idx
[1] != idx
[2])
320 try_shift_candidate(elbg
, idx
);
324 #define BIG_PRIME 433494437LL
326 void ff_init_elbg(int *points
, int dim
, int numpoints
, int *codebook
,
327 int numCB
, int max_steps
, int *closest_cb
,
332 if (numpoints
> 24*numCB
) {
333 /* ELBG is very costly for a big number of points. So if we have a lot
334 of them, get a good initial codebook to save on iterations */
335 int *temp_points
= av_malloc(dim
*(numpoints
/8)*sizeof(int));
336 for (i
=0; i
<numpoints
/8; i
++) {
337 k
= (i
*BIG_PRIME
) % numpoints
;
338 memcpy(temp_points
+ i
*dim
, points
+ k
*dim
, dim
*sizeof(int));
341 ff_init_elbg(temp_points
, dim
, numpoints
/8, codebook
, numCB
, 2*max_steps
, closest_cb
, rand_state
);
342 ff_do_elbg(temp_points
, dim
, numpoints
/8, codebook
, numCB
, 2*max_steps
, closest_cb
, rand_state
);
344 av_free(temp_points
);
346 } else // If not, initialize the codebook with random positions
347 for (i
=0; i
< numCB
; i
++)
348 memcpy(codebook
+ i
*dim
, points
+ ((i
*BIG_PRIME
)%numpoints
)*dim
,
353 void ff_do_elbg(int *points
, int dim
, int numpoints
, int *codebook
,
354 int numCB
, int max_steps
, int *closest_cb
,
359 elbg_data
*elbg
= &elbg_d
;
360 int i
, j
, k
, last_error
, steps
=0;
361 int *dist_cb
= av_malloc(numpoints
*sizeof(int));
362 int *size_part
= av_malloc(numCB
*sizeof(int));
363 cell
*list_buffer
= av_malloc(numpoints
*sizeof(cell
));
365 int best_dist
, best_idx
= 0;
367 elbg
->error
= INT_MAX
;
370 elbg
->codebook
= codebook
;
371 elbg
->cells
= av_malloc(numCB
*sizeof(cell
*));
372 elbg
->utility
= av_malloc(numCB
*sizeof(int));
373 elbg
->nearest_cb
= closest_cb
;
374 elbg
->points
= points
;
375 elbg
->utility_inc
= av_malloc(numCB
*sizeof(int));
376 elbg
->scratchbuf
= av_malloc(5*dim
*sizeof(int));
378 elbg
->rand_state
= rand_state
;
381 free_cells
= list_buffer
;
382 last_error
= elbg
->error
;
384 memset(elbg
->utility
, 0, numCB
*sizeof(int));
385 memset(elbg
->cells
, 0, numCB
*sizeof(cell
*));
389 /* This loop evaluate the actual Voronoi partition. It is the most
390 costly part of the algorithm. */
391 for (i
=0; i
< numpoints
; i
++) {
392 best_dist
= distance_limited(elbg
->points
+ i
*elbg
->dim
, elbg
->codebook
+ best_idx
*elbg
->dim
, dim
, INT_MAX
);
393 for (k
=0; k
< elbg
->numCB
; k
++) {
394 dist
= distance_limited(elbg
->points
+ i
*elbg
->dim
, elbg
->codebook
+ k
*elbg
->dim
, dim
, best_dist
);
395 if (dist
< best_dist
) {
400 elbg
->nearest_cb
[i
] = best_idx
;
401 dist_cb
[i
] = best_dist
;
402 elbg
->error
+= dist_cb
[i
];
403 elbg
->utility
[elbg
->nearest_cb
[i
]] += dist_cb
[i
];
404 free_cells
->index
= i
;
405 free_cells
->next
= elbg
->cells
[elbg
->nearest_cb
[i
]];
406 elbg
->cells
[elbg
->nearest_cb
[i
]] = free_cells
;
412 memset(size_part
, 0, numCB
*sizeof(int));
414 memset(elbg
->codebook
, 0, elbg
->numCB
*dim
*sizeof(int));
416 for (i
=0; i
< numpoints
; i
++) {
417 size_part
[elbg
->nearest_cb
[i
]]++;
418 for (j
=0; j
< elbg
->dim
; j
++)
419 elbg
->codebook
[elbg
->nearest_cb
[i
]*elbg
->dim
+ j
] +=
420 elbg
->points
[i
*elbg
->dim
+ j
];
423 for (i
=0; i
< elbg
->numCB
; i
++)
424 vect_division(elbg
->codebook
+ i
*elbg
->dim
,
425 elbg
->codebook
+ i
*elbg
->dim
, size_part
[i
], elbg
->dim
);
427 } while(((last_error
- elbg
->error
) > DELTA_ERR_MAX
*elbg
->error
) &&
428 (steps
< max_steps
));
432 av_free(elbg
->utility
);
433 av_free(list_buffer
);
434 av_free(elbg
->cells
);
435 av_free(elbg
->utility_inc
);
436 av_free(elbg
->scratchbuf
);