logo Sign In

Info: New colormatching script

Author
Time
 (Edited)

Here is an avisynth script that I worked up that TRIES to match the colors of one source with another. Your mileage may vary. Feel free to comment, leave feedback, suggestions, examples etc. here.

Function RGBMatch(clip gref, clip bref, clip “input”, int “mix”)

{# v1.2 - by G-force

Make Red, Green and Blue channel average, (and min and max) of second clip match first clip

or optionally, make third clip match difference between first two

i.e., if the cropping is different between the sources, you could crop the sources first<

to better match each other and then only apply the result to the third (uncropped) clip

mix = how much min/max compensation to do, 0=none (average only), 255=fully match min/max (default)

input  = Default(input,bref)</span>

mix    = Default(mix,255)          </span>

global gref = gref

global bref = bref

global input = input

global mix = mix

scriptclip(bref,"""

grefrgb=gref.ConvertToRGB()

brefrgb=bref.ConvertToRGB()

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>inputrgb=input.ConvertToRGB()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>grefr = grefrgb.ShowRed().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>grefg = grefrgb.ShowGreen().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>grefb = grefrgb.ShowBlue().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>brefr = brefrgb.ShowRed().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>brefg = brefrgb.ShowGreen().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>brefb = brefrgb.ShowBlue().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>inr = inputrgb.ShowRed().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>ing = inputrgb.ShowGreen().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>inb = inputrgb.ShowBlue().ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y1r = AverageLuma(grefr)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y1g = AverageLuma(grefg)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y1b = AverageLuma(grefb)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y2r = ((255-mix)0+mixYplanemin(grefr))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y2g = ((255-mix)0+mixYplanemin(grefg))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y2b = ((255-mix)0+mixYplanemin(grefb))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y3r = ((255-mix)255+mixYplanemax(grefr))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y3g = ((255-mix)255+mixYplanemax(grefg))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>y3b = ((255-mix)255+mixYplanemax(grefb))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x1r = AverageLuma(brefr)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x1g = AverageLuma(brefg)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x1b = AverageLuma(brefb)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x2r = ((255-mix)0+mixYplanemin(brefr))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x2g = ((255-mix)0+mixYplanemin(brefg))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x2b = ((255-mix)0+mixYplanemin(brefb))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x3r = ((255-mix)255+mixYplanemax(brefr))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x3g = ((255-mix)255+mixYplanemax(brefg))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>x3b = ((255-mix)255+mixYplanemax(brefb))/255</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>#compute coefficients for y=ax^2+bx+c using min, avg, max</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>ar  = x1r==x2r? 0: x1r==x3r? 0: x2r==x3r? 0:</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”> \ (y3r-y1r+(x1r-x3r)(y1r-y2r)/(x1r-x2r))/((x1r-x3r)(x2r-x3r))</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>br  = x1r==x2r? 0:</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”> \ ((y2r-y1r)/(x2r-x1r))-ar*(x1r+x2r)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>cr  = y1r-arx1rx1r-br*x1r</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>ag  = x1g==x2g? 0: x1g==x3g? 0: x2g==x3g? 0:</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”> \ (y3g-y1g+(x1g-x3g)(y1g-y2g)/(x1g-x2g))/((x1g-x3g)(x2g-x3g))</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>bg  = x1g==x2g? 0:</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”> \ ((y2g-y1g)/(x2g-x1g))-ag*(x1g+x2g)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>cg  = y1g-agx1gx1g-bg*x1g</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>ab  = x1b==x2b? 0: x1b==x3b? 0: x2b==x3b? 0:</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”> \ (y3b-y1b+(x1b-x3b)(y1b-y2b)/(x1b-x2b))/((x1b-x3b)(x2b-x3b))</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>bb  = x1b==x2b? 0:</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”> \ ((y2b-y1b)/(x2b-x1b))-ab*(x1b+x2b)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>cb  = y1b-abx1bx1b-bb*x1b</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>inr=inr.MT_lut(“x x * “+string(ar)+” * x “+string(br)+” * + “+string(cr)+” +”).ConvertToRGB()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>ing=ing.MT_lut(“x x * “+string(ag)+” * x “+string(bg)+” * + “+string(cg)+” +”).ConvertToRGB()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>inb=inb.MT_lut(“x x * “+string(ab)+” * x “+string(bb)+” * + “+string(cb)+” +”).ConvertToRGB()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>MergeRGB(inr,ing,inb)</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>ConvertToYV12()</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>""")</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>
</span>

<span style=“font-size: 11px; line-height: 13.666666984558105px;”>Return(last)}</span>

