From 4adaa05bcb472d0bb39fbedc0898ab71ad74c844 Mon Sep 17 00:00:00 2001 From: Jarek Sacha Date: Thu, 23 Mar 2023 20:58:30 -0400 Subject: [PATCH] Refactoring - do not relay on value convention, check RGB type --- .../color/converter/RGBWorkingSpace.scala | 70 ++++----------- .../color/converter/ColorConverter.scala | 85 +++++++++++-------- 2 files changed, 67 insertions(+), 88 deletions(-) diff --git a/ijp-color/src/main/scala-3/ij_plugins/color/converter/RGBWorkingSpace.scala b/ijp-color/src/main/scala-3/ij_plugins/color/converter/RGBWorkingSpace.scala index ff6506d..fd0576c 100644 --- a/ijp-color/src/main/scala-3/ij_plugins/color/converter/RGBWorkingSpace.scala +++ b/ijp-color/src/main/scala-3/ij_plugins/color/converter/RGBWorkingSpace.scala @@ -1,6 +1,6 @@ /* * Image/J Plugins - * Copyright (C) 2002-2022 Jarek Sacha + * Copyright (C) 2002-2023 Jarek Sacha * Author's email: jpsacha at gmail dot com * * This library is free software; you can redistribute it and/or @@ -249,17 +249,23 @@ enum RGBWorkingSpace( gamma = 2.2 ) - /** sRGB */ + /** + * sRGB + * + * Note: The gamma of sRGB is not exactly 2.2, but rather, is a grafting together of two different functions, + * that when viewed together, may be approximated by a simple 2.2 gamma curve. + * See [[http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html Bruce Lindbloom's RGB Working Space Information]] + */ case sRGB - extends RGBWorkingSpace( - "sRGB", - xR = 0.64, - yR = 0.33, - xG = 0.30, - yG = 0.60, - xB = 0.15, - yB = 0.06, - refWhite = D65, + extends RGBWorkingSpace( + "sRGB", + xR = 0.64, + yR = 0.33, + xG = 0.30, + yG = 0.60, + xB = 0.15, + yB = 0.06, + refWhite = D65, gamma = -2.2 ) @@ -307,48 +313,6 @@ enum RGBWorkingSpace( ).transpose val xyz2rgb: Matrix3x3 = rgb2xyz.inverse - - /** Convert a value in this RGB color space to XYZ with the same reference white. */ - def convertRGB2XYZ(r: Double, g: Double, b: Double): XYZ = { - val r1 = invCompand(r) - val g1 = invCompand(g) - val b1 = invCompand(b) - - val x = r1 * rgb2xyz.m00 + g1 * rgb2xyz.m10 + b1 * rgb2xyz.m20 - val y = r1 * rgb2xyz.m01 + g1 * rgb2xyz.m11 + b1 * rgb2xyz.m21 - val z = r1 * rgb2xyz.m02 + g1 * rgb2xyz.m12 + b1 * rgb2xyz.m22 - - XYZ(x, y, z) - } - - final private def invCompand(companded: Double): Double = { - if (gamma > 0.0) { - if (companded >= 0.0) pow(companded, gamma) else -pow(-companded, gamma) - } else if (gamma < 0.0) { - /* sRGB */ - val (c, sign) = - if (companded < 0.0) { - (-companded, -1.0d) - } else { - (companded, 1.0d) - } - sign * (if (c <= 0.04045) c / 12.92 else pow((c + 0.055) / 1.055, 2.4)) - } else { - /* L* */ - val (c, sign) = - if (companded < 0.0) { - (-companded, -1) - } else { - (companded, 1) - } - sign * (if (c <= 0.08) { - 2700.0 * companded / 24389.0 - } else { - (((1000000.0 * c + 480000.0) * c + 76800.0) * c + 4096.0) / 1560896.0 - }) - } - } - } object RGBWorkingSpace extends WithNameCompanion[RGBWorkingSpace] diff --git a/ijp-color/src/main/scala/ij_plugins/color/converter/ColorConverter.scala b/ijp-color/src/main/scala/ij_plugins/color/converter/ColorConverter.scala index a474e7d..ea0f394 100644 --- a/ijp-color/src/main/scala/ij_plugins/color/converter/ColorConverter.scala +++ b/ijp-color/src/main/scala/ij_plugins/color/converter/ColorConverter.scala @@ -1,6 +1,6 @@ /* * Image/J Plugins - * Copyright (C) 2002-2021 Jarek Sacha + * Copyright (C) 2002-2023 Jarek Sacha * Author's email: jpsacha at gmail dot com * * This library is free software; you can redistribute it and/or @@ -29,9 +29,9 @@ import scala.math.pow /** Color conversion constants */ object ColorConverter { - val kE: Double = 216.0 / 24389.0 - val kK: Double = 24389.0 / 27.0 - val kKE: Double = 8.0 + private val kE: Double = 216.0 / 24389.0 + private val kK: Double = 24389.0 / 27.0 + private val kKE: Double = 8.0 } /** @@ -220,26 +220,32 @@ final class ColorConverter( /** Create copy of this object with a modified field. */ def copyWith( - refWhite: ReferenceWhite = refWhite, - rgbSpace: RGBWorkingSpace = rgbSpace, - chromaticAdaptation: Option[ChromaticAdaptation] = chromaticAdaptation, - rgbScale: Double = rgbScale, - xyzScale: Double = xyzScale - ): ColorConverter = { + refWhite: ReferenceWhite = refWhite, + rgbSpace: RGBWorkingSpace = rgbSpace, + chromaticAdaptation: Option[ChromaticAdaptation] = chromaticAdaptation, + rgbScale: Double = rgbScale, + xyzScale: Double = xyzScale + ): ColorConverter = { new ColorConverter(refWhite, rgbSpace, chromaticAdaptation, rgbScale, xyzScale) } + /** + * De-linearize + * + * @param linear linear value + * @return + */ private def compand(linear: Double): Double = { rgbSpace match { case RGBWorkingSpace.sRGB => assert(rgbSpace.gamma < 0) val (l, sign) = if (linear < 0.0) (-linear, -1.0) else (linear, 1.0) - val c = if (l <= 0.0031308) l * 12.92 else 1.055 * math.pow(l, 1.0 / 2.4) - 0.055 + val c = if (l <= 0.0031308) l * 12.92 else 1.055 * math.pow(l, 1.0 / 2.4) - 0.055 c * sign case RGBWorkingSpace.ECIRGBv2 => assert(rgbSpace.gamma == 0) val (l, sign) = if (linear < 0.0) (-linear, -1.0) else (linear, 1.0) - val c = if (l <= (216.0 / 24389.0)) l * 24389.0 / 2700.0 else 1.16 * math.pow(l, 1.0 / 3.0) - 0.16 + val c = if (l <= (216.0 / 24389.0)) l * 24389.0 / 2700.0 else 1.16 * math.pow(l, 1.0 / 3.0) - 0.16 c * sign case _ => assert(rgbSpace.gamma > 0) @@ -247,30 +253,39 @@ final class ColorConverter( } } + /** + * Linearize + * + * @param companded de-linearized valuer + * @return + */ private def invCompand(companded: Double): Double = - if (rgbSpace.gamma > 0.0) { - if (companded >= 0.0) pow(companded, rgbSpace.gamma) else -pow(-companded, rgbSpace.gamma) - } else if (rgbSpace.gamma < 0.0) { - /* sRGB */ - val (c, sign) = - if (companded < 0.0) { - (-companded, -1.0d) - } else { - (companded, 1.0d) - } - sign * (if (c <= 0.04045) c / 12.92 else pow((c + 0.055) / 1.055, 2.4)) - } else { - /* L* */ - val (c, sign) = - if (companded < 0.0) { - (-companded, -1) + rgbSpace match { + case RGBWorkingSpace.sRGB => + assert(rgbSpace.gamma < 0) + val (c, sign) = + if (companded < 0.0) { + (-companded, -1.0d) + } else { + (companded, 1.0d) + } + sign * (if (c <= 0.04045) c / 12.92 else pow((c + 0.055) / 1.055, 2.4)) + case RGBWorkingSpace.ECIRGBv2 => + assert(rgbSpace.gamma == 0) + /* L* */ + val (c, sign) = + if (companded < 0.0) { + (-companded, -1) + } else { + (companded, 1) + } + sign * (if (c <= 0.08) { + 2700.0 * companded / 24389.0 } else { - (companded, 1) - } - sign * (if (c <= 0.08) { - 2700.0 * companded / 24389.0 - } else { - (((1000000.0 * c + 480000.0) * c + 76800.0) * c + 4096.0) / 1560896.0 - }) + (((1000000.0 * c + 480000.0) * c + 76800.0) * c + 4096.0) / 1560896.0 + }) + case _ => + assert(rgbSpace.gamma > 0) + if (companded >= 0.0) pow(companded, rgbSpace.gamma) else -pow(-companded, rgbSpace.gamma) } }