jmac698
27th June 2011, 22:40
#RGB<=>YCgCo demo by jmac, requires masktools v2a38+, tested in avisynth 2.58
#The demo just shows colorbars, but what is happening is a conversion back and forth between colorspaces
#Theoretically you would convert to YCgCo and compress, this will compress about 10% better than YUV
#However, it's unclear how to send this to an h.264 encoder. There's probably a way to arrange the pixels to make it work.
#To test compression, just feed as YUV to a compressor. The Cg/Co channels will be subsampled. Playback the result as YUV, the script will decode it.
#Ver 1.0 - Does correct, full range conversion both ways, in 8bit
#Ver 0.1 - does something, but incorrectly - almost finished
#ImageReader("E:\project001a\YCgCo\YCgCo-1600x4800.jpg")#Sample picture stacked as RGB,Y,Cg,Co (Cg and Co are colourized for illustration)
colorbars.Levels(16, 1, 235, 0, 255, coring=false)#fix bug in colorbars...
rgb=verticalunstack4(0)
y=verticalunstack4(1)
cg=verticalunstack4(2)
co=verticalunstack4(3)
#Testing...
RGB2YCgCo
#for realtime playback in ffdshow, from h.264 with YCgCo, erase all lines above
#except I don't know the format return from ffdshow
YCgCo2RGB
function verticalunstack4(clip v, int slice) {
#Return n'th vertical slice of n slices, e.g. 4 videos stackedvertically (opposite of stackvertical)
#note slice=0 is the top block
slices=4
v
blockheight=height/slices
crop(0,slice*blockheight,0,blockheight)
}
function RGB2YCgCo(clip v) {
#convert an assumed RGB clip into Co,Y,Cg
#~ Y = 0.25 * R + 0.5 * G + 0.25 * B
#~ Cg = -0.25 * R + 0.5 * G - 0.25 * B + 0.5
#~ Co = 0.5 * R - 0.5 * B + 0.5
v
#put planes into yuv for masktools (awkward)
#RGBintoYV12
r1=ShowRed.converttoyv12(matrix="PC.709")#R->Y
g1=ShowGreen.converttoyv12(matrix="PC.709")#G->Y
b1=ShowBlue.converttoyv12(matrix="PC.709")#B->y
r=YtoUV(r1,r1,r1.pointresize(r1.width*2,r1.height*2))#y->y, y->u, y->v
g=YtoUV(g1,g1,g1.pointresize(g1.width*2,g1.height*2))#y->y, y->u, y->v
b=YtoUV(b1,b1,b1.pointresize(b1.width*2,b1.height*2))#y->y, y->u, y->v
#Note: remember b=u=Cg=z, r=v=Co=x, g=y=y=y
mt_lutxyz(r,g,b,yexpr="x 4 / y 2 / + z 4 / +",uexpr="y 2 / x 4 / - z 4 / - 128 +",vexpr="x 2 / z 2 / - 128 +",chroma="process")
YV12intoRGB
}
function YCgCo2RGB(clip v) {
#convert an assumed Co,Y,Cg clip into RGB
#~ R = Y - Cg + Co
#~ G = Y + Cg
#~ B = Y - Cg - Co + 1
v
#put planes into yuv for masktools (awkward)
r1=ShowRed.converttoyv12(matrix="PC.709")#R->Y
g1=ShowGreen.converttoyv12(matrix="PC.709")#G->Y
b1=ShowBlue.converttoyv12(matrix="PC.709")#B->y
r=YtoUV(r1,r1,r1.pointresize(r1.width*2,r1.height*2))#y->y, y->u, y->v
g=YtoUV(g1,g1,g1.pointresize(g1.width*2,g1.height*2))#y->y, y->u, y->v
b=YtoUV(b1,b1,b1.pointresize(b1.width*2,b1.height*2))#y->y, y->u, y->v
#Note: remember b=u=Cg=z, r=v=Co=x, g=y=y=y
mt_lutxyz(r,g,b,yexpr="y z + 128 -",uexpr="y z - x - 256 +",vexpr="y z - x +",chroma="process")
YV12intoRGB
}
function RGBintoYV12(clip v) {#This wasn't used in the end
#place r,g,b data directly into v,y,u planes
#this result has no visual meaning (however, closest approximation) but is only for performing arithmetic on the data
v
pointresize(width*2,height*2)#doublesize to allow full 4:4:4 color resolution with u,v
r=ShowRed.converttoyv12(matrix="PC.709")
g=ShowGreen.converttoyv12(matrix="PC.709")
g=g.pointresize(width*2,height*2)#this is destined for Y which must be larger
b=ShowBlue.converttoyv12(matrix="PC.709")
YtoUV(b,r,g)#b->u, r->v, g->y
}
function YV12intoRGB(clip v) {
#place v,y,u data into r,g,b planes
#this result has no visual meaning (however, closest approximation) but is only for performing arithmetic on the data
v
r=vtoy.converttorgb(matrix="PC.709")
g=greyscale.converttorgb(matrix="PC.709")
g=g.pointresize(width/2,height/2)#Y was doublesized
b=utoy.converttorgb(matrix="PC.709")
MergeRGB(r,g,b)#u->b, v->r, y->g
}
#The demo just shows colorbars, but what is happening is a conversion back and forth between colorspaces
#Theoretically you would convert to YCgCo and compress, this will compress about 10% better than YUV
#However, it's unclear how to send this to an h.264 encoder. There's probably a way to arrange the pixels to make it work.
#To test compression, just feed as YUV to a compressor. The Cg/Co channels will be subsampled. Playback the result as YUV, the script will decode it.
#Ver 1.0 - Does correct, full range conversion both ways, in 8bit
#Ver 0.1 - does something, but incorrectly - almost finished
#ImageReader("E:\project001a\YCgCo\YCgCo-1600x4800.jpg")#Sample picture stacked as RGB,Y,Cg,Co (Cg and Co are colourized for illustration)
colorbars.Levels(16, 1, 235, 0, 255, coring=false)#fix bug in colorbars...
rgb=verticalunstack4(0)
y=verticalunstack4(1)
cg=verticalunstack4(2)
co=verticalunstack4(3)
#Testing...
RGB2YCgCo
#for realtime playback in ffdshow, from h.264 with YCgCo, erase all lines above
#except I don't know the format return from ffdshow
YCgCo2RGB
function verticalunstack4(clip v, int slice) {
#Return n'th vertical slice of n slices, e.g. 4 videos stackedvertically (opposite of stackvertical)
#note slice=0 is the top block
slices=4
v
blockheight=height/slices
crop(0,slice*blockheight,0,blockheight)
}
function RGB2YCgCo(clip v) {
#convert an assumed RGB clip into Co,Y,Cg
#~ Y = 0.25 * R + 0.5 * G + 0.25 * B
#~ Cg = -0.25 * R + 0.5 * G - 0.25 * B + 0.5
#~ Co = 0.5 * R - 0.5 * B + 0.5
v
#put planes into yuv for masktools (awkward)
#RGBintoYV12
r1=ShowRed.converttoyv12(matrix="PC.709")#R->Y
g1=ShowGreen.converttoyv12(matrix="PC.709")#G->Y
b1=ShowBlue.converttoyv12(matrix="PC.709")#B->y
r=YtoUV(r1,r1,r1.pointresize(r1.width*2,r1.height*2))#y->y, y->u, y->v
g=YtoUV(g1,g1,g1.pointresize(g1.width*2,g1.height*2))#y->y, y->u, y->v
b=YtoUV(b1,b1,b1.pointresize(b1.width*2,b1.height*2))#y->y, y->u, y->v
#Note: remember b=u=Cg=z, r=v=Co=x, g=y=y=y
mt_lutxyz(r,g,b,yexpr="x 4 / y 2 / + z 4 / +",uexpr="y 2 / x 4 / - z 4 / - 128 +",vexpr="x 2 / z 2 / - 128 +",chroma="process")
YV12intoRGB
}
function YCgCo2RGB(clip v) {
#convert an assumed Co,Y,Cg clip into RGB
#~ R = Y - Cg + Co
#~ G = Y + Cg
#~ B = Y - Cg - Co + 1
v
#put planes into yuv for masktools (awkward)
r1=ShowRed.converttoyv12(matrix="PC.709")#R->Y
g1=ShowGreen.converttoyv12(matrix="PC.709")#G->Y
b1=ShowBlue.converttoyv12(matrix="PC.709")#B->y
r=YtoUV(r1,r1,r1.pointresize(r1.width*2,r1.height*2))#y->y, y->u, y->v
g=YtoUV(g1,g1,g1.pointresize(g1.width*2,g1.height*2))#y->y, y->u, y->v
b=YtoUV(b1,b1,b1.pointresize(b1.width*2,b1.height*2))#y->y, y->u, y->v
#Note: remember b=u=Cg=z, r=v=Co=x, g=y=y=y
mt_lutxyz(r,g,b,yexpr="y z + 128 -",uexpr="y z - x - 256 +",vexpr="y z - x +",chroma="process")
YV12intoRGB
}
function RGBintoYV12(clip v) {#This wasn't used in the end
#place r,g,b data directly into v,y,u planes
#this result has no visual meaning (however, closest approximation) but is only for performing arithmetic on the data
v
pointresize(width*2,height*2)#doublesize to allow full 4:4:4 color resolution with u,v
r=ShowRed.converttoyv12(matrix="PC.709")
g=ShowGreen.converttoyv12(matrix="PC.709")
g=g.pointresize(width*2,height*2)#this is destined for Y which must be larger
b=ShowBlue.converttoyv12(matrix="PC.709")
YtoUV(b,r,g)#b->u, r->v, g->y
}
function YV12intoRGB(clip v) {
#place v,y,u data into r,g,b planes
#this result has no visual meaning (however, closest approximation) but is only for performing arithmetic on the data
v
r=vtoy.converttorgb(matrix="PC.709")
g=greyscale.converttorgb(matrix="PC.709")
g=g.pointresize(width/2,height/2)#Y was doublesized
b=utoy.converttorgb(matrix="PC.709")
MergeRGB(r,g,b)#u->b, v->r, y->g
}