Skip to content

Commit

Permalink
Support ScaleMinMax for To<:Integer
Browse files Browse the repository at this point in the history
Integer-valued images are not generally recommended (deciding contrast is a mess), but it's worth having them work.
Note this also improves overflow-safety (for From<:Signed).
  • Loading branch information
timholy committed Apr 26, 2016
1 parent 66a4956 commit 200ffe8
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
22 changes: 15 additions & 7 deletions src/map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ immutable ScaleMinMax{To,From,S<:AbstractFloat} <: MapInfo{To}
end

ScaleMinMax{To,From}(::Type{To}, min::From, max::From, s::AbstractFloat) = ScaleMinMax{To,From,typeof(s)}(min, max, s)
ScaleMinMax{To,From}(::Type{To}, min::From, max::From, s) = ScaleMinMax(To, min, max, convert_float(To, Float32, s))
convert_float{To<:AbstractFloat,T}(::Type{To}, ::Type{T}, s) = convert(To, s)
convert_float{To,T}(::Type{To}, ::Type{T}, s) = convert(T, s)
ScaleMinMax{To<:Union{Fractional,Colorant},From}(::Type{To}, mn::From, mx::From) = ScaleMinMax(To, mn, mx, 1.0f0/(convert(Float32, mx)-convert(Float32, mn)))

# ScaleMinMax constructors that take AbstractArray input
Expand All @@ -249,20 +252,22 @@ similar{T,F,To,From,S}(mapi::ScaleMinMax{To,From,S}, ::Type{T}, ::Type{F}) = Sca

# Implementation
function immap{To<:Union{Real,AbstractGray},From<:Union{Real,AbstractGray}}(mapi::ScaleMinMax{To,From}, val::From)
g = gray(val)
t = ifelse(g < mapi.min, zero(From), ifelse(g > mapi.max, mapi.max-mapi.min, g-mapi.min))
convert(To, mapi.s*t)
t = clamp(gray(val), gray(mapi.min), gray(mapi.max))
f = mapi.s*t - mapi.s*mapi.min # better than mapi.s*(t-mapi.min) (overflow)
convertsafely(To, f)
end
function immap{To<:Union{Real,AbstractGray},From<:Union{Real,AbstractGray}}(mapi::ScaleMinMax{To,From}, val::Union{Real,Colorant})
immap(mapi, convert(From, val))
end
function map1{To<:Union{RGB24,ARGB32},From<:Real}(mapi::ScaleMinMax{To,From}, val::From)
t = ifelse(val < mapi.min, zero(From), ifelse(val > mapi.max, mapi.max-mapi.min, val-mapi.min))
convert(UFixed8, mapi.s*t)
t = clamp(val, mapi.min, mapi.max)
f = mapi.s*t - mapi.s*mapi.min
convert(UFixed8, f)
end
function map1{To<:Colorant,From<:Real}(mapi::ScaleMinMax{To,From}, val::From)
t = ifelse(val < mapi.min, zero(From), ifelse(val > mapi.max, mapi.max-mapi.min, val-mapi.min))
convert(eltype(To), mapi.s*t)
t = clamp(val, mapi.min, mapi.max)
f = mapi.s*t - mapi.s*mapi.min
convertsafely(eltype(To), f)
end
function map1{To<:Union{RGB24,ARGB32},From<:Real}(mapi::ScaleMinMax{To,From}, val::Union{Real,Colorant})
map1(mapi, convert(From, val))
Expand Down Expand Up @@ -695,3 +700,6 @@ end

ufixedsc{T<:UFixed}(::Type{T}, img::AbstractImageDirect) = immap(mapinfo(T, img), img)
ufixed8sc(img::AbstractImageDirect) = ufixedsc(UFixed8, img)

convertsafely{T}(::Type{T}, val) = convert(T, val)
convertsafely{T<:Integer}(::Type{T}, val::AbstractFloat) = round(T, val)
10 changes: 10 additions & 0 deletions test/map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ facts("Map") do
@fact map(Clamp01NaN(A), A) --> [0.0 0.5; 1.0 0.0]
B = colorim(repeat(reshape(A, (1,2,2)), outer=[3,1,1]))
@fact map(Clamp01NaN(B), B) --> [RGB(0.0,0,0) RGB(0.5,0.5,0.5); RGB(1.0,1,1) RGB(0.0,0,0)]
# Integer-valued images are not recommended, but let's at
# least make sure they work
smm = ScaleMinMax(UInt8, 0.0, 1.0, 255)
@fact map(smm, 0.0) --> exactly(0x00)
@fact map(smm, 1.0) --> exactly(0xff)
@fact map(smm, 0.1) --> exactly(round(UInt8, 0.1*255.0f0))
smm = ScaleMinMax(Gray{U8}, typemin(Int8), typemax(Int8))
@fact map(smm, 2) --> Gray{U8}(0.51)
smm = ScaleMinMax(RGB24, typemin(Int8), typemax(Int8))
@fact map(smm, 2) --> RGB24(0x828282)
end

context("ScaleSigned") do
Expand Down

0 comments on commit 200ffe8

Please sign in to comment.