2 * Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com>
4 * This file is part of FFmpeg.
6 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * @file libavcodec/elbg.c
23 * Codebook Generator using the ELBG algorithm
28 #include "libavutil/lfg.h"
32 #define DELTA_ERR_MAX 0.1 ///< Precision of the ELBG algorithm (as percentual error)
35 * In the ELBG jargon, a cell is the set of points that are closest to a
36 * codebook entry. Not to be confused with a RoQ Video cell. */
37 typedef struct cell_s
{
58 static inline int distance_limited(int *a
, int *b
, int dim
, int limit
)
61 for (i
=0; i
<dim
; i
++) {
62 dist
+= (a
[i
] - b
[i
])*(a
[i
] - b
[i
]);
70 static inline void vect_division(int *res
, int *vect
, int div
, int dim
)
75 res
[i
] = ROUNDED_DIV(vect
[i
],div
);
77 memcpy(res
, vect
, dim
*sizeof(int));
81 static int eval_error_cell(elbg_data
*elbg
, int *centroid
, cell
*cells
)
84 for (; cells
; cells
=cells
->next
)
85 error
+= distance_limited(centroid
, elbg
->points
+ cells
->index
*elbg
->dim
, elbg
->dim
, INT_MAX
);
90 static int get_closest_codebook(elbg_data
*elbg
, int index
)
92 int i
, pick
=0, diff
, diff_min
= INT_MAX
;
93 for (i
=0; i
<elbg
->numCB
; i
++)
95 diff
= distance_limited(elbg
->codebook
+ i
*elbg
->dim
, elbg
->codebook
+ index
*elbg
->dim
, elbg
->dim
, diff_min
);
96 if (diff
< diff_min
) {
104 static int get_high_utility_cell(elbg_data
*elbg
)
107 /* Using linear search, do binary if it ever turns to be speed critical */
108 int r
= av_lfg_get(elbg
->rand_state
)%elbg
->utility_inc
[elbg
->numCB
-1] + 1;
109 while (elbg
->utility_inc
[i
] < r
)
112 assert(!elbg
->cells
[i
]);
118 * Implementation of the simple LBG algorithm for just two codebooks
120 static int simple_lbg(int dim
,
127 int numpoints
[2] = {0,0};
128 int newcentroid
[2][dim
];
131 memset(newcentroid
, 0, sizeof(newcentroid
));
136 for (tempcell
= cells
; tempcell
; tempcell
=tempcell
->next
) {
137 idx
= distance_limited(centroid
[0], points
+ tempcell
->index
*dim
, dim
, INT_MAX
)>=
138 distance_limited(centroid
[1], points
+ tempcell
->index
*dim
, dim
, INT_MAX
);
140 for (i
=0; i
<dim
; i
++)
141 newcentroid
[idx
][i
] += points
[tempcell
->index
*dim
+ i
];
144 vect_division(centroid
[0], newcentroid
[0], numpoints
[0], dim
);
145 vect_division(centroid
[1], newcentroid
[1], numpoints
[1], dim
);
147 for (tempcell
= cells
; tempcell
; tempcell
=tempcell
->next
) {
148 int dist
[2] = {distance_limited(centroid
[0], points
+ tempcell
->index
*dim
, dim
, INT_MAX
),
149 distance_limited(centroid
[1], points
+ tempcell
->index
*dim
, dim
, INT_MAX
)};
150 int idx
= dist
[0] > dist
[1];
151 newutility
[idx
] += dist
[idx
];
154 return newutility
[0] + newutility
[1];
157 static void get_new_centroids(elbg_data
*elbg
, int huc
, int *newcentroid_i
,
165 for (i
=0; i
< elbg
->dim
; i
++) {
170 for (tempcell
= elbg
->cells
[huc
]; tempcell
; tempcell
= tempcell
->next
)
171 for(i
=0; i
<elbg
->dim
; i
++) {
172 min
[i
]=FFMIN(min
[i
], elbg
->points
[tempcell
->index
*elbg
->dim
+ i
]);
173 max
[i
]=FFMAX(max
[i
], elbg
->points
[tempcell
->index
*elbg
->dim
+ i
]);
176 for (i
=0; i
<elbg
->dim
; i
++) {
177 newcentroid_i
[i
] = min
[i
] + (max
[i
] - min
[i
])/3;
178 newcentroid_p
[i
] = min
[i
] + (2*(max
[i
] - min
[i
]))/3;
183 * Add the points in the low utility cell to its closest cell. Split the high
184 * utility cell, putting the separed points in the (now empty) low utility
187 * @param elbg Internal elbg data
188 * @param indexes {luc, huc, cluc}
189 * @param newcentroid A vector with the position of the new centroids
191 static void shift_codebook(elbg_data
*elbg
, int *indexes
,
195 cell
**pp
= &elbg
->cells
[indexes
[2]];
200 *pp
= elbg
->cells
[indexes
[0]];
202 elbg
->cells
[indexes
[0]] = NULL
;
203 tempdata
= elbg
->cells
[indexes
[1]];
204 elbg
->cells
[indexes
[1]] = NULL
;
207 cell
*tempcell2
= tempdata
->next
;
208 int idx
= distance_limited(elbg
->points
+ tempdata
->index
*elbg
->dim
,
209 newcentroid
[0], elbg
->dim
, INT_MAX
) >
210 distance_limited(elbg
->points
+ tempdata
->index
*elbg
->dim
,
211 newcentroid
[1], elbg
->dim
, INT_MAX
);
213 tempdata
->next
= elbg
->cells
[indexes
[idx
]];
214 elbg
->cells
[indexes
[idx
]] = tempdata
;
215 tempdata
= tempcell2
;
219 static void evaluate_utility_inc(elbg_data
*elbg
)
223 for (i
=0; i
< elbg
->numCB
; i
++) {
224 if (elbg
->numCB
*elbg
->utility
[i
] > elbg
->error
)
225 inc
+= elbg
->utility
[i
];
226 elbg
->utility_inc
[i
] = inc
;
231 static void update_utility_and_n_cb(elbg_data
*elbg
, int idx
, int newutility
)
235 elbg
->utility
[idx
] = newutility
;
236 for (tempcell
=elbg
->cells
[idx
]; tempcell
; tempcell
=tempcell
->next
)
237 elbg
->nearest_cb
[tempcell
->index
] = idx
;
241 * Evaluate if a shift lower the error. If it does, call shift_codebooks
242 * and update elbg->error, elbg->utility and elbg->nearest_cb.
244 * @param elbg Internal elbg data
245 * @param indexes {luc (low utility cell, huc (high utility cell), cluc (closest cell to low utility cell)}
247 static void try_shift_candidate(elbg_data
*elbg
, int idx
[3])
249 int j
, k
, olderror
=0, newerror
, cont
=0;
251 int newcentroid
[3][elbg
->dim
];
252 int *newcentroid_ptrs
[3];
255 newcentroid_ptrs
[0] = newcentroid
[0];
256 newcentroid_ptrs
[1] = newcentroid
[1];
257 newcentroid_ptrs
[2] = newcentroid
[2];
260 olderror
+= elbg
->utility
[idx
[j
]];
262 memset(newcentroid
[2], 0, elbg
->dim
*sizeof(int));
265 for (tempcell
=elbg
->cells
[idx
[2*k
]]; tempcell
; tempcell
=tempcell
->next
) {
267 for (j
=0; j
<elbg
->dim
; j
++)
268 newcentroid
[2][j
] += elbg
->points
[tempcell
->index
*elbg
->dim
+ j
];
271 vect_division(newcentroid
[2], newcentroid
[2], cont
, elbg
->dim
);
273 get_new_centroids(elbg
, idx
[1], newcentroid
[0], newcentroid
[1]);
275 newutility
[2] = eval_error_cell(elbg
, newcentroid
[2], elbg
->cells
[idx
[0]]);
276 newutility
[2] += eval_error_cell(elbg
, newcentroid
[2], elbg
->cells
[idx
[2]]);
278 newerror
= newutility
[2];
280 newerror
+= simple_lbg(elbg
->dim
, newcentroid_ptrs
, newutility
, elbg
->points
,
281 elbg
->cells
[idx
[1]]);
283 if (olderror
> newerror
) {
284 shift_codebook(elbg
, idx
, newcentroid_ptrs
);
286 elbg
->error
+= newerror
- olderror
;
289 update_utility_and_n_cb(elbg
, idx
[j
], newutility
[j
]);
291 evaluate_utility_inc(elbg
);
296 * Implementation of the ELBG block
298 static void do_shiftings(elbg_data
*elbg
)
302 evaluate_utility_inc(elbg
);
304 for (idx
[0]=0; idx
[0] < elbg
->numCB
; idx
[0]++)
305 if (elbg
->numCB
*elbg
->utility
[idx
[0]] < elbg
->error
) {
306 if (elbg
->utility_inc
[elbg
->numCB
-1] == 0)
309 idx
[1] = get_high_utility_cell(elbg
);
310 idx
[2] = get_closest_codebook(elbg
, idx
[0]);
312 if (idx
[1] != idx
[0] && idx
[1] != idx
[2])
313 try_shift_candidate(elbg
, idx
);
317 #define BIG_PRIME 433494437LL
319 void ff_init_elbg(int *points
, int dim
, int numpoints
, int *codebook
,
320 int numCB
, int max_steps
, int *closest_cb
,
325 if (numpoints
> 24*numCB
) {
326 /* ELBG is very costly for a big number of points. So if we have a lot
327 of them, get a good initial codebook to save on iterations */
328 int *temp_points
= av_malloc(dim
*(numpoints
/8)*sizeof(int));
329 for (i
=0; i
<numpoints
/8; i
++) {
330 k
= (i
*BIG_PRIME
) % numpoints
;
331 memcpy(temp_points
+ i
*dim
, points
+ k
*dim
, dim
*sizeof(int));
334 ff_init_elbg(temp_points
, dim
, numpoints
/8, codebook
, numCB
, 2*max_steps
, closest_cb
, rand_state
);
335 ff_do_elbg(temp_points
, dim
, numpoints
/8, codebook
, numCB
, 2*max_steps
, closest_cb
, rand_state
);
337 av_free(temp_points
);
339 } else // If not, initialize the codebook with random positions
340 for (i
=0; i
< numCB
; i
++)
341 memcpy(codebook
+ i
*dim
, points
+ ((i
*BIG_PRIME
)%numpoints
)*dim
,
346 void ff_do_elbg(int *points
, int dim
, int numpoints
, int *codebook
,
347 int numCB
, int max_steps
, int *closest_cb
,
352 elbg_data
*elbg
= &elbg_d
;
353 int i
, j
, k
, last_error
, steps
=0;
354 int *dist_cb
= av_malloc(numpoints
*sizeof(int));
355 int *size_part
= av_malloc(numCB
*sizeof(int));
356 cell
*list_buffer
= av_malloc(numpoints
*sizeof(cell
));
359 elbg
->error
= INT_MAX
;
362 elbg
->codebook
= codebook
;
363 elbg
->cells
= av_malloc(numCB
*sizeof(cell
*));
364 elbg
->utility
= av_malloc(numCB
*sizeof(int));
365 elbg
->nearest_cb
= closest_cb
;
366 elbg
->points
= points
;
367 elbg
->utility_inc
= av_malloc(numCB
*sizeof(int));
369 elbg
->rand_state
= rand_state
;
372 free_cells
= list_buffer
;
373 last_error
= elbg
->error
;
375 memset(elbg
->utility
, 0, numCB
*sizeof(int));
376 memset(elbg
->cells
, 0, numCB
*sizeof(cell
*));
380 /* This loop evaluate the actual Voronoi partition. It is the most
381 costly part of the algorithm. */
382 for (i
=0; i
< numpoints
; i
++) {
383 dist_cb
[i
] = INT_MAX
;
384 for (k
=0; k
< elbg
->numCB
; k
++) {
385 dist
= distance_limited(elbg
->points
+ i
*elbg
->dim
, elbg
->codebook
+ k
*elbg
->dim
, dim
, dist_cb
[i
]);
386 if (dist
< dist_cb
[i
]) {
388 elbg
->nearest_cb
[i
] = k
;
391 elbg
->error
+= dist_cb
[i
];
392 elbg
->utility
[elbg
->nearest_cb
[i
]] += dist_cb
[i
];
393 free_cells
->index
= i
;
394 free_cells
->next
= elbg
->cells
[elbg
->nearest_cb
[i
]];
395 elbg
->cells
[elbg
->nearest_cb
[i
]] = free_cells
;
401 memset(size_part
, 0, numCB
*sizeof(int));
403 memset(elbg
->codebook
, 0, elbg
->numCB
*dim
*sizeof(int));
405 for (i
=0; i
< numpoints
; i
++) {
406 size_part
[elbg
->nearest_cb
[i
]]++;
407 for (j
=0; j
< elbg
->dim
; j
++)
408 elbg
->codebook
[elbg
->nearest_cb
[i
]*elbg
->dim
+ j
] +=
409 elbg
->points
[i
*elbg
->dim
+ j
];
412 for (i
=0; i
< elbg
->numCB
; i
++)
413 vect_division(elbg
->codebook
+ i
*elbg
->dim
,
414 elbg
->codebook
+ i
*elbg
->dim
, size_part
[i
], elbg
->dim
);
416 } while(((last_error
- elbg
->error
) > DELTA_ERR_MAX
*elbg
->error
) &&
417 (steps
< max_steps
));
421 av_free(elbg
->utility
);
422 av_free(list_buffer
);
423 av_free(elbg
->cells
);
424 av_free(elbg
->utility_inc
);