AVS Forum banner
  • Everything You Wanted to Know About HDMI Cables. Ep. 7 of the AVSForum Podcast is now live. Click here for details.

Color Correction with a HTPC - Simpler solution and now it really works!

225K views 461 replies 71 participants last post by  Grimmy84  
#1 ·
Post changed to reflect the results of the discussion bellow with zoyd and JohnAd.


I would like to thank zoyd for testing my previous solution, with the same results as mine, and helping me find the error. I also would like to thank JohnAd for suggesting the use of mplayerc and its shader support for performing the color correction. He has also wrote the shader code presented here for performing the color correction, so a big part of the credits should go to him. Finally, I would like to thank to the authors of the color articles I point to.


I have been working to find a way for correcting the image of a display with oversaturated primaries using a HTPC. We will try to correct the image to have the colors as close as possible to the sourcing standard, within our display's color gamut. For this we will use mplayerc (Media Player Classic) which is available to anyone for free.


Before I start, I would like to tell you that I am not an expert in color science. In case anything is wrong, feel free to correct me and I will update this thread accordingly.

Technical details:

I will not be very extensive here. In Charles Poynton's ColorFAQ page there are two documents that explains all the basics about color and color conversion: the ColorFAQ.pdf and the Colour Space Conversions .


It is possible to convert an image captured in a RGB color space with a color gamut defined by a set of primaries, to a color gamut defined by a different set of primaries. For the conversion being without any color loss, the second color gamut should contain entirely the first color gamut (Display with oversaturated primaries - see note 1). In case the second color gamut is contained in the entire first color gamut, you can still use this solution to get accurate colors, but you would never achieve the colors that are out of the gamut (Display with undersaturated primaries - see note 2). The more usual situation is the first.


What we want is converting the colors captured with BT.709, EBU, SMPTE-C or any other source primaries color gamut (the standards used for coding the material) to our display's primaries color gamut.


My first step was writing a little matlab file for calculating these conversion matrices.


