Skip to content

Improve support for operations on Gray #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 3, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 69 additions & 17 deletions src/ColorVectorSpace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,28 @@ module ColorVectorSpace

using ColorTypes, FixedPointNumbers, Compat, Base.Cartesian

import Base: ==, +, -, *, /, .+, .-, .*, ./, ^, <
import Base: ==, +, -, *, /, .+, .-, .*, ./, ^, <, ~
import Base: abs, abs2, clamp, convert, copy, div, eps, isfinite, isinf,
isnan, isless, length, one, promote_array_type, promote_rule, zero,
isnan, isless, length, mapreduce, norm, one, promote_array_type, promote_rule, zero,
trunc, floor, round, ceil, bswap,
mod, rem, atan2, hypot
mod, rem, atan2, hypot, max, min

# The unaryOps
import Base: conj, sin, cos, tan, sinh, cosh, tanh,
asin, acos, atan, asinh, acosh, atanh,
sec, csc, cot, asec, acsc, acot,
sech, csch, coth, asech, acsch, acoth,
sinc, cosc, cosd, cotd, cscd, secd,
sind, tand, acosd, acotd, acscd, asecd,
asind, atand, rad2deg, deg2rad,
log, log2, log10, log1p, exponent, exp,
exp2, expm1, cbrt, sqrt, erf,
erfc, erfcx, erfi, dawson,
significand, lgamma,
gamma, lfact, frexp, modf, airy, airyai,
airyprime, airyaiprime, airybi, airybiprime,
besselj0, besselj1, bessely0, bessely1,
eta, zeta, digamma

