vpx/vp8/common/implicit_segmentation.c

256 lines
6.1 KiB
C
Raw Normal View History

/*
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "vp8/common/onyxc_int.h"
#define MAX_REGIONS 24000
#ifndef NULL
#define NULL 0
#endif
#define min_mbs_in_region 3
// this linked list structure holds equivalences for connected
// component labeling
struct list_el {
int label;
int seg_value;
int count;
struct list_el *next;
};
typedef struct list_el item;
// connected colorsegments
typedef struct {
int min_x;
int min_y;
int max_x;
int max_y;
long long sum_x;
long long sum_y;
int pixels;
int seg_value;
int label;
} segment_info;
typedef enum {
SEGMENT_MODE,
SEGMENT_MV,
SEGMENT_REFFRAME,
SEGMENT_SKIPPED
} SEGMENT_TYPE;
// this merges the two equivalence lists and
// then makes sure that every label points to the same
// equivalence list
void merge(item *labels, int u, int v) {
item *a = labels[u].next;
item *b = labels[v].next;
item c;
item *it = &c;
int count;
// check if they are already merged
if (u == v || a == b)
return;
count = a->count + b->count;
// merge 2 sorted linked lists.
while (a != NULL && b != NULL) {
if (a->label < b->label) {
it->next = a;
a = a->next;
} else {
it->next = b;
b = b->next;
}
it = it->next;
}
if (a == NULL)
it->next = b;
else
it->next = a;
it = c.next;
// make sure every equivalence in the linked list points to this new ll
while (it != NULL) {
labels[it->label].next = c.next;
it = it->next;
}
c.next->count = count;
}
void segment_via_mode_info(VP8_COMMON *oci, int how) {
MODE_INFO *mi = oci->mi;
int i, j;
int mb_index = 0;
int label = 1;
int pitch = oci->mb_cols;
// holds linked list equivalences
// the max should probably be allocated at a higher level in oci
item equivalences[MAX_REGIONS];
int eq_ptr = 0;
item labels[MAX_REGIONS];
segment_info segments[MAX_REGIONS];
int label_count = 1;
int labeling[400 * 300];
int *lp = labeling;
label_count = 1;
memset(labels, 0, sizeof(labels));
memset(segments, 0, sizeof(segments));
/* Go through each macroblock first pass labelling */
for (i = 0; i < oci->mb_rows; i++, lp += pitch) {
for (j = 0; j < oci->mb_cols; j++) {
// int above seg_value, left seg_value, this seg_value...
int a = -1, l = -1, n = -1;
// above label, left label
int al = -1, ll = -1;
if (i) {
al = lp[j - pitch];
a = labels[al].next->seg_value;
}
if (j) {
ll = lp[j - 1];
l = labels[ll].next->seg_value;
}
// what setting are we going to do the implicit segmentation on
switch (how) {
case SEGMENT_MODE:
n = mi[mb_index].mbmi.mode;
break;
case SEGMENT_MV:
n = mi[mb_index].mbmi.mv[0].as_int;
if (mi[mb_index].mbmi.ref_frame == INTRA_FRAME)
n = -9999999;
break;
case SEGMENT_REFFRAME:
n = mi[mb_index].mbmi.ref_frame;
break;
case SEGMENT_SKIPPED:
n = mi[mb_index].mbmi.mb_skip_coeff;
break;
}
// above and left both have the same seg_value
if (n == a && n == l) {
// pick the lowest label
lp[j] = (al < ll ? al : ll);
labels[lp[j]].next->count++;
// merge the above and left equivalencies
merge(labels, al, ll);
}
// this matches above seg_value
else if (n == a) {
// give it the same label as above
lp[j] = al;
labels[al].next->count++;
}
// this matches left seg_value
else if (n == l) {
// give it the same label as above
lp[j] = ll;
labels[ll].next->count++;
} else {
// new label doesn't match either
item *e = &labels[label];
item *nl = &equivalences[eq_ptr++];
lp[j] = label;
nl->label = label;
nl->next = 0;
nl->seg_value = n;
nl->count = 1;
e->next = nl;
label++;
}
mb_index++;
}
mb_index++;
}
lp = labeling;
// give new labels to regions
for (i = 1; i < label; i++)
if (labels[i].next->count > min_mbs_in_region && labels[labels[i].next->label].label == 0) {
segment_info *cs = &segments[label_count];
cs->label = label_count;
labels[labels[i].next->label].label = label_count++;
labels[labels[i].next->label].seg_value = labels[i].next->seg_value;
cs->seg_value = labels[labels[i].next->label].seg_value;
cs->min_x = oci->mb_cols;
cs->min_y = oci->mb_rows;
cs->max_x = 0;
cs->max_y = 0;
cs->sum_x = 0;
cs->sum_y = 0;
cs->pixels = 0;
}
lp = labeling;
// this is just to gather stats...
for (i = 0; i < oci->mb_rows; i++, lp += pitch) {
for (j = 0; j < oci->mb_cols; j++) {
segment_info *cs;
int oldlab = labels[lp[j]].next->label;
int lab = labels[oldlab].label;
lp[j] = lab;
cs = &segments[lab];
cs->min_x = (j < cs->min_x ? j : cs->min_x);
cs->max_x = (j > cs->max_x ? j : cs->max_x);
cs->min_y = (i < cs->min_y ? i : cs->min_y);
cs->max_y = (i > cs->max_y ? i : cs->max_y);
cs->sum_x += j;
cs->sum_y += i;
cs->pixels++;
lp[j] = lab;
mb_index++;
}
mb_index++;
}
{
lp = labeling;
printf("labelling \n");
mb_index = 0;
for (i = 0; i < oci->mb_rows; i++, lp += pitch) {
for (j = 0; j < oci->mb_cols; j++) {
printf("%4d", lp[j]);
}
printf(" ");
for (j = 0; j < oci->mb_cols; j++, mb_index++) {
// printf("%3d",mi[mb_index].mbmi.mode );
printf("%4d:%4d", mi[mb_index].mbmi.mv[0].as_mv.row,
mi[mb_index].mbmi.mv[0].as_mv.col);
}
printf("\n");
++mb_index;
}
printf("\n");
}
}