vpn common -> implicit segmentation
This introduces base functions for introducing implicit segmentation. The code that actually stores the results to the segment map isn't here yet. This just prints out the segmentation map results if you call it. Uses connected component labeling technique on mbmi info so that only if 2 mbs are horizontally or vertically touching do they get the same segment. vp8next - plumbing for rotation code to produce taps for rotation ( tapify. py ), code for predicting using rotation ( predict_rotated.c ) , code for finding the best rotation find_rotation.c. didn't checkin code that uses this in the codec. still work in progress. Fixed copyright notice Change-Id: I450c13cfa41ab2fcb699f3897760370b4935fdf8
This commit is contained in:
parent
5aab0c3fb7
commit
91325b8fe7
277
vp8/common/implicit_segmentation.c
Normal file
277
vp8/common/implicit_segmentation.c
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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
|
||||
#define NULL 0
|
||||
|
||||
#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.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.as_mv.row,mi[mb_index].mbmi.mv.as_mv.col );
|
||||
}
|
||||
printf("\n");
|
||||
++mb_index;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
85
vp8/common/predict_rotated.c
Normal file
85
vp8/common/predict_rotated.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if CONFIG_ROTATION
|
||||
typedef struct
|
||||
{
|
||||
int y;
|
||||
int x;
|
||||
unsigned long t;
|
||||
} tap;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
tap pt[4];
|
||||
} point_taps;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
point_taps pt[256];
|
||||
} mb_taps;
|
||||
|
||||
mb_taps mt_8x8[] =
|
||||
{
|
||||
#include "rotate2.h"
|
||||
};
|
||||
|
||||
mb_taps mt[] =
|
||||
{
|
||||
#include "rotate.h"
|
||||
};
|
||||
|
||||
void predict_rotated_16x16(int rotation_index, unsigned char *src, int sp,
|
||||
unsigned char *dst, int dp)
|
||||
{
|
||||
int i, j, k, p = 0;
|
||||
|
||||
for (i = 0; i < 16; i++, dst += dp)
|
||||
{
|
||||
for (j = 0; j < 16; j++, p++)
|
||||
{
|
||||
unsigned int sum = 32768;
|
||||
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
tap *tp = &mt[rotation_index].pt[p].pt[k];
|
||||
sum += src[tp->y * sp + tp->x] * tp->t;
|
||||
}
|
||||
sum >>= 16;
|
||||
dst[j] = sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
void predict_rotated_8x8(int rotation_index, unsigned char *src, int sp,
|
||||
unsigned char *dst, int dp)
|
||||
{
|
||||
int i, j, k, p = 0;
|
||||
|
||||
for (i = 0; i < 8; i++, dst += dp)
|
||||
{
|
||||
for (j = 0; j < 8; j++, p++)
|
||||
{
|
||||
unsigned int sum = 32768;
|
||||
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
tap *tp = &mt_8x8[rotation_index].pt[p].pt[k];
|
||||
sum += src[tp->y * sp + tp->x] * tp->t;
|
||||
}
|
||||
sum >>= 16;
|
||||
dst[j] = sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
2827
vp8/common/rotate.h
Normal file
2827
vp8/common/rotate.h
Normal file
File diff suppressed because it is too large
Load Diff
2827
vp8/common/rotate2.h
Normal file
2827
vp8/common/rotate2.h
Normal file
File diff suppressed because it is too large
Load Diff
106
vp8/common/tapify.py
Executable file
106
vp8/common/tapify.py
Executable file
@ -0,0 +1,106 @@
|
||||
"""
|
||||
* 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.
|
||||
"""
|
||||
#!/usr/bin/env python
|
||||
import sys,string,os,re,math,numpy
|
||||
scale = 2**16
|
||||
def dist(p1,p2):
|
||||
x1,y1 = p1
|
||||
x2,y2 = p2
|
||||
if x1==x2 and y1==y2 :
|
||||
return 1.0
|
||||
return 1/ math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
|
||||
|
||||
def gettaps(p):
|
||||
def l(b):
|
||||
return int(math.floor(b))
|
||||
def h(b):
|
||||
return int(math.ceil(b))
|
||||
def t(b,p,s):
|
||||
return int((scale*dist(b,p)+s/2)/s)
|
||||
r,c = p
|
||||
ul=[l(r),l(c)]
|
||||
ur=[l(r),h(c)]
|
||||
ll=[h(r),l(c)]
|
||||
lr=[h(r),h(c)]
|
||||
sum = dist(ul,p)+dist(ur,p)+dist(ll,p)+dist(lr,p)
|
||||
t4 = scale - t(ul,p,sum) - t(ur,p,sum) - t(ll,p,sum);
|
||||
return [[ul,t(ul,p,sum)],[ur,t(ur,p,sum)],
|
||||
[ll,t(ll,p,sum)],[lr,t4]]
|
||||
|
||||
def print_mb_taps(angle,blocksize):
|
||||
theta = angle / 57.2957795;
|
||||
affine = [[math.cos(theta),-math.sin(theta)],
|
||||
[math.sin(theta),math.cos(theta)]]
|
||||
radius = (float(blocksize)-1)/2
|
||||
print " // angle of",angle,"degrees"
|
||||
for y in range(blocksize) :
|
||||
for x in range(blocksize) :
|
||||
r,c = numpy.dot(affine,[y-radius, x-radius])
|
||||
tps = gettaps([r+radius,c+radius])
|
||||
for t in tps :
|
||||
p,t = t
|
||||
tr,tc = p
|
||||
print " %2d, %2d, %5d, " % (tr,tc,t,),
|
||||
print " // %2d,%2d " % (y,x)
|
||||
|
||||
i=float(sys.argv[1])
|
||||
while i <= float(sys.argv[2]) :
|
||||
print_mb_taps(i,float(sys.argv[4]))
|
||||
i=i+float(sys.argv[3])
|
||||
"""
|
||||
|
||||
taps = []
|
||||
pt=dict()
|
||||
ptr=dict()
|
||||
for y in range(16) :
|
||||
for x in range(16) :
|
||||
r,c = numpy.dot(affine,[y-7.5, x-7.5])
|
||||
tps = gettaps([r+7.5,c+7.5])
|
||||
j=0
|
||||
for tp in tps :
|
||||
p,i = tp
|
||||
r,c = p
|
||||
pt[y,x,j]= [p,i]
|
||||
try:
|
||||
ptr[r,j,c].append([y,x])
|
||||
except:
|
||||
ptr[r,j,c]=[[y,x]]
|
||||
j = j+1
|
||||
|
||||
for key in sorted(pt.keys()) :
|
||||
print key,pt[key]
|
||||
|
||||
lr = -99
|
||||
lj = -99
|
||||
lc = 0
|
||||
|
||||
shuf=""
|
||||
mask=""
|
||||
for r,j,c in sorted(ptr.keys()) :
|
||||
for y,x in ptr[r,j,c] :
|
||||
if lr != r or lj != j :
|
||||
print "shuf_"+str(lr)+"_"+str(lj)+"_"+shuf.ljust(16,"0"), lc
|
||||
shuf=""
|
||||
lc = 0
|
||||
for i in range(lc,c-1) :
|
||||
shuf = shuf +"0"
|
||||
shuf = shuf + hex(x)[2]
|
||||
lc =c
|
||||
break
|
||||
lr = r
|
||||
lj = j
|
||||
# print r,j,c,ptr[r,j,c]
|
||||
# print
|
||||
|
||||
for r,j,c in sorted(ptr.keys()) :
|
||||
for y,x in ptr[r,j,c] :
|
||||
print r,j,c,y,x
|
||||
break
|
||||
"""
|
58
vp8/encoder/find_rotation.c
Normal file
58
vp8/encoder/find_rotation.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 "block.h"
|
||||
#include "variance.h"
|
||||
|
||||
#if CONFIG_ROTATION
|
||||
|
||||
int vp8_find_best_rotation(MACROBLOCK *x, BLOCK *b, BLOCKD *d, int_mv *bestmv,
|
||||
int_mv *ref_mv, int *bri, int error_per_bit,
|
||||
const vp8_variance_fn_ptr_t *vfp, int *mvcost[2],
|
||||
int *distortion, unsigned int *sse1)
|
||||
{
|
||||
unsigned char *z = (*(b->base_src) + b->src);
|
||||
|
||||
int ri;
|
||||
|
||||
int y_stride;
|
||||
|
||||
unsigned int besterr;
|
||||
int br = bestmv->as_mv.row;
|
||||
int bc = bestmv->as_mv.col;
|
||||
unsigned char *y = *(d->base_pre) + d->pre + br * d->pre_stride + bc;
|
||||
y_stride = d->pre_stride;
|
||||
|
||||
// calculate central point error
|
||||
besterr = vfp->vf(y, y_stride, z, b->src_stride, sse1);
|
||||
*distortion = besterr;
|
||||
|
||||
// find the best matching rotation
|
||||
*bri = 5;
|
||||
for (ri = 0; ri < ROTATIONS; ri++)
|
||||
{
|
||||
unsigned int this_err;
|
||||
unsigned char pb[256];
|
||||
predict_rotated_16x16(ri, y, y_stride, pb, 16);
|
||||
this_err = vfp->vf(pb, 16, z, b->src_stride, sse1);
|
||||
|
||||
if (this_err < besterr)
|
||||
{
|
||||
*bri = ri;
|
||||
besterr = this_err;
|
||||
}
|
||||
}
|
||||
*sse1 = besterr;
|
||||
*distortion = besterr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -73,6 +73,11 @@ VP8_COMMON_SRCS-yes += common/setupintrarecon.c
|
||||
VP8_COMMON_SRCS-yes += common/swapyv12buffer.c
|
||||
VP8_COMMON_SRCS-$(CONFIG_POSTPROC_VISUALIZER) += common/textblit.c
|
||||
VP8_COMMON_SRCS-yes += common/treecoder.c
|
||||
VP8_COMMON_SRCS-yes += common/implicit_segmentation.c
|
||||
VP8_COMMON_SRCS-yes += common/implicit_segmentation.h
|
||||
VP8_COMMON_SRCS-yes += common/predict_rotated.c
|
||||
VP8_COMMON_SRCS-yes += common/rotate.h
|
||||
VP8_COMMON_SRCS-yes += common/rotate2.h
|
||||
|
||||
VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/idct_x86.h
|
||||
VP8_COMMON_SRCS-$(ARCH_X86)$(ARCH_X86_64) += common/x86/subpixel_x86.h
|
||||
|
@ -87,9 +87,11 @@ VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.h
|
||||
VP8_CX_SRCS-$(CONFIG_INTERNAL_STATS) += common/postproc.c
|
||||
VP8_CX_SRCS-yes += encoder/temporal_filter.c
|
||||
VP8_CX_SRCS-yes += encoder/temporal_filter.h
|
||||
VP8_CX_SRCS-yes += encoder/find_rotation.c
|
||||
VP8_CX_SRCS-yes += encoder/mbgraph.c
|
||||
VP8_CX_SRCS-yes += encoder/mbgraph.h
|
||||
|
||||
|
||||
ifeq ($(CONFIG_REALTIME_ONLY),yes)
|
||||
VP8_CX_SRCS_REMOVE-yes += encoder/firstpass.c
|
||||
VP8_CX_SRCS_REMOVE-yes += encoder/temporal_filter.c
|
||||
|
Loading…
x
Reference in New Issue
Block a user