Author
Time
 (Edited)

Ok, my first feedback on this updated script is:

After trying it on the 97 SE TB version and 2004 SE DVD of ANH, this time it does indeed lock black and white level it seems, but the saturation comes out way too strong at times.

Could it be that the difference in gamma between the two versions is confusing this script? Or is it that the resulting chroma of this script is matched to a luma difference which is now ignored since the black/white levels are locked?

I'm going to try it on some sources that match a bit better in luma.

Author
Time

Interesting You_Too. Can you post examples of the inputs and output when the saturation is too strong?

-G

Author
Time

Here's a good example, though when looking at it like this I think it might've been my mistake after all. I had to re-encode the 04 SE that I got from DJ to mpeg2 and it made it darker for some reason. Maybe that's what makes this harder for the script to match it.

97 SE on top, 04 SE in middle and result on bottom.

Author
Time

Gamma difference isn't the issue, You_Too. The 2004 SE (B reference) frame is massively clipped which is causing problems when redistributing the 97 SE RGB luma.

I've equalised the RGB luma in your A & B reference frames to illustrate the extent of the clipping in the 2004 SE. The only way this script might work with the 2004 SE/Blu-ray is if it's modified to affect hue only.

 

Author
Time
 (Edited)

 

You_Too, I've modified the Blu-ray to remove most of the clipping from that frame. Would you mind running g-force's script on the following image? Should be a much better result. I've also included an untouched Blu-ray frame (bottom) if you feel like doing a comparison.

 

edit: added untouched (clipped) Blu-ray frame for comparison.

Author
Time

snicker said:

You_Too, I've modified the Blu-ray to remove most of the clipping from that frame. Would you mind running g-force's script on the following image? Should be a much better result.

Yeah, I know the 04 SE is clipped a lot, and got clipped even more when converted back to mpeg2 it seems. I've had better results with some other experiments but I won't post anything just yet.

Anyway, here's that frame of yours run through the script:

Much better! Though if there was a way to make this script also change hues that would be awesome. In the 97 SE Greedo's face and jacket is incorrectly tinted blue, yet they still appear green/teal here after applying the script.

Author
Time

Thanks for helping out snicker! So, You_Too, you might have better results with the average only (as opposed to the average/min/max) script I posted yesterday, and then doing a MergeLuma so the results don't affect the brightness at all.

I don't think this approach is going to get you a Blue Greedo however, as this is pretty much just a first-order approximation.

I'll wait to hear back on your results from experimenting before updating the script.

-G

Author
Time
 (Edited)

