-
Notifications
You must be signed in to change notification settings - Fork 10
/
IPTPQc2.java
122 lines (105 loc) · 3.62 KB
/
IPTPQc2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package band.full.video.dolby;
import static band.full.video.dolby.VdrDmDataPayload.IPTPQ_YCCtoRGB_coef;
import static band.full.video.dolby.VdrDmDataPayload.IPTPQc2_RGBtoLMS_coef;
import static band.full.video.dolby.VdrDmDataPayload.getRGBtoLMS;
import static band.full.video.dolby.VdrDmDataPayload.getYCCtoRGB;
import static band.full.video.itu.ColorRange.FULL;
import static band.full.video.itu.ICtCp.LMStoRGB;
import static band.full.video.itu.ICtCp.RGBtoLMS;
import band.full.core.color.Matrix3x3;
import band.full.core.color.Primaries;
import band.full.video.itu.BT2020;
import band.full.video.itu.ColorMatrix;
import band.full.video.smpte.ST2084;
/**
* Encoding/decoding of <em>RGB</em> values to/from Dolby Vision profile 5
* <em>IPTPQc2</em> color space.
* <p>
* This color matrix has reshaping state so is not thread safe and cannot be
* shared. Create an instance for each encode.
*
* @author Igor Malinin
*/
public final class IPTPQc2 extends ColorMatrix {
public static final ST2084 PQ = new ST2084(2, "DVp5");
public static final Primaries PRIMARIES =
new Primaries(2, BT2020.PRIMARIES);
public static final IPTPQc2 PQ10IPTc2 = new IPTPQc2(10);
public static final IPTPQc2 PQ12IPTc2 = new IPTPQc2(12);
/**
* <pre>
* [1.0, 0.09753, 0.20520]
* [1.0, -0.11389, 0.13318]
* [1.0, 0.03259, -0.67688]
* </pre>
*/
public static final Matrix3x3 IPTtoPQLMS =
getYCCtoRGB(IPTPQ_YCCtoRGB_coef);
/**
* <pre>
* [0.40013, 0.39989, 0.19998]
* [4.45534, -4.85146, 0.39612]
* [0.80567, 0.35718, -1.16285]
* </pre>
*/
public static final Matrix3x3 PQLMStoIPT = IPTtoPQLMS.invert();
/**
* <pre>
* [ 1.04254, -0.02130, -0.02130]
* [-0.02124, 1.04254, -0.02130]
* [-0.02130, -0.02130, 1.04254]
* </pre>
*/
public static final Matrix3x3 CROSS_TALK_INVERSE =
getRGBtoLMS(IPTPQc2_RGBtoLMS_coef);
/**
* <pre>
* [0.9600, 0.0200, 0.0200]
* [0.0200, 0.9600, 0.0200]
* [0.0200, 0.0200, 0.9600]
* </pre>
*/
public static final Matrix3x3 CROSS_TALK = CROSS_TALK_INVERSE.invert();
// TODO enable pivots and full polynomials
// currently only first order polynomial scaling supported
public final double[] reshaping;
public IPTPQc2(int bitdepth) {
this(bitdepth, 1.0, 2.0, 2.0);
}
public IPTPQc2(int bitdepth, double... reshaping) {
super(2, PQ, PRIMARIES, bitdepth, FULL);
this.reshaping = reshaping;
}
@Override
public double[] fromRGB(double[] rgb, double[] ipt) {
return fromLinearRGB(transfer.toLinear(rgb, ipt), ipt);
}
@Override
public double[] fromLinearRGB(double[] rgb, double[] ipt) {
RGBtoLMS.multiply(rgb, ipt); // TODO combine with cross talk
CROSS_TALK.multiply(ipt, ipt);
transfer.fromLinear(ipt, ipt);
PQLMStoIPT.multiply(ipt, ipt);
for (int i = 0; i < 3; i++) {
ipt[i] /= reshaping[i];
}
return ipt;
}
@Override
public double[] toRGB(double[] ipt, double[] rgb) {
return transfer.fromLinear(toLinearRGB(ipt, rgb), rgb);
}
@Override
public double[] toLinearRGB(double[] ipt, double[] rgb) {
for (int i = 0; i < 3; i++) {
rgb[i] = ipt[i] * reshaping[i];
}
IPTtoPQLMS.multiply(rgb, rgb);
transfer.toLinear(rgb, rgb);
CROSS_TALK_INVERSE.multiply(rgb, rgb);
return LMStoRGB.multiply(rgb, rgb); // TODO combine with cross talk
}
public static void main(String[] args) {
System.out.println(CROSS_TALK.toString());
}
}