Skip to content

Commit

Permalink
API: prefer use of immutable IndexedSeq instead of Array #72
Browse files Browse the repository at this point in the history
  • Loading branch information
jpsacha committed Jul 22, 2022
1 parent 4809d0f commit 7cd70b3
Show file tree
Hide file tree
Showing 26 changed files with 635 additions and 609 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ class ColorCalibratorUIModel(val image: ImagePlus, parentWindow: Window) extends
for {
currentChart <- referenceChartOptionWrapper.value
} yield {
newChart2.copyWithEnabled(currentChart.enabled.toArray)
newChart2.copyWithEnabled(currentChart.enabled)
}
).getOrElse(newChart2)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Image/J Plugins
* Copyright (C) 2002-2021 Jarek Sacha
* Copyright (C) 2002-2022 Jarek Sacha
* Author's email: jpsacha at gmail dot com
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -114,12 +114,11 @@ object CalibrateTask {

}

private def showScatterChart(
x: Array[Array[Double]],
y: Array[Array[Double]],
seriesLabels: Array[String],
chartTitle: String
): Unit = {
private def showScatterChart(x: IndexedSeq[IndexedSeq[Double]],
y: IndexedSeq[IndexedSeq[Double]],
seriesLabels: Array[String],
chartTitle: String
): Unit = {

require(x.length == y.length)
require(seriesLabels.length == 3)
Expand Down Expand Up @@ -431,13 +430,12 @@ class CalibrateTask(
"\n")
}

private def showColorErrorChart(
x: Array[Array[Double]],
y: Array[Array[Double]],
columnNames: Array[String],
seriesLabels: Array[String],
titlePrefix: String
): Unit = {
private def showColorErrorChart(x: IndexedSeq[IndexedSeq[Double]],
y: IndexedSeq[IndexedSeq[Double]],
columnNames: Array[String],
seriesLabels: Array[String],
titlePrefix: String
): Unit = {

assert(x.length == y.length)
assert(x.length == columnNames.length)
Expand All @@ -454,18 +452,15 @@ class CalibrateTask(
PlotUtils.createBarPlot(titlePrefix + " - Individual Chip Error", data, "Chip", "Error", barColors)
}

private def showResidualScatterChart(x: Array[Array[Double]], y: Array[Array[Double]], chartTitle: String): Unit = {
private def showResidualScatterChart(x: IndexedSeq[IndexedSeq[Double]], y: IndexedSeq[IndexedSeq[Double]], chartTitle: String): Unit = {

val dy = new Array[Array[Double]](x.length)
for (i <- x.indices) {
val xi = x(i)
val yi = y(i)
val dd = new Array[Double](xi.length)
for (j <- xi.indices) {
dd(j) = math.abs(yi(j) - xi(j))
}
dy(i) = dd
}
val dy =
x.zipWithIndex
.map { case (xi, i) =>
val yi = y(i)
xi.zipWithIndex
.map { case (xij, j) => math.abs(yi(j) - xij) }
}
showScatterChart(x, dy, referenceColorSpace().bandsNames, chartTitle)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Image/J Plugins
* Copyright (C) 2002-2021 Jarek Sacha
* Copyright (C) 2002-2022 Jarek Sacha
* Author's email: jpsacha at gmail dot com
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -71,7 +71,9 @@ object ColorCorrectionBatchItem {

val files = inputDir.listFiles().filter(_.getName.endsWith(inputExt))

files.map(file => new ColorCorrectionBatchItem(recipe, file, dstDir = outputDir, config = itemConfig))
files
.map(file => new ColorCorrectionBatchItem(recipe, file, dstDir = outputDir, config = itemConfig))
.toSeq
}

def nameWithoutExtension(file: File): String = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Image/J Plugins
* Copyright (C) 2002-2021 Jarek Sacha
* Copyright (C) 2002-2022 Jarek Sacha
* Author's email: jpsacha at gmail dot com
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -159,8 +159,8 @@ class SelectEnabledChipsTask(chart: GridColorChart, parentWindow: Option[Window]
dialog.showDialog()

if (dialog.wasOKed) {
val enabled: Array[Boolean] = data.sortBy(_.index).map(_.enabled.value).toArray
val c = chart.copyWithEnabled(enabled)
val enabled = data.sortBy(_.index).map(_.enabled.value).toIndexedSeq
val c = chart.copyWithEnabled(enabled)
Option(c)
} else {
None
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Image/J Plugins
* Copyright (C) 2002-2021 Jarek Sacha
* Copyright (C) 2002-2022 Jarek Sacha
* Author's email: jpsacha at gmail dot com
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -157,10 +157,10 @@ class ColorConverterView(val model: ColorConverterModel) {
addColorUI(row, buttonRGB, rgbUI.control, Some("[0-255]"))
row += 1

addChoiceBox(row, "Ref. White", model.referenceWhite, ReferenceWhite.values)
addChoiceBox(row, "Ref. White", model.referenceWhite, ReferenceWhite.values.toSeq)
row += 1

addChoiceBox(row, "RGB Model", model.rgbWorkingSpace, RGBWorkingSpace.values)
addChoiceBox(row, "RGB Model", model.rgbWorkingSpace, RGBWorkingSpace.values.toSeq)
gp.add(
new Label {
id = "ijp-label"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Image/J Plugins
* Copyright (C) 2002-2021 Jarek Sacha
* Copyright (C) 2002-2022 Jarek Sacha
* Author's email: jpsacha at gmail dot com
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -58,25 +58,27 @@ sealed abstract class ReferenceColorSpace(override val entryName: String, bands:
}

/**
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
def toLab(c: Array[Double], refWhite: ReferenceWhite): ColorTriple.Lab = {
require(c.length == 3)
toLab(c(0), c(1), c(2), refWhite)
}

def toLab(c: IndexedSeq[Double], refWhite: ReferenceWhite): ColorTriple.Lab = toLab(c.toArray, refWhite)

/**
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
def toLab(fps: Array[FloatProcessor], refWhite: ReferenceWhite): Array[FloatProcessor] = {
require(fps.length == 3)
val w = fps(0).getWidth
val w = fps(0).getWidth
val h = fps(0).getHeight
val n = w * h
val lFP = new FloatProcessor(w, h)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,30 @@ enum ReferenceColorSpace(val name: String, bands: Array[String]) extends WithNam
}

/**
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
def toLab(c: Array[Double], refWhite: ReferenceWhite): ColorTriple.Lab = {
require(c.length == 3)
toLab(c(0), c(1), c(2), refWhite)
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
def toLab (c: Array[Double], refWhite: ReferenceWhite): ColorTriple.Lab = {
require (c.length == 3)
toLab (c (0), c (1), c (2), refWhite)
}

def toLab (c: IndexedSeq[Double], refWhite: ReferenceWhite): ColorTriple.Lab = toLab (c.toArray, refWhite)


/**
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
def toLab(fps: Array[FloatProcessor], refWhite: ReferenceWhite): Array[FloatProcessor] = {
require(fps.length == 3)
val w = fps(0).getWidth
val h = fps(0).getHeight
val n = w * h
* Convert color value from the current color space to CIE L*a*b*
*
* @param refWhite
* reference white of the reference color chart.
*/
def toLab (fps: Array[FloatProcessor], refWhite: ReferenceWhite): Array[FloatProcessor] = {
require (fps.length == 3)
val w = fps (0).getWidth
val h = fps (0).getHeight
val n = w * h
val lFP = new FloatProcessor(w, h)
val aFP = new FloatProcessor(w, h)
val bFP = new FloatProcessor(w, h)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Image/J Plugins
* Copyright (C) 2002-2021 Jarek Sacha
* Copyright (C) 2002-2022 Jarek Sacha
* Author's email: jpsacha at gmail dot com
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -29,38 +29,38 @@ import ij_plugins.color.calibration.chart.{ColorChart, ReferenceColorSpace}
import ij_plugins.color.calibration.regression.{CubicPolynomialTriple, MappingFactory, MappingMethod}
import ij_plugins.color.util.Utils.{clipUInt8D, delta}

import scala.reflect.ClassTag

/** Color calibration helper methods */
object ColorCalibrator {

/**
* Results of computing color calibration.
*
* @param reference
* reference color values
* @param observed
* observed color values
* @param corrected
* color values after calibration
* @param corrector
* coefficients of the polynomial mapping functions.
*/
case class CalibrationFit(
reference: Array[Array[Double]],
observed: Array[Array[Double]],
corrected: Array[Array[Double]],
corrector: CubicPolynomialTriple
) {
* Results of computing color calibration.
*
* @param reference
* reference color values
* @param observed
* observed color values
* @param corrected
* color values after calibration
* @param corrector
* coefficients of the polynomial mapping functions.
*/
case class CalibrationFit(reference: IndexedSeq[IndexedSeq[Double]],
observed: IndexedSeq[IndexedSeq[Double]],
corrected: IndexedSeq[IndexedSeq[Double]],
corrector: CubicPolynomialTriple) {
// Validate inputs
require(reference.length > 0)
require(reference.nonEmpty)
require(reference.forall(_.length == 3))
require(observed.length == reference.length)
require(observed.forall(_.length == 3))
require(corrected.length == reference.length)
require(corrected.forall(_.length == 3))

/**
*/
def correctedDeltas: Array[Double] = reference zip corrected map (p => delta(p._1, p._2))
*/
def correctedDeltas: IndexedSeq[Double] = reference zip corrected map (p => delta(p._1, p._2))
}

/** Create instance of ColorCalibrator */
Expand Down Expand Up @@ -115,50 +115,52 @@ class ColorCalibrator(
import ColorCalibrator.*

/**
* Compute coefficients of a polynomial color mapping between the reference and observed colors.
*
* @param observed
* Actually observed color values.
* @return
* color mapping coefficients.
* @throws java.lang.IllegalArgumentException
* when the reference and observed values are not sufficient to compute mapping polynomial coefficients, for
* instance, if the desired polynomial order is too high given the number of reference colors.
*/
def computeCalibrationMapping(observed: Array[Array[Double]]): CalibrationFit = {
* Compute coefficients of a polynomial color mapping between the reference and observed colors.
*
* @param observed
* Actually observed color values.
* @return
* color mapping coefficients.
* @throws java.lang.IllegalArgumentException
* when the reference and observed values are not sufficient to compute mapping polynomial coefficients, for
* instance, if the desired polynomial order is too high given the number of reference colors.
*/
def computeCalibrationMapping(observed: IndexedSeq[IndexedSeq[Double]]): CalibrationFit = {
require(
observed.length == chart.referenceChipsEnabled.length,
s"Expecting ${chart.referenceChipsEnabled.length} observations, got ${observed.length}."
)
require(observed.forall(_.length == 3))

val reference = chart.referenceColorEnabled(referenceColorSpace).clone()
if (clipReferenceRGB && ReferenceColorSpace.sRGB == referenceColorSpace) {
reference.foreach(r => {

val referenceClipped = {
val reference1 = chart.referenceColorEnabled(referenceColorSpace)

if (clipReferenceRGB && ReferenceColorSpace.sRGB == referenceColorSpace) {
// Values should be clipped, but decimal precision should net be truncated
r(0) = clipUInt8D(r(0))
r(1) = clipUInt8D(r(1))
r(2) = clipUInt8D(r(2))
})
reference1.map(r => r.map(clipUInt8D))
} else {
reference1
}
}

require(reference.length == observed.length)
require(referenceClipped.length == observed.length)

val corrector = MappingFactory.createCubicPolynomialTriple(reference, observed, mappingMethod)
val corrector = MappingFactory.createCubicPolynomialTriple(referenceClipped, observed, mappingMethod)
val corrected = observed.map(corrector.map)

CalibrationFit(reference = reference, observed = observed, corrected = corrected, corrector)
CalibrationFit(reference = referenceClipped, observed = observed, corrected = corrected, corrector)
}

/**
* Estimate calibration coefficient. This method does not clip reference color values.
*
* @param bands
* input image bands to measure observed color value of chart's chips.
* @throws java.lang.IllegalArgumentException
* if one of the calibration mapping functions cannot be computed.
*/
def computeCalibrationMapping[T <: ImageProcessor](bands: Array[T]): CalibrationFit = {
* Estimate calibration coefficient. This method does not clip reference color values.
*
* @param bands
* input image bands to measure observed color value of chart's chips.
* @throws java.lang.IllegalArgumentException
* if one of the calibration mapping functions cannot be computed.
*/
def computeCalibrationMapping[T <: ImageProcessor : ClassTag](bands: IndexedSeq[T]): CalibrationFit = {
require(
(bands.forall(_.isInstanceOf[ByteProcessor]) |
bands.forall(_.isInstanceOf[ShortProcessor]) |
Expand Down Expand Up @@ -200,7 +202,7 @@ class ColorCalibrator(
val src = image.getProcessor.asInstanceOf[ColorProcessor]
computeCalibrationMapping(src)
case (GRAY8, 3) | (GRAY16, 3) | (GRAY32, 3) =>
val src = (1 to 3).map(image.getStack.getProcessor).toArray
val src = (1 to 3).map(image.getStack.getProcessor)
computeCalibrationMapping(src)
case _ =>
throw new IllegalArgumentException(
Expand Down
Loading

0 comments on commit 7cd70b3

Please sign in to comment.