typealias AbstractGray{T} Color{T,1}
typealias TransparentRGB{C<:AbstractRGB,T} TransparentColor{C,T,4}
Expand All @@ -20,9 +37,14 @@ typealias TransparentGrayUfixed{C<:AbstractGray,T<:Ufixed} TransparentColor{C,T,

@compat typealias MathTypes Union{AbstractRGB,TransparentRGB,AbstractGray,TransparentRGB}

export sumsq

## Generic algorithms
if VERSION >= v"0.4-"
mapreduce(f, op::Base.ShortCircuiting, a::MathTypes) = f(a) # ambiguity
mapreduce(f, op, a::MathTypes) = f(a)
else
mapreduce(f, op, a::MathTypes) = Base.evaluate(f, a)
end

for f in (:trunc, :floor, :round, :ceil, :eps, :bswap)
@eval $f{T}(g::Gray{T}) = Gray{T}($f(gray(g)))
@eval @vectorize_1arg Gray $f
Expand Down Expand Up @@ -127,11 +149,11 @@ isinf{T<:Ufixed}(c::Colorant{T}) = false
isinf{T<:AbstractFloat}(c::AbstractRGB{T}) = isinf(red(c)) || isinf(green(c)) || isinf(blue(c))
isinf(c::TransparentRGBFloat) = isinf(red(c)) || isinf(green(c)) || isinf(blue(c)) || isinf(alpha(c))
abs(c::AbstractRGB) = abs(red(c))+abs(green(c))+abs(blue(c)) # should this have a different name?
abs{T<:Ufixed}(c::AbstractRGB{T}) = float32(red(c))+float32(green(c))+float32(blue(c)) # should this have a different name?
abs{T<:Ufixed}(c::AbstractRGB{T}) = Float32(red(c))+Float32(green(c))+Float32(blue(c)) # should this have a different name?
abs(c::TransparentRGB) = abs(red(c))+abs(green(c))+abs(blue(c))+abs(alpha(c)) # should this have a different name?
abs{T<:Ufixed}(c::TransparentRGB{T}) = float32(red(c))+float32(green(c))+float32(blue(c))+float32(alpha(c)) # should this have a different name?
sumsq(c::AbstractRGB) = red(c)^2+green(c)^2+blue(c)^2
sumsq{T<:Ufixed}(c::AbstractRGB{T}) = float32(red(c))^2+float32(green(c))^2+float32(blue(c))^2
abs{T<:Ufixed}(c::TransparentRGB{T}) = Float32(red(c))+Float32(green(c))+Float32(blue(c))+Float32(alpha(c)) # should this have a different name?
abs2(c::AbstractRGB) = red(c)^2+green(c)^2+blue(c)^2
abs2{T<:Ufixed}(c::AbstractRGB{T}) = Float32(red(c))^2+Float32(green(c))^2+Float32(blue(c))^2

one{C<:AbstractRGB}(::Type{C}) = C(1,1,1)
one{C<:TransparentRGB}(::Type{C}) = C(1,1,1,1)
Expand Down Expand Up @@ -171,6 +193,26 @@ typemax{C<:AbstractRGB}(::Type{C}) = one(C)

# Scalar Gray
copy(c::AbstractGray) = c
const unaryOps = (:-, :~, :conj, :abs,
:sin, :cos, :tan, :sinh, :cosh, :tanh,
:asin, :acos, :atan, :asinh, :acosh, :atanh,
:sec, :csc, :cot, :asec, :acsc, :acot,
:sech, :csch, :coth, :asech, :acsch, :acoth,
:sinc, :cosc, :cosd, :cotd, :cscd, :secd,
:sind, :tand, :acosd, :acotd, :acscd, :asecd,
:asind, :atand, :rad2deg, :deg2rad,
:log, :log2, :log10, :log1p, :exponent, :exp,
:exp2, :expm1, :cbrt, :sqrt, :erf,
:erfc, :erfcx, :erfi, :dawson,
:significand, :lgamma,
:gamma, :lfact, :frexp, :modf, :airy, :airyai,
:airyprime, :airyaiprime, :airybi, :airybiprime,
:besselj0, :besselj1, :bessely0, :bessely1,
:eta, :zeta, :digamma)
for op in unaryOps
@eval ($op)(c::AbstractGray) = $op(gray(c))
end

(*)(f::Real, c::AbstractGray) = base_colorant_type(c){multype(typeof(f),eltype(c))}(f*gray(c))
(*)(f::Real, c::TransparentGray) = base_colorant_type(c){multype(typeof(f),eltype(c))}(f*gray(c), f*alpha(c))
(*)(c::AbstractGray, f::Real) = (*)(f, c)
Expand All @@ -180,10 +222,12 @@ copy(c::AbstractGray) = c
(.*)(f::Real, c::TransparentGray) = (*)(f, c)
(.*)(c::TransparentGray, f::Real) = (*)(f, c)
(/)(c::AbstractGray, f::Real) = (one(f)/f)*c
(/)(n::Number, c::AbstractGray) = n/gray(c)
(/)(c::TransparentGray, f::Real) = (one(f)/f)*c
(/)(c::AbstractGray, f::Integer) = (one(eltype(c))/f)*c
(/)(c::TransparentGray, f::Integer) = (one(eltype(c))/f)*c
(./)(c::AbstractGray, f::Real) = c/f
(./)(n::Number, c::AbstractGray) = n/gray(c)
(./)(c::TransparentGray, f::Real) = c/f
(+){S,T}(a::AbstractGray{S}, b::AbstractGray{T}) = color_rettype(a,b){sumtype(S,T)}(gray(a)+gray(b))
(+)(a::TransparentGray, b::TransparentGray) = color_rettype(a,b){sumtype(eltype(a),eltype(b))}(gray(a)+gray(b),alpha(a)+alpha(b))
Expand All @@ -206,22 +250,28 @@ div(a::AbstractGray, b::AbstractGray) = div(gray(a), gray(b))
(.-)(a::AbstractGray, b::Number) = gray(a)-b
(.+)(a::Number, b::AbstractGray) = a+gray(b)
(.-)(a::Number, b::AbstractGray) = a-gray(b)
max{T<:AbstractGray}(a::T, b::T) = T(max(gray(a),gray(b)))
max(a::AbstractGray, b::AbstractGray) = max(promote(a,b)...)
max(a::Number, b::AbstractGray) = max(promote(a,b)...)
max(a::AbstractGray, b::Number) = max(promote(a,b)...)
min{T<:AbstractGray}(a::T, b::T) = T(min(gray(a),gray(b)))
min(a::AbstractGray, b::AbstractGray) = min(promote(a,b)...)
min(a::Number, b::AbstractGray) = min(promote(a,b)...)
min(a::AbstractGray, b::Number) = min(promote(a,b)...)

isfinite{T<:AbstractFloat}(c::AbstractGray{T}) = isfinite(gray(c))
isfinite(c::TransparentGrayFloat) = isfinite(gray(c)) && isfinite(alpha(c))
isnan{T<:AbstractFloat}(c::AbstractGray{T}) = isnan(gray(c))
isnan(c::TransparentGrayFloat) = isnan(gray(c)) && isnan(alpha(c))
isinf{T<:AbstractFloat}(c::AbstractGray{T}) = isinf(gray(c))
isinf(c::TransparentGrayFloat) = isinf(gray(c)) && isnan(alpha(c))
abs(c::AbstractGray) = abs(gray(c)) # should this have a different name?
norm(c::AbstractGray) = abs(gray(c))
abs(c::TransparentGray) = abs(gray(c))+abs(alpha(c)) # should this have a different name?
abs{T<:Ufixed}(c::AbstractGray{T}) = float32(gray(c)) # should this have a different name?
abs(c::TransparentGrayUfixed) = float32(gray(c)) + float32(alpha(c)) # should this have a different name?
sumsq(x::Real) = x^2
sumsq(c::AbstractGray) = gray(c)^2
sumsq{T<:Ufixed}(c::AbstractGray{T}) = float32(gray(c))^2
sumsq(c::TransparentGray) = gray(c)^2+alpha(c)^2
sumsq(c::TransparentGrayUfixed) = float32(gray(c))^2 + float32(alpha(c))^2
abs(c::TransparentGrayUfixed) = Float32(gray(c)) + Float32(alpha(c)) # should this have a different name?
abs2(c::AbstractGray) = gray(c)^2
abs2{T<:Ufixed}(c::AbstractGray{T}) = Float32(gray(c))^2
abs2(c::TransparentGray) = gray(c)^2+alpha(c)^2
abs2(c::TransparentGrayUfixed) = Float32(gray(c))^2 + Float32(alpha(c))^2
atan2(x::Gray, y::Gray) = atan2(convert(Real, x), convert(Real, y))
hypot(x::Gray, y::Gray) = hypot(convert(Real, x), convert(Real, y))

Expand Down Expand Up @@ -358,4 +408,6 @@ end
promote_rule{C1<:Colorant,C2<:Colorant}(::Type{C1}, ::Type{C2}) = color_rettype(C1,C2){promote_type(eltype(C1), eltype(C2))}
promote_rule{T<:Real,C<:AbstractGray}(::Type{T}, ::Type{C}) = promote_type(T, eltype(C))

@deprecate sumsq abs2

end
24 changes: 23 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module ColorVectorSpaceTests

using FactCheck, ColorVectorSpace, ColorTypes, FixedPointNumbers, Compat
using FactCheck, Base.Test, ColorVectorSpace, ColorTypes, FixedPointNumbers, Compat

macro test_colortype_approx_eq(a, b)
:(test_colortype_approx_eq($(esc(a)), $(esc(b)), $(string(a)), $(string(b))))
Expand Down Expand Up @@ -28,6 +28,8 @@ facts("Colortypes") do
@test_colortype_approx_eq cf^2 Gray{Float32}(0.01)
@test_colortype_approx_eq cf^3.0f0 Gray{Float32}(0.001)
@fact eltype(2.0*cf) --> Float64
@fact abs2(ccmp) --> 0.2f0^2
@fact sumabs2(ccmp) --> 0.2f0^2
cu = Gray{U8}(0.1)
@fact 2*cu --> Gray(2*cu.val)
@fact 2.0f0*cu --> Gray(2.0f0*cu.val)
Expand Down Expand Up @@ -70,6 +72,7 @@ facts("Colortypes") do
@fact (acf/Gray{Float32}(2))[1] --> roughly(0.05f0)
@fact (acu/2)[1] --> Gray(gray(acu[1])/2)
@fact (acf/2)[1] --> roughly(Gray{Float32}(0.05f0))
@fact sumabs2([cf,ccmp]) --> roughly(0.05f0)

@fact gray(0.8) --> 0.8
end
Expand All @@ -85,6 +88,24 @@ facts("Colortypes") do
@fact isless(0.5, g1) --> false
@fact g1 < 0.5 --> true
@fact 0.5 < g1 --> false
@fact @inferred(max(g1, g2)) --> g2
@fact @inferred(max(g1, 0.1)) --> 0.2
@fact @inferred(min(g1, g2)) --> g1
@fact @inferred(min(g1, 0.1)) --> 0.1
end

context("Unary operations with Gray") do
for g in (Gray(0.4), Gray{U8}(0.4))
for op in ColorVectorSpace.unaryOps
try
v = @eval $op(gray(g)) # if this fails, don't bother
@fact $op(g) --> v
end
end
end
u = U8(0.4)
@fact ~Gray(u) --> Gray(~u)
@fact -Gray(u) --> Gray(-u)
end

context("Arithmetic with GrayA") do
Expand Down Expand Up @@ -138,6 +159,7 @@ facts("Colortypes") do
@fact RGB(1, Inf, 0.5) --> isinf
@fact RGB(1, Inf, 0.5) --> not(isnan)
@fact abs(RGB(0.1,0.2,0.3)) --> roughly(0.6)
@fact sumabs2(RGB(0.1,0.2,0.3)) --> roughly(0.14)

acu = RGB{U8}[cu]
acf = RGB{Float32}[cf]
Expand Down