In the PC, the RGB data we have is all at the non-linear domain (called R'G'B'), and the conversion between primaries should be done at the linear domain (called RGB). So, for performing the color correction, we have to convert from R'G'B'->RGB, apply the conversion matrix and then convert back from RGB->R'G'B' - our displays need R'G'B'. Since in this process we have the RGB data at the linear domain, we could also correct the gamma accordingly to our displays gamma curve, in case you could not correct it in the display itself.


Solved the problem theoretically, we just need to find a way of doing it...

How to do it:

1a-Update your DirectX runtime for the latest version. Go here .

1b-Download and install mplayerc with shader support. You can get it here . I use Casimirs version: MPC Homecinema.

2-Run mplayerc.

3-Select View->Shader Editor

4-In the top field write the name you want for the shader (I used Color Correction BT.709) and click Enter for adding the new shader entrance.

5-In the field on the right of the name select ps_2_0

6-In the space bellow these two fields, copy and paste the following code:

Code:
Code:
sampler s0 : register(s0);
float4 p0 : register(c0);

static float4x4 r2r =
{
\t0.8634, 0.1515, -0.0149, 0,
\t-0.0083, 0.9484, 0.0599, 0,
\t0.02446, 0.0312, 0.9444, 0,
\t0, 0, 0, 0
};

float4 main(float2 tex : TEXCOORD0) : COLOR
{
    float4 c0 = tex2D(s0, tex);
    c0 = pow(c0, 1/0.45);
    c0 = mul(r2r, c0);
    c0 = saturate(c0);
    c0 = pow(c0, 0.45);

    return c0;
}
It should look like this: Attachment 92193

7-copy your matrix into the code (see "Creating the matrix", bellow)

8-Repeat steps 4 to 7 if you want to color correct other source types, like BT.601 EBU (PAL) or BT-601 SMPTE-C (current NTSC)

9-Go to View->Options->Playback->Output and select:

-DirectShow Video: VMR9(Renderless)

-Surface: 3D Surfaces

It should look like this: Attachment 92192

10-Play your video

11-Go to Play->Shaders and select the shader you want


This method is great because you could pause the image and toggle (Ctrl+P) the shader to see its effect on the image. Also, all the calculations for the correction are done in your graphic cards GPU, not needing more CPU power.

Gamma correction:

If you can not adjust your display's gamma curve and it's not the standard value (1/0.45), you can correct it with this method.

The last line of the shader code:
Code:
Code:
c0 = pow(c0, 0.45);
converts the RGB data again to the R'G'B' using a power function. By default, it uses the standard power function for BT.709.

Changing the power function, you can obtain R'G'B' data that better fits your display and viewing environment.

According to Poynton's gamma faq here , when you view your display in a dim surround, you should use a power function with a coefficient slightly higher than 1/gamma, he suggests 1.13/gamma. If you view your display in a lit surround, you should use a coefficient toward 1/gamma. You can play a little with this number and see which will please you more. You can even create different shaders for daytime viewing and nightime viewing.


Example:

Your display has a gamma of 1.9.

If you use a lit environment for your viewings (daytime), the last line, in your case, should be:
Code:
Code:
c0 = pow(c0, 1/1.9);
If you use a dim environment for your viewings (evening or light controlled room), the last line, in your case, should be:
Code:
Code:
c0 = pow(c0, 1.13/1.9);
Creating the matrix:

If you know your display primaries coordinates, you can calculate the matrices needed for color correcting your display.

JohnAd provided this excel file: Attachment 92415 which calculates and outputs the matrix and the shader code ready to use in mplayerc.

You should create a shader for each source you will use. In general, you would want BT.709 and BT.601 EBU or BT.709 and BT.601 SMPTE-C. Not all people see both PAL and NTSC material.


If you don't have a colorimeter to measure your display's primaries coordinates, look at this file: Attachment 92245

I have calculated the matrices for some displays I knew the coordinates.

Note: Even if you have any of the displays indicated in the file, it doesn't mean your will have the same coordinates, but probably it will be close enough...


Here is an example for BT.709 sources with projector JVC RS1/HD1:
Code:
Code:
BT.709
 0.9347627,  0.0563391,  0.0088982
 0.0298623,  0.9461880,  0.0239497
 0.0160549,  0.1037023,  0.8802428
Now, let's change the matrix for using it in the shader. Remember we must add a 4th row and 4th column with all zeros.
Code:
Code:
0.9347627,  0.0563391,  0.0088982, 0,
 0.0298623,  0.9461880,  0.0239497, 0,
 0.0160549,  0.1037023,  0.8802428, 0,
 0, 0, 0, 0
Just copy the corrected matrix in the shader code.


If you want, you could post here your coordinates and I will calculate the matrices for you and update the file above.


That's All.


As the title says, this could be done to any display you have. If you know your display's primaries coordinates and your source coding standard, you could correct the image to get accurate colors. If you don't know it, you could try to improve your image with some trial and error, but it would be very difficult to get accurate colors.


It would be great if some of you could test this solution and report about it. If you also could post some pics with a before and after would be great!


The fact that I have found this solution does not mean that I think we should correct the colors or that the "wrong" colors bother me. I just think that we should be able to see and decide for ourselves.



Note 1: Since we will have to "shrink" the display's color gamut to have the same size of the source one, there will be less bit steps available, because the full level [0:255] will correspond only to the full display's color gamut. For example: with the shrinking, the full red which is [255,0,0] will be converted to [247,52,40] (BT.709 and RS1 display). This means loosing some color levels and the possibility of appearing a slightly amount of banding, due to the current PC limitation of 8-bit color depth..


Note 2: We will need to "expand" the display's color gamut to have the same size of the source one, but this is not possible, because we cannot go outside of the display's color gamut. We can still have the accurate colors that lie inside the display's color gamut, but for the colors outside it would appear as a severe color "crush". It's not very wise to color correct in this situation...


Note 3: In reality, the conversion matrix is 3x3, but because the shader uses 4x4 matrices, we have to add a 4th column and a 4th row with all zeros, like in the example code. To know how to calculate and select the correct matrices, see next post.



 

cc_mat.txt 2.0859375k . file

 

ColourCorrection.zip 9.7255859375k . file
 

Attachments

#2 ·
Here are the results of some tests I have made to my projector using colorfacts and test patterns from dvd DVE (Tit. 14, ch 8-10, R,G,B full screens). The idea of these tests was confirming the primaries coordinates correction in the color corrected image.


My projector is a JVC M15. The primaries coordinates are:
R [0.6682 0.3283]; G [0.2734 0.6762]; B [0.1409 0.0552]


Here are the CIE charts of my projector using BT.709 and EBU primaries color gamut as a reference: Attachment 92246 and Attachment 92247

The outer triangle is my projector's color gamut. The inner triangle is the source standard color gamut. The white circles over the vertices of the inner triangle are my projector's primaries after the color correction with the method described above. You could see that are almost spot on!


These were the primaries coordinates measured with the EBU color correction:
R [0.6439 0.3293]; G [0.2892 0.6073]; B [0.1492 0.0591]

The EBU primaries coordinates are:
R [0.6400 0.3300]; G [0.2900 0.6000]; B [0.1500 0.0600]


I will add later some pictures with some movie images to see the effect.

 
#3 ·
Interesting thread, thank you!

Do you think, by any chance, if this could work with Powerdvd ultra (which operates in Overlay not VMR9)?
 
#4 ·
If you could use ffdhow with powerdvd it should work, ffdshow supports overlay, but I think powerdvd does not work with ffdshow. I have tryed it and it did not work.


If you are asking this because you want to use gpu accelaration, forget ffdshow, you only can use it with software decoding.


But there is still a possibility... If the graphic card makers would give us the possibility of specifying the YUV-RGB decoding matrix through the drivers, we could use the matrices calculated here. Since the correction would be done at the graphics card drivers, you would then be able to use everything you want: overlay, vmr9, evr, gpu acceleration, etc.


We could ask for it, but I believe this would never happen. It could be the source of lots of problems to them...
 
#5 ·
Good idea and good thread. One caveat to be very careful of is using 8-bit video to correct 8-bit video. It would be great if we could output more than 8-bits so we did not lose any colors. However, if you are limited to 8-bits, you will lose colors via this method.


Bill
 
#6 ·
Yes, I mencioned it in my note 1.


This solution is not the ideal one - that would be the display having accurate primaries - it's the possible one with our current PCs and software. It would be great if in a near future we could have desktop resolutions with more than 8 bit per color primary, but I think the problem is no OS support for it... there are already displays that support more than 8 bit video at the input.
 
#8 ·
You actually need two matrix transforms for SD and HD - for SD you need to subset SMPTE-C inside REC709 - since some HTPC software expands fully to sRGB which is the same as REC709.


Then you need the other transform to subset REC709 inside your display.


I figured there would be a way to do it if the HTPC geeks got on the ball.


Yes you might see banding/dithering/clipping - but for the first time you would see accurate color. Once you have watched it for two weeks - you cannot go back. Then you can join the crowd demanding proper solutions.
 
#10 ·

Quote:
Originally Posted by smyth22 /forum/post/11714406


Does this mean you would need an HD and blu ray drive in an HTPC to make this work for an HD DVD source? Thanks for your really fine work yesgrey3.

If you could find a way of feeding the HD-DVD or Blu-Ray player output signal to a PC and pass it through ffdshow, you would not need a PC drive, but I believe it should be cheaper buying a PC drive.


If we could have this feature in our graphics card drivers, would make the things easier and faster!
 
#11 ·

Quote:
Originally Posted by yesgrey3 /forum/post/11714611


If we could have this feature in our graphics card drivers, would make the things easier and faster!

The math would be pretty trivial, but first we need 10-bit pipes.


Bill
 
#12 ·
I'm probably missing something, but doesn't ATI claim full 10bit processing? I thought it was possible to output 10bit 4:2:2 from an ATI card...


The problem I presume is accessing the 10 bit pipe when most apps assume 8 bit.


From the ATI site for the 2600 series under Display output:

"Each (output) supports 18-, 24-, and 30-bit digital displays at all resolutions up to 1920x1200 (single-link DVI) or 2560x1600 (dual-link DVI)"


From the "display controllers" section.

"# Full 30-bit display processing

# Programmable piecewise linear gamma correction, color correction, and color space conversion

# Spatial/temporal dithering provides 30-bit color quality on 24-bit and 18-bit displays"

http://ati.amd.com/products/Radeonhd2600/specs.html
 
#13 ·
Looks promising. You would essentially need to create a 10-bit profile to remap colors and tie that into the video card or DirectShow filters. The latter is where this thread seems headed. The former may be easier.


Bill
 
#14 ·

Quote:
Originally Posted by krasmuzik /forum/post/11713695


You actually need two matrix transforms for SD and HD - for SD you need to subset SMPTE-C inside REC709 - since some HTPC software expands fully to sRGB which is the same as REC709.


Then you need the other transform to subset REC709 inside your display.

From reading the pdf files about color, this was my understanding of it:

-HD: is mastered with BT.709 primaries and using BT.709 coefficients.

For seeing this material you have to select "PC.709" or "rec709" in the avisynth command line.


-SD: is mastered with SMPTE-C or EBU primaries and using BT.601 coefficients.

For seeing this material you have to select "PC.601" or "rec601" in the avisynth command line, and download the respective avisynth.dll file.


I have created two versions: one with BT.601 and EBU primaries and another with BT.601 and SMPTE-C primaries. The BT.709 is the same in both files, because the HDTV standard is the same for all parts of the world.


Please correct me if any of my assumptions are wrong.
 
#15 ·
Here are the results of some tests I have made to my projector using colorfacts and test patterns from dvd DVE (Tit. 14, ch 8-10, R,G,B full screens). The idea of these tests was confirming the primaries coordinates correction in the color corrected image.


My primaries in the CIE chart:
Attachment 90453

coordinates:
R:[0.6682,0.3283]; G:[0.2734,0.6762]; B:[0.1409,0.0552]


First, I tested without any color correction to see which matrix mode to use. The correct matrix mode should give RGB coordinates that match the display primaries.


Using reference avisynth.dll (without color correction):

-matrix="PC.709"

coordinates:
R:[0.6609,0.3339]; G:[0.2650,0.6801]; B:[0.1418,0.0585]


-matrix="PC.601"

coordinates:
R:[0.6664,0.3283]; G:[0.2699,0.6776]; B:[0.1419,0.0551]


-matrix="rec601"

coordinates:
R:[0.6683,0.3282]; G:[0.2731,0.6764]; B:[0.1409,0.0551]


Conclusion: This dvd was mastered with BT.601. A very curious thing was getting accurate colors with the rec601 mode, which means converting Y [16:235] -> RGB [0:255]. When I used the PC.601, which means converting Y [0:255] -> RGB [0:255], the colors were not accurate.


Now using jvc_m15_avisynth26_corr_pal (with color correction):

-matrix="rec601"

coordinates:
R:[0.6674,0.3280]; G:[0.2744,0.6731]; B:[0.1418,0.0538]

It should be the EBU primaries coordinates...


Conclusion: I was very disapointed. I passed all day redoing the calculations, thinking I have made any mistake. No, it's everything correct. The problem is my projector gamma curve saturates at the top, so at very bright levels all the images are almost the same. In my case, the correction will have no effect at 80 IRE.


The EBU primary green in my projector is at RGB=[29,250,19], which is just too bright to notice any difference, compared to RGB=[0,255,0], with my gamma curve.


Note:

EBU primaries coordinates:
R:[0.6400,0.3300]; G:[0.2900,0.6000]; B:[0.1500,0.0600]


Edit: In fact, the problem was not the gamma curve saturating at the top IRE. The problem was doing the correction in the non-linear R'G'B' domain and not in the linear RGB as it should. With the correction done in the linear RGB domain, everything is correct, as you can see in my post #2 - edited with the test results of the new method. The correct EBU primary green in my projector is at [95,253,80] and not at [29,250,19] as stated above.
 
#16 ·
Getgrey3: Have you tried to look at dvds before and after your adjustments which display the saturation issue; I think Seabiscut was one and there were other examples in the RS1 thread. I am just wondering is there is improvement despite the < 20 IRE and > 80 IRE issue. Also would adjusting those parts of the gamma curve allow you tosolve your problem and is that possible with the software you are using or another product? I dont know enough about the interactions at work here to know if that is feasible. GOod luck with you experiments.
 
#17 ·
I will recalibrate my projector with Dilard to see if I could get a better gamma curve. I have changed my PC recently and my previous calibration was done with the old PC. After that I will try to capture some images and posting it, but remember I don't have a RS1. It would be great if someone with a RS1 could post some pics.
 
#19 ·

Quote:
Originally Posted by reio-ta /forum/post/11727335


Are there any video cards which output, DVI or HDMI 10-bit per channel(30-bit RGB) 4:2:2? Also, how would you do it?


Is that true?


The "Spatial/temporal dithering provides 30-bit color quality on 24-bit and 18-bit displays" could mean it does 30-bit internal and outputs as either 24 or 18 bit only? What's the "dithering" about too? Not true 30-bit? Or is it doing both? Dithering on 24 and 18 bit displays, and true 30-bit on 30-bit displays?

Well, I haven't tested it myself, which is why I asked in this thread. ATI certainly claims their cards do output 30 bit, but I'm not up on the latest HTPC developments. The way I read it, dithering is for displays which cannot accept a 30 bit input. Hopefully someone will confirm. At the very least it's promising that we can get banding-free 30 bit output or at least properly dithered 24 bit output.
 
#20 ·

Quote:
Originally Posted by smyth22 /forum/post/11731115


Sorry I missed that you did not have an RS1; that makes your efforts even more praiseworthy.

This is a solution for all displays that could be used with a HTPC. The only requirement is a PC with enough CPU power to run ffdshow. For SD it would be easy, but for HD you would need a better CPU, because the H.264 conversion have to be done in software when you use ffdshow.


Lots of projectors previous to RS1 had also this problem. The RS1 only was the first to be noted. When you aproach the perfection, the smaller imperfections are revealed.
Image



Added files for a SIM2 C3X by a forum member request.
 
#21 ·

Quote:
Originally Posted by yesgrey3 /forum/post/11733251


The only requirement is a PC with enough CPU power to run ffdshow. For SD it would be easy, but for HD you would need a better CPU, because the H.264 conversion have to be done in software when you use ffdshow.

Can't you decode with CoreAVC and feed the raw data to ffdshow?
 
#23 ·
I really like the ffdshow program. Very nice to use.
 
#25 ·
That would be the best solution. I have looked at it but it appeared to be a very simple thing and not the right way of doing it. In the NVidia control panel you could restrict the output of each channel, but for remapping the colors to a color gamut with different primaries you need to multiply the RGB values by a 3x3 matrix, which means that the RGB channels in the output color gammut will depend on all channels, and not only on the respective channel.

Now if the drivers would allow us to use such a correction matrix, that would be a different story!...


If I am missing some point please feel free to correct me.
Image
 
#26 ·
A brief Google reveals that nVidia drivers can be set up to use ICC color profiles created with various display profiling tools. An ICC profile can be far more capable than a 3x3 matrix, but the quality of profiles varies according to the tool you use to create them. This is old stuff - serious photographers using Photoshop have been doing it for many years to control both their displays and their printers.


Take a look at this Wikipedia article .