Joegenco / PixelManager

Tries to manage pixels colors
142 stars 13 forks source link

Some Log Encodings could have used OCIO's LogCameraTransform #7

Closed EaryChow closed 1 year ago

EaryChow commented 1 year ago

OCIO has a LogCameraTransform function.

I see some spaces using the function, but not all, not sure why this is the case.

Apple Log for example,

EDIT: I deleted the Apple Log example since I noticed after posting this issue that the lower part is also curved. You can still see the content in edit history.

Fuji's F-Log: image

        - !<LogCameraTransform> {base: 10, log_side_slope: 0.344676, log_side_offset: 0.790453, lin_side_slope: 0.555556, lin_side_offset: 0.009468, lin_side_break: 0.00089}

Fuji F-Log2: ef8298f098654dd76abcd2c20c26fb4a

        - !<LogCameraTransform> {base: 10, log_side_slope: 0.245281, log_side_offset: 0.384316, lin_side_slope: 5.555556, lin_side_offset: 0.064829, lin_side_break: 0.000889}

Etc.

You can go check the white paper for each of the Logs, they are usually publically available.

Though note there are exceptions, this function can only work if the lower segment of the curve is linear, if both parts are curved, we would have to use LUT. Example is Nikon N-Log: image

Both parts are curved, and the break point is very high, higher than middle grey. In this case it is impossible to do N-Log correctly with this function. So double check to make sure whether the Log curve fits the use case of this function. A lot of the curves do.

Joegenco commented 1 year ago

Well, simply put I did not know how to put the log function together. I used log functions that I could find and I know they are correct.

I used LUTs for the functions I did not know how to construct but could export a 2_Linear LUT for.

Now I know how! Thank you for thoroughly explaining. I just gained incredibly valuable knowledge.

Canon and Nikon most-likely will stay as a LUT (Canon being baked-in lut in OCIO) since like you mentioned, they are not quite possible to do with the

Ill be implementing these and once I do, I will close this issue.

Joegenco commented 1 year ago

I cannot figure this out.

Cannot find any documentation for ProtuneLog.

I found D-Log and also realized X5, X7 and X9 use the same D-Log curve but cannot write the function myself. image What is 0.584555 in this case?

(while searching for this found out that D-LOG-m is just D-Log with ITU709 matrix.

Also found Apple-Log however this seems like its like N-Log and cannot be put on formula. image

_And heres something funny I stumbled accross, just push the saturation slider the doc says._

EaryChow commented 1 year ago

What is 0.584555 in this case?

log offset I believe? I understand the "slope" to be a multiplier, "offset" to be addend, log slope/offset is applied to the entire log operation's result, while linear slope/offset is applied to the part within the log() parentheses. This is how I understand it anyways. OCIO is not doing a good job at documenting their functions.

Also found Apple-Log however this seems like its like N-Log and cannot be put on formula.

Yeah that's why I deleted the example from the first post. Honestly the break point is low enough that it's very close. But yeah it's not 100% correct on the lower end to assume linear in this case.

The official Apple Log LUT is strangely a 3x1D LUT though, with three columns being completely the same. Might as well be a simple 1D LUT. Here is the simple 1D LUT with the same file size but three times the resolution, generated by directly copying the math formula to Python: Apple_Log_EOTF.spi1d.txt

Just delete txt at the end, GitHub cannot upload LUTs to posts.

And heres something funny I stumbled accross, just push the saturation slider the doc says.

Apparently that doc was not meant for an OCIO style workflow.

EaryChow commented 1 year ago

Tried filling in the function for D-Log:

        - !<LogCameraTransform> {base: 10, log_side_slope: 0.256663, log_side_offset: 0.584555, lin_side_slope: 0.9892, lin_side_offset: 0.0108, lin_side_break: 0.0078}

Somehow the result didn't match the LUT you are using. Also tried to generate a LUT from python (again by directly copying the math from PDF to python script): D_Log_EOTF.spi1d.txt

The result matches with my LUT. I am a bit confused, where did you get the LUT in the current repo if it was not generated from the math formula in the white paper?

Joegenco commented 1 year ago

Apple Lut I have is "official" too from their Dev site. Ill swap it with yours.

Used this for the D-Log and ProTune. https://cameramanben.github.io/LUTCalc/LUTCalc/index.html Might be outdated.

EaryChow commented 1 year ago

Cannot find any documentation for ProtuneLog.

Me neither, but I found this from colour python package I haven't tested it, might be worth trying and comparing. If they don't match, might be worth investigating where the two parties get their source from.

If you want to try generating LUT from python, you can use this script as boilerplate (edit: just committed some cleanups and corrections. Feel free to use it now)

Joegenco commented 1 year ago

Aha, found the funtion for ProTune from ACES 1.0.3 repo.

    def protune_to_linear(normalized_code_value):
        c1 = 113.0
        c2 = 1.0
        c3 = 112.0
        linear = ((pow(c1, normalized_code_value) - c2) / c3)

Turned it into this using your boilerplate py and generated a lut from it. However I have feeling this can be written as a function for OCIO and not a LUT, is that right?

import colour
import numpy

def Protune_Log_Curve(x):
    c1 = 113.0
    c2 = 1.0
    c3 = 112.0
    curve = ((pow(c1, x) - c2) / c3)

    return curve

x_input = numpy.linspace(0.0, 1.0, 4096)
y_LUT = Protune_Log_Curve(x_input)

LUT_name = "Protune_Log_Curve_EOTF"
LUT_safe = LUT_name.replace(" ", "_")
LUT = colour.LUT1D(
    table=y_LUT,
    name=LUT_safe
)

colour.io.luts.write_LUT(LUT, "{}.spi1d".format(LUT_safe), method="Sony SPI1D")

Thank you very much for the scirpt! Appriciate it very much :)

EaryChow commented 1 year ago

Did a bit of a search trying to find where ACES got the source from, I found the answer here in a forum post

I believe the forum post comfirmed that GoPro never released any official info about the encoding, the one in ACES was just some individuals doing "experimental transform" on a blackbox camera encoding.

Looking at the formula, it indeed can be put into a built-in function, if we inverse the EOTF math, we get this: encoding = log113(linear * 112 + 1)

        - !<LogAffineTransform> {base: 113, log_side_slope: 1, log_side_offset: 0, lin_side_slope: 112, lin_side_offset: 1}

Though worth noting that the ProTune encoding doesn't seem to have any higher dynamic range information, I honestly don't see a benefit in using the encoding in the first place.

Joegenco commented 1 year ago

This look very odd to me, I will postphone implementing protune "correctly" until i can get my hands on a gopro and do some testing myself.

Thank you so much for your help!