Skip to content

Commit

Permalink
[api]: Fix FITS image rescaling. Use the min and max values if is out…
Browse files Browse the repository at this point in the history
… of range
  • Loading branch information
tiagohm committed Apr 6, 2024
1 parent b28ee23 commit d1f010e
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 18 deletions.
4 changes: 3 additions & 1 deletion api/src/main/kotlin/nebulosa/api/image/ImageService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ class ImageService(
val (autoStretch, shadow, highlight, midtone) = transformation.stretch
val scnrEnabled = transformation.scnr.channel != null
val manualStretch = shadow != 0f || highlight != 1f || midtone != 0.5f
var stretchParams = ScreenTransformFunction.Parameters(midtone, shadow, highlight)

val shouldBeTransformed = enabled && (autoStretch || manualStretch
|| transformation.mirrorHorizontal || transformation.mirrorVertical || transformation.invert
Expand Down Expand Up @@ -139,11 +138,14 @@ class ImageService(
val statistics = if (operation == ImageOperation.OPEN) transformedImage.compute(Statistics.GRAY)
else null

var stretchParams = ScreenTransformFunction.Parameters.DEFAULT

if (enabled) {
if (autoStretch) {
stretchParams = AutoScreenTransformFunction.compute(transformedImage)
transformedImage = ScreenTransformFunction(stretchParams).transform(transformedImage)
} else if (manualStretch) {
stretchParams = ScreenTransformFunction.Parameters(midtone, shadow, highlight)
transformedImage = ScreenTransformFunction(stretchParams).transform(transformedImage)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package nebulosa.fits
import nebulosa.fits.FitsFormat.readPixel
import nebulosa.image.format.ImageChannel
import nebulosa.image.format.ImageData
import nebulosa.image.format.ImageData.Companion.representableRange
import nebulosa.io.SeekableSource
import nebulosa.log.loggerFor
import okio.Buffer
import okio.Sink
import kotlin.math.max
import kotlin.math.min

@Suppress("NOTHING_TO_INLINE")
Expand All @@ -20,9 +21,6 @@ internal data class SeekableSourceImageData(
private val range: ClosedFloatingPointRange<Float>,
) : ImageData {

private val rangeDelta = range.endInclusive - range.start
private val rescale = range.start != 0f || range.endInclusive != 1f

@JvmField internal val channelSizeInBytes = (numberOfPixels * bitpix.byteLength).toLong()
@JvmField internal val totalSizeInBytes = channelSizeInBytes * numberOfChannels

Expand Down Expand Up @@ -77,6 +75,9 @@ internal data class SeekableSourceImageData(
var pos = 0

Buffer().use { buffer ->
var min = Float.MAX_VALUE
var max = Float.MIN_VALUE

while (remainingPixels > 0) {
var n = min(PIXEL_COUNT, remainingPixels)
val byteCount = n * bitpix.byteLength.toLong()
Expand All @@ -90,12 +91,25 @@ internal data class SeekableSourceImageData(

repeat(n) {
val pixel = buffer.readPixel(bitpix)
output[pos++] = if (rescale) pixel.representableRange(range.start, range.endInclusive, rangeDelta)
else pixel
if (pixel < min) min = pixel
if (pixel > max) max = pixel
output[pos++] = pixel
}

remainingPixels -= n
}

if (min < 0f || max > 1f) {
val rangeMin = min(range.start, min)
val rangeMax = max(range.endInclusive, max)
val rangeDelta = rangeMax - rangeMin

LOG.info("rescaling [{}, {}] to [0, 1]. channel={}, delta={}", rangeMin, rangeMax, channel, rangeDelta)

for (i in output.indices) {
output[i] = (output[i] - rangeMin) / rangeDelta
}
}
}
}

Expand Down Expand Up @@ -130,5 +144,7 @@ internal data class SeekableSourceImageData(
companion object {

const val PIXEL_COUNT = 64

@JvmStatic private val LOG = loggerFor<SeekableSourceImageData>()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,4 @@ interface ImageData {
val blue: FloatArray

fun readChannelTo(channel: ImageChannel, output: FloatArray)

companion object {

@Suppress("NOTHING_TO_INLINE")
inline fun Float.representableRange(rangeMin: Float, rangeMax: Float, rangeDelta: Float = rangeMax - rangeMin): Float {
return if (this < rangeMin) 0f
else if (this > rangeMax) 1f
else (this - rangeMin) / rangeDelta
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ data class ScreenTransformFunction(

companion object {

@JvmStatic val EMPTY = Parameters()
@JvmStatic val DEFAULT = Parameters()
}
}

Expand Down

0 comments on commit d1f010e

Please sign in to comment.