Skip to content

Commit

Permalink
IPTPQc2 - combine IPTtoPQLMS reshaping matrices
Browse files Browse the repository at this point in the history
  • Loading branch information
Igor Malinin committed Aug 14, 2021
1 parent 49c2405 commit d1ae57d
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 68 deletions.
21 changes: 11 additions & 10 deletions core/src/main/java/band/full/video/dolby/IPTPQc2.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,19 @@ public final class IPTPQc2 extends ColorMatrix {
public static final IPTPQc2 PQ10IPTc2 = new IPTPQc2(10);
public static final IPTPQc2 PQ12IPTc2 = new IPTPQc2(12);

private static final double[] RESHAPING = {1.0, 2.0, 2.0};

/**
* <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);
public static final Matrix3x3 IPTtoPQLMS = getYCCtoRGB(IPTPQ_YCCtoRGB_coef);

private static final Matrix3x3 IPTtoPQLMS_RESHAPED =
IPTtoPQLMS.multiplyColumns(RESHAPING);

/**
* <pre>
Expand All @@ -51,6 +55,9 @@ public final class IPTPQc2 extends ColorMatrix {
*/
public static final Matrix3x3 PQLMStoIPT = IPTtoPQLMS.invert();

private static final Matrix3x3 PQLMStoIPT_RESHAPED =
IPTtoPQLMS_RESHAPED.invert();

/**
* <pre>
* [ 1.04254, -0.02130, -0.02130]
Expand Down Expand Up @@ -93,10 +100,7 @@ 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];
}
PQLMStoIPT_RESHAPED.multiply(ipt, ipt);
return ipt;
}

Expand All @@ -107,10 +111,7 @@ public double[] toRGB(double[] ipt, double[] 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);
IPTtoPQLMS_RESHAPED.multiply(ipt, rgb);
transfer.toLinear(rgb, rgb);
CROSS_TALK_INVERSE.multiply(rgb, rgb);
return LMStoRGB.multiply(rgb, rgb); // TODO combine with cross talk
Expand Down
138 changes: 80 additions & 58 deletions core/src/test/java/band/full/video/dolby/TestIPTPQc2.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package band.full.video.dolby;

import static band.full.video.dolby.IPTPQc2.IPTtoPQLMS;
import static band.full.video.dolby.IPTPQc2.PQ12IPTc2;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;

Expand All @@ -10,66 +12,75 @@
* @author Igor Malinin
*/
public class TestIPTPQc2 {
private static final IPTPQc2 MATRIX = new IPTPQc2(12);
private final IPTPQc2 cm = PQ12IPTc2;

@Test
public void valuesITPtoPQLMS() {
assertEquals(1.0, IPTtoPQLMS.get(0, 0));
assertEquals(0.009, IPTtoPQLMS.get(0, 1), 1e-3);
assertEquals(0.111, IPTtoPQLMS.get(0, 2), 1e-3);
assertEquals(1.0, IPTtoPQLMS.get(1, 0));
assertEquals(-0.009, IPTtoPQLMS.get(1, 1), 1e-3);
assertEquals(-0.111, IPTtoPQLMS.get(1, 2), 1e-3);
assertEquals(1.0, IPTtoPQLMS.get(2, 0));
assertEquals(0.560, IPTtoPQLMS.get(2, 1), 1e-3);
assertEquals(-0.321, IPTtoPQLMS.get(2, 2), 1e-3);
assertAll(
() -> assertEquals(1.0, IPTtoPQLMS.get(0, 0)),
() -> assertEquals(0.0976, IPTtoPQLMS.get(0, 1), 1e-4),
() -> assertEquals(0.2052, IPTtoPQLMS.get(0, 2), 5e-5),
() -> assertEquals(1.0, IPTtoPQLMS.get(1, 0)),
() -> assertEquals(-0.1139, IPTtoPQLMS.get(1, 1), 5e-5),
() -> assertEquals(0.1332, IPTtoPQLMS.get(1, 2), 5e-5),
() -> assertEquals(1.0, IPTtoPQLMS.get(2, 0)),
() -> assertEquals(0.0326, IPTtoPQLMS.get(2, 1), 5e-5),
() -> assertEquals(-0.6769, IPTtoPQLMS.get(2, 2), 5e-5));
}

@Test
public void valuesFull() {
assertEquals(0, MATRIX.VMIN);
assertEquals(4095, MATRIX.VMAX);
assertEquals(0, MATRIX.YMIN);
assertEquals(4095, MATRIX.YMAX);
assertEquals(1, MATRIX.CMIN);
assertEquals(4095, MATRIX.CMAX);
assertEquals(2048, MATRIX.ACHROMATIC);
assertAll(
() -> assertEquals(0, cm.VMIN),
() -> assertEquals(4095, cm.VMAX),
() -> assertEquals(0, cm.YMIN),
() -> assertEquals(4095, cm.YMAX),
() -> assertEquals(1, cm.CMIN),
() -> assertEquals(4095, cm.CMAX),
() -> assertEquals(2048, cm.ACHROMATIC));
}

@Test
public void fromLumaCode() {
assertEquals(0.0, MATRIX.fromLumaCode(MATRIX.YMIN));
assertEquals(1.0, MATRIX.fromLumaCode(MATRIX.YMAX));
assertAll(
() -> assertEquals(0.0, cm.fromLumaCode(cm.YMIN)),
() -> assertEquals(1.0, cm.fromLumaCode(cm.YMAX)));
}

@Test
public void fromChromaCode() {
assertEquals(-0.5, MATRIX.fromChromaCode(MATRIX.CMIN));
assertEquals(0.5, MATRIX.fromChromaCode(MATRIX.CMAX));
assertEquals(0.0, MATRIX.fromChromaCode(MATRIX.ACHROMATIC));
assertAll(
() -> assertEquals(-0.5, cm.fromChromaCode(cm.CMIN)),
() -> assertEquals(0.5, cm.fromChromaCode(cm.CMAX)),
() -> assertEquals(0.0, cm.fromChromaCode(cm.ACHROMATIC)));
}

@Test
public void toLumaCode() {
assertEquals(MATRIX.YMIN, MATRIX.toLumaCode(0.0));
assertEquals(MATRIX.YMAX, MATRIX.toLumaCode(1.0));
assertAll(
() -> assertEquals(cm.YMIN, cm.toLumaCode(0.0)),
() -> assertEquals(cm.YMAX, cm.toLumaCode(1.0)));
}

@Test
public void toChromaCode() {
assertEquals(MATRIX.CMIN, MATRIX.toChromaCode(-0.5));
assertEquals(MATRIX.CMAX, MATRIX.toChromaCode(0.5));
assertEquals(MATRIX.ACHROMATIC, MATRIX.toChromaCode(0.0));
assertAll(
() -> assertEquals(cm.CMIN, cm.toChromaCode(-0.5)),
() -> assertEquals(cm.CMAX, cm.toChromaCode(0.5)),
() -> assertEquals(cm.ACHROMATIC, cm.toChromaCode(0.0)));
}

@Test
public void black() {
double[] expected = {0.0, 0.0, 0.0};
double[] black = {0.0, 0.0, 0.0};
assertArrayEquals(expected, MATRIX.toRGB(black, black));
assertArrayEquals(expected, MATRIX.toLinearRGB(black, black));
assertArrayEquals(expected, MATRIX.fromRGB(black, black));
assertArrayEquals(expected, MATRIX.fromLinearRGB(black, black));

assertAll(
() -> assertArrayEquals(expected, cm.toRGB(black, black)),
() -> assertArrayEquals(expected, cm.toLinearRGB(black, black)),
() -> assertArrayEquals(expected, cm.fromRGB(black, black)),
() -> assertArrayEquals(expected,
cm.fromLinearRGB(black, black)));
}

@Test
Expand All @@ -78,8 +89,9 @@ public void gray() {
double[] rgb = {0.5, 0.5, 0.5};
double[] itp = {0.5, 0.0, 0.0};

assertColorEquals(0.5, 0.5, 0.5, MATRIX.toRGB(itp, tmp));
assertColorEquals(0.5, 0.0, 0.0, MATRIX.fromRGB(rgb, tmp));
assertAll(
() -> assertColorEquals(0.5, 0.5, 0.5, cm.toRGB(itp, tmp)),
() -> assertColorEquals(0.5, 0.0, 0.0, cm.fromRGB(rgb, tmp)));
}

@Test
Expand All @@ -88,61 +100,71 @@ public void white() {
double[] rgb = {1.0, 1.0, 1.0};
double[] itp = {1.0, 0.0, 0.0};

assertColorEquals(1.0, 1.0, 1.0, MATRIX.toRGB(itp, tmp));
assertColorEquals(1.0, 1.0, 1.0, MATRIX.toLinearRGB(itp, tmp));
assertColorEquals(1.0, 0.0, 0.0, MATRIX.fromRGB(rgb, tmp));
assertColorEquals(1.0, 0.0, 0.0, MATRIX.fromLinearRGB(rgb, tmp));
assertAll(
() -> assertColorEquals(1.0, 1.0, 1.0, cm.toRGB(itp, tmp)),
() -> assertColorEquals(1.0, 1.0, 1.0,
cm.toLinearRGB(itp, tmp)),
() -> assertColorEquals(1.0, 0.0, 0.0, cm.fromRGB(rgb, tmp)),
() -> assertColorEquals(1.0, 0.0, 0.0,
cm.fromLinearRGB(rgb, tmp)));
}

private void assertColorEquals(double c0, double c1, double c2,
double[] actual) {
assertEquals(c0, actual[0], 1e-15);
assertEquals(c1, actual[1], 1e-15);
assertEquals(c2, actual[2], 1e-15);
assertAll(
() -> assertEquals(c0, actual[0], 7e-5),
() -> assertEquals(c1, actual[1], 7e-5),
() -> assertEquals(c2, actual[2], 7e-5));
}

@Test
public void red() {
symmetry(0.5, 0.0, 0.0);
symmetry(1.0, 0.0, 0.0);
assertAll(
() -> symmetry(0.5, 0.0, 0.0),
() -> symmetry(1.0, 0.0, 0.0));
}

@Test
public void green() {
symmetry(0.0, 0.5, 0.0);
symmetry(0.0, 1.0, 0.0);
assertAll(
() -> symmetry(0.0, 0.5, 0.0),
() -> symmetry(0.0, 1.0, 0.0));
}

@Test
public void blue() {
symmetry(0.0, 0.0, 0.5);
symmetry(0.0, 0.0, 1.0);
assertAll(
() -> symmetry(0.0, 0.0, 0.5),
() -> symmetry(0.0, 0.0, 1.0));
}

private void symmetry(double r, double g, double b) {
symmetryE(r, g, b);
symmetryO(r, g, b);
assertAll(
() -> symmetryE(r, g, b),
() -> symmetryO(r, g, b));
}

private void symmetryE(double r, double g, double b) {
double[] rgb = {r, g, b};

MATRIX.fromRGB(rgb, rgb);
MATRIX.toRGB(rgb, rgb);
cm.fromRGB(rgb, rgb);
cm.toRGB(rgb, rgb);

assertEquals(r, rgb[0], 5e-6);
assertEquals(g, rgb[1], 5e-6);
assertEquals(b, rgb[2], 5e-6);
assertAll(
() -> assertEquals(r, rgb[0], 6e-6),
() -> assertEquals(g, rgb[1], 6e-6),
() -> assertEquals(b, rgb[2], 6e-6));
}

private void symmetryO(double r, double g, double b) {
double[] rgb = {r, g, b};

MATRIX.fromLinearRGB(rgb, rgb);
MATRIX.toLinearRGB(rgb, rgb);
cm.fromLinearRGB(rgb, rgb);
cm.toLinearRGB(rgb, rgb);

assertEquals(r, rgb[0], 5e-13);
assertEquals(g, rgb[1], 5e-13);
assertEquals(b, rgb[2], 5e-13);
assertAll(
() -> assertEquals(r, rgb[0], 5e-13),
() -> assertEquals(g, rgb[1], 5e-13),
() -> assertEquals(b, rgb[2], 5e-13));
}
}

0 comments on commit d1ae57d

Please sign in to comment.