improved XYB conversion

This commit is contained in:
minjaesong
2025-08-27 01:37:43 +09:00
parent 33e77e378e
commit cda9a34b23
4 changed files with 40 additions and 18 deletions

View File

@@ -684,7 +684,6 @@ DCT-based compression, motion compensation, and efficient temporal coding.
* Enables bitrate-constrained encoding alongside quality modes
* All video frames now include 4-byte rate control factor after payload size
- Version 3.0: Additional support of XYB Colour space
* Increased encoding efficiency, decreased decoding performance
# File Structure
\x1F T S V M T E V

View File

@@ -1656,10 +1656,13 @@ class GraphicsJSR223Delegate(private val vm: VM) {
val x = xBlock[xbIdx]
val b = bBlock[xbIdx]
// Dequantize from integer ranges
val yVal = (y - 128.0) / 255.0
val xVal = x / 255.0
val bVal = b / 255.0
// Optimal range-based dequantization (exact inverse of improved quantization)
val X_MIN = -0.016; val X_MAX = 0.030
val xVal = (x / 255.0) * (X_MAX - X_MIN) + X_MIN // X: inverse of range mapping
val Y_MAX = 0.85
val yVal = (y / 255.0) * Y_MAX // Y: inverse of improved scale
val B_MAX = 0.85
val bVal = (((b - 1.0) + 128.0) / 255.0) * B_MAX // B: inverse of ((val/B_MAX*255)-128+1)
// XYB to LMS gamma
val lgamma = xVal + yVal
@@ -1723,10 +1726,16 @@ class GraphicsJSR223Delegate(private val vm: VM) {
val yVal = (lgamma + mgamma) / 2.0
val bVal = sgamma
// Quantize to integer ranges suitable for TEV
val yQuant = (yVal * 255.0 + 128.0).toInt().coerceIn(0, 255) // Y: 0-255 (like YCoCg Y)
val xQuant = (xVal * 255.0).toInt().coerceIn(-128, 127) // X: -128 to +127 (like Co)
val bQuant = (bVal * 255.0).toInt().coerceIn(-128, 127) // B: -128 to +127 (like Cg, aggressively quantized)
// Optimal range-based quantization for XYB values (improved precision)
// X: actual range -0.016 to +0.030, map to full 0-255 precision
val X_MIN = -0.016; val X_MAX = 0.030
val xQuant = (((xVal - X_MIN) / (X_MAX - X_MIN)) * 255.0).toInt().coerceIn(0, 255)
// Y: range 0 to 0.85, map to 0 to 255 (improved scale)
val Y_MAX = 0.85
val yQuant = ((yVal / Y_MAX) * 255.0).toInt().coerceIn(0, 255)
// B: range 0 to 0.85, map to -128 to +127 (improved precision with +1 offset for yellow-green)
val B_MAX = 0.85
val bQuant = (((bVal / B_MAX) * 255.0) - 128.0 + 1.0).toInt().coerceIn(-128, 127)
// Store XYB values
val yIdx = py * 16 + px

View File

@@ -232,18 +232,32 @@ static void rgb_to_xyb(uint8_t r, uint8_t g, uint8_t b, int *y, int *x, int *xyb
double y_val = (lgamma + mgamma) / 2.0;
double b_val = sgamma;
// Quantize to integer ranges suitable for TEV
*y = CLAMP((int)(y_val * 255.0 + 128.0), 0, 255); // Y: 0-255 (like YCoCg Y)
*x = CLAMP((int)(x_val * 255.0), -128, 127); // X: -128 to +127 (like Co)
*xyb_b = CLAMP((int)(b_val * 255.0), -128, 127); // B: -128 to +127 (like Cg, aggressively quantized)
// Optimal range-based quantization for XYB values (improved precision)
// X: actual range -0.016 to +0.030, map to full 0-255 precision
const double X_MIN = -0.016, X_MAX = 0.030;
*x = CLAMP((int)(((x_val - X_MIN) / (X_MAX - X_MIN)) * 255.0), 0, 255);
// Y: range 0 to 0.85, map to 0 to 255 (improved scale)
const double Y_MAX = 0.85;
*y = CLAMP((int)((y_val / Y_MAX) * 255.0), 0, 255);
// B: range 0 to 0.85, map to -128 to +127 (improved precision with +1 offset for yellow-green)
const double B_MAX = 0.85;
*xyb_b = CLAMP((int)(((b_val / B_MAX) * 255.0) - 128.0 + 1.0), -128, 127);
}
// XYB to RGB transform (for verification)
static void xyb_to_rgb(int y, int x, int xyb_b, uint8_t *r, uint8_t *g, uint8_t *b) {
// Dequantize from integer ranges
double y_val = (y - 128.0) / 255.0;
double x_val = x / 255.0;
double b_val = xyb_b / 255.0;
// Optimal range-based dequantization (exact inverse of improved quantization)
const double X_MIN = -0.016, X_MAX = 0.030;
double x_val = (x / 255.0) * (X_MAX - X_MIN) + X_MIN; // X: inverse of range mapping
const double Y_MAX = 0.85;
double y_val = (y / 255.0) * Y_MAX; // Y: inverse of improved scale
const double B_MAX = 0.85;
double b_val = (((xyb_b - 1.0) + 128.0) / 255.0) * B_MAX; // B: inverse of ((val/B_MAX*255)-128+1)
// Debug print for red color
if (x == 127 && y == 147 && xyb_b == 28) {
printf("DEBUG: Red conversion - Dequantized XYB: X=%.6f Y=%.6f B=%.6f\n", x_val, y_val, b_val);
}
// XYB to LMS gamma
double lgamma = x_val + y_val;

View File

@@ -12,7 +12,7 @@
// XYB conversion constants from JPEG XL specification
static const double XYB_BIAS = 0.00379307325527544933;
static const double CBRT_BIAS = 0.01558; // cbrt(XYB_BIAS)
static const double CBRT_BIAS = 0.155954200549248620; // cbrt(XYB_BIAS)
// RGB to LMS mixing coefficients
static const double RGB_TO_LMS[3][3] = {