Hue maps (top to bottom) - Blu (source), 97 SE (reference), color match result (g-force's script):

 

Author
Time
 (Edited)

Blu-ray matched using 'Match Color' in Photoshop: Photoshop result (top) and hue map (middle), 97 SE hue map (bottom).

You_Too, this seems to be a fairly accurate translation of your reference colours.

 

Author
Time

snicker said:

You_Too, this seems to be a fairly accurate translation of your reference colours.

I don't know, it looks quite off. The wall light is yellow for example.

Anyway, let's not get stuck in this bad example, using that mpeg2 encode I made just for frame matching. I think g-force's new script can be useful for other things. I'm looking into some possibilities.

Author
Time
 (Edited)

You_Too said:

snicker said:

You_Too, this seems to be a fairly accurate translation of your reference colours.

I don't know, it looks quite off. The wall light is yellow for example.

Reds in both sources have lost subtle highlight detail due to clipping. I've found that once the Blu-ray colour clipping is dealt with, these yellow/orange highlight details show up quite often. They're exaggerated here but not inaccurate.

The hue translation through Photoshop's colour matching is pretty much spot on. If used as a hue adjustment layer for the output from g-force's script (which exhibits less clipping) it should produce quite good results, especially considering the limitations of both sources.

Author
Time

It will be interesting to watch the development of g-force's script. I think we could be on to a winner here.

Author
Time

Is this script designed specifically for Star Wars or does it have a more general application?

In other words, would you like this thread moving to the Technical Discussion forum?

Guidelines for post content and general behaviour: read announcement here

Max. allowable image sizes in signatures: reminder here

Author
Time

Hey Moth3r,

I wondered that as well, but I vote that it stays here for the following reasons:

1. It is stemming from a result of SW restoration specific challenges

2. I'm lazy, and don't visit the other thread often

3. We've had less relavent or simular threads here

Ultimately, your call. Of course we could always move it if and when it starts to be used for other purposes.

-G

Author
Time

I did some testing earlier tonight.

This script successfully matches the colors in GOUT to those in the '85 CAV P&S LD!

A picture is worth a thousand words. Post 102 is worth more.

I’m late to the party, but I think this is the best song. Enjoy!

—Teams Jetrell Fo 1, Jetrell Fo 2, and Jetrell Fo 3

Author
Time

Can we see some before/after shots?

A Goon in a Gaggle of 'em

Author
Time

bkev said:

Can we see some before/after shots?

Sure. They're not perfect and do note that I didn't do any levels-correction.

Sample 1

Sample 2

Sample 3

Sample 4

Sample 5

Sample 6

A picture is worth a thousand words. Post 102 is worth more.

I’m late to the party, but I think this is the best song. Enjoy!

—Teams Jetrell Fo 1, Jetrell Fo 2, and Jetrell Fo 3

Author
Time

Wow, that's pretty impressive! But man some of those shots are a tad too bright.

What’s the internal temperature of a TaunTaun? Luke warm.

Author
Time
Wow, so you recoloured a widescreen version using a pan and scan version (?)! Can this script work from single stills?
Author
Time

Mavimao said:

Wow, that's pretty impressive! But man some of those shots are a tad too bright.

Mavimao: I agree, but keep in mind that I didn't correct the levels in either source. The end result would be darker if I had.

Everyone: For the record, this was only an experiment.

A picture is worth a thousand words. Post 102 is worth more.

I’m late to the party, but I think this is the best song. Enjoy!

—Teams Jetrell Fo 1, Jetrell Fo 2, and Jetrell Fo 3

Author
Time

frank678 said:

Wow, so you recoloured a widescreen version using a pan and scan version (?)! Can this script work from single stills?

It works frame-by-frame for all of IP reel #1, at least. Interestingly, it doesn't display the characteristic flicker one would expect.

I IVTC'd the Pan&Scan version, isolated IP reel #1, and then temporally-aligned that to IP reel #1 from GOUT resulting in, of course, all matching frames.

I then applied g-force's RGBMatch to each clip and took some samples.

A picture is worth a thousand words. Post 102 is worth more.

I’m late to the party, but I think this is the best song. Enjoy!

—Teams Jetrell Fo 1, Jetrell Fo 2, and Jetrell Fo 3

Author
Time

frank678 said:

Wow, so you recoloured a widescreen version using a pan and scan version (?)! Can this script work from single stills?

1. Yes

2. I haven't tried yet, but I'm pretty sure it can.

A picture is worth a thousand words. Post 102 is worth more.

I’m late to the party, but I think this is the best song. Enjoy!

—Teams Jetrell Fo 1, Jetrell Fo 2, and Jetrell Fo 3