Skip to content

Instantly share code, notes, and snippets.

@gregzuro
Created May 30, 2013 23:58
Show Gist options
  • Save gregzuro/5682170 to your computer and use it in GitHub Desktop.
Save gregzuro/5682170 to your computer and use it in GitHub Desktop.
julia algorithms
#### Math with images ####
(+)(img::AbstractImageDirect, n::Number) = share(img, data(img)+n)
(+)(n::Number, img::AbstractImageDirect) = share(img, data(img)+n)
(+)(img::AbstractImageDirect, A::BitArray) = share(img, data(img)+A)
(+)(img::AbstractImageDirect, A::AbstractArray) = share(img, data(img)+data(A))
(-)(img::AbstractImageDirect, n::Number) = share(img, data(img)-n)
(-)(n::Number, img::AbstractImageDirect) = share(img, n-data(img))
(-)(img::AbstractImageDirect, A::BitArray) = share(img, data(img)-A)
(-)(img::AbstractImageDirect, A::AbstractArray) = share(img, data(img)-data(A))
(*)(img::AbstractImageDirect, n::Number) = share(img, data(img)*n)
(*)(n::Number, img::AbstractImageDirect) = share(img, data(img)*n)
(/)(img::AbstractImageDirect, n::Number) = share(img, data(img)/n)
(.*)(img::AbstractImageDirect, A::BitArray) = share(img, data(img).*A)
(.*)(A::BitArray, img::AbstractImageDirect) = share(img, data(img).*A)
(.*)(img1::AbstractImageDirect, img2::AbstractImageDirect) = share(img1, data(img1).*data(img2))
(.*)(img::AbstractImageDirect, A::AbstractArray) = share(img, data(img).*A)
(.*)(A::AbstractArray, img::AbstractImageDirect) = share(img, data(img).*A)
(./)(img::AbstractImageDirect, A::BitArray) = share(img, data(img)./A)
(./)(img1::AbstractImageDirect, img2::AbstractImageDirect) = share(img, data(img1)./data(img2))
(./)(img::AbstractImageDirect, A::AbstractArray) = share(img, data(img)./A)
# (./)(A::AbstractArray, img::AbstractImageDirect) = share(img, A./data(img))
(.<)(img::AbstractImageDirect, n::Number) = data(img) .< n
(.>)(img::AbstractImageDirect, n::Number) = data(img) .> n
(.<)(img::AbstractImageDirect, A::AbstractArray) = data(img) .< A
(.>)(img::AbstractImageDirect, A::AbstractArray) = data(img) .> A
(.==)(img::AbstractImageDirect, n::Number) = data(img) .== n
(.==)(img::AbstractImageDirect, A::AbstractArray) = data(img) .== A
#### Scaling/clipping/type conversion ####
function scale{T}(scalei::ScaleInfo{T}, img::Union(StridedArray,AbstractImageDirect))
out = similar(img, T)
dout = data(out)
dimg = data(img)
for i = 1:length(dimg)
dout[i] = scale(scalei, dimg[i])
end
out
end
type ScaleNone{T} <: ScaleInfo{T}; end
scale{T<:Number}(scalei::ScaleNone{T}, val::T) = val
scale{T,S<:Number}(scalei::ScaleNone{T}, val::S) = convert(T, val)
scale{T<:Integer,S<:FloatingPoint}(scalei::ScaleNone{T}, val::S) = convert(T, round(val))
scale(scalei::ScaleNone{Uint8}, val::Uint16) = (val>>>8) & 0xff
scale(scalei::ScaleNone{Uint8}, val::Uint16) = (val>>>8) & 0xff
convert{I<:AbstractImageDirect}(::Type{I}, img::Union(StridedArray,AbstractImageDirect)) = scale(ScaleNone{eltype(I)}(), img)
type BitShift{T,N} <: ScaleInfo{T} end
scale{T,N}(scalei::BitShift{T,N}, val::Integer) = convert(T, val>>>N)
# The Clip types just enforce bounds, but do not scale or
# subtract the minimum
type ClipMin{T,From} <: ScaleInfo{T}
min::From
end
ClipMin{T,From}(::Type{T}, min::From) = ClipMin{T,From}(min)
type ClipMax{T,From} <: ScaleInfo{T}
max::From
end
ClipMax{T,From}(::Type{T}, max::From) = ClipMax{T,From}(max)
type ClipMinMax{T,From} <: ScaleInfo{T}
min::From
max::From
end
ClipMinMax{T,From}(::Type{T}, min::From, max::From) = ClipMinMax{T,From}(min,max)
scale{T<:Number}(scalei::ClipMin{T,T}, val::T) = max(val, scalei.min)
scale(scalei::ClipMin{Uint8,Uint16}, val::Uint16) = (max(val, scalei.min)>>>8) & 0xff
scale{T<:Number}(scalei::ClipMax{T,T}, val::T) = min(val, scalei.max)
scale(scalei::ClipMax{Uint8,Uint16}, val::Uint16) = (min(val, scalei.max)>>>8) & 0xff
scale{T<:Number}(scalei::ClipMinMax{T,T}, val::T) = min(max(val, scalei.min), scalei.max)
scale{T<:Number,F<:Number}(scalei::ClipMinMax{T,F}, val::F) = convert(T,min(max(val, scalei.min), scalei.max))
# scale(scalei::ClipMinMax{Uint8,Uint16}, val::Uint16) = (min(max(val, scalei.min), scalei.max)>>>8) & 0xff
# This scales and subtracts the min value
type ScaleMinMax{To,From} <: ScaleInfo{To}
min::From
max::From
s::Float64
end
function scale{To<:Integer,From<:Number}(scalei::ScaleMinMax{To,From}, val::From)
# Clip to range min:max and subtract min
t::From = (val > scalei.min) ? ((val < scalei.max) ? val-scalei.min : scalei.max-scalei.min) : zero(From)
convert(To, ifloor(scalei.s*t))
end
function scale{To<:Number,From<:Number}(scalei::ScaleMinMax{To,From}, val::From)
t::From = (val > scalei.min) ? ((val < scalei.max) ? val-scalei.min : scalei.max-scalei.min) : zero(From)
convert(To, scalei.s*t)
end
function scaleinfo{To<:Unsigned,From<:Unsigned}(::Type{To}, img::AbstractArray{From})
l = limits(img)
if l[1] == typemin(From) && l[2] == typemax(From)
return ScaleNone{To}()
end
ScaleMinMax{To,From}(l[1],l[2],typemax(To)/(l[2]-l[1]))
end
function scaleinfo{To<:Unsigned,From<:FloatingPoint}(::Type{To}, img::AbstractArray{From})
l = limits(img)
if !isinf(l[1]) && !isinf(l[2])
return ScaleMinMax{To,From}(l[1],l[2],typemax(To)/(l[2]-l[1]))
else
return ScaleNone{To}()
end
end
scaleminmax{To}(::Type{To}, img::AbstractArray, mn::Number, mx::Number) = ScaleMinMax{To,eltype(img)}(mn, mx, typemax(To)/(mx-mn))
scaleminmax{To}(::Type{To}, img::AbstractArray) = scaleminmax(To, img, min(img), max(img))
scaleminmax(img::AbstractArray) = scaleminmax(Uint8, img)
scaleminmax(img::AbstractArray, mn::Number, mx::Number) = scaleminmax(Uint8, img, mn, mx)
sc(img::AbstractArray) = scale(scaleminmax(img), img)
sc(img::AbstractArray, mn::Number, mx::Number) = scale(scaleminmax(img, mn, mx), img)
#### Converting 2d image to uint32 color ####
uint32color!(buf::Array{Uint32,2}, img::Union(StridedArray,AbstractImageDirect),
scalei::ScaleInfo = scaleinfo(Uint8, img)) = uint32color!(buf, img, !isxfirst(img), scalei)
uint32color!(buf::Array{Uint32,2}, img::Union(StridedArray,AbstractImageDirect),
scalei::ScaleInfo = scaleinfo(Uint8, img)) = uint32color!(buf, img, !isxfirst(img), scalei)
function uint32color!{S<:String}(buf::Array{Uint32,2}, img::Union(StridedArray,AbstractImageDirect),
xy::Array{S} = xy, scalei::ScaleInfo = scaleinfo(Uint8, img))
p = spatialpermutation(xy, img)
uint32color!(buf, img, p[1] > p[2], scalei)
end
function uint32color!(buf::Array{Uint32,2}, img::Union(StridedArray,AbstractImageDirect), transpose::Bool, scalei::ScaleInfo = scaleinfo(Uint8, img))
assert2d(img)
cs = colorspace(img)
firstindex, spsz, spstride, csz, cstride = iterate_spatial(img)
isz, jsz = spsz
istride, jstride = spstride
A = parent(img)
if transpose
w, h = jsz, isz
else
w, h = isz, jsz
end
if size(buf, 1) != w || size(buf, 2) != h
@show size(buf)
@show w
@show h
@show transpose
error("Output buffer is of the wrong size")
end
# Check to see whether we can do a direct copy
if eltype(img) <: Union(Uint32, Int32)
if cs == "RGB24" || cs == "ARGB32"
if transpose
copyt!(buf, img.data)
else
copy!(buf, img.data)
end
return buf
end
end
uint32color!(buf, A, transpose, cs, firstindex, isz, jsz, istride, jstride, cstride, scalei)
end
function uint32color!(buf::Array{Uint32,2}, A::Array, transpose::Bool, cs::String, firstindex::Int, isz::Int, jsz::Int, istride::Int, jstride::Int, cstride::Int, scalei::ScaleInfo)
if cstride == 0
if cs == "Gray"
if !transpose
# Note: can't use a single linear index for RHS, because this might be a subarray
l = 1
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 0:istride:(isz-1)*istride
gr = scale(scalei, A[k+i])
buf[l] = rgb24(gr, gr, gr)
l += 1
end
end
else
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 1:isz
gr = scale(scalei, A[k+(i-1)*istride])
buf[j,i] = rgb24(gr, gr, gr)
end
end
end
else
error("colorspace ", cs, " not yet supported")
end
else
if cs == "RGB"
if !transpose
l = 1
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 0:istride:(isz-1)*istride
ki = k+i
buf[l] = rgb24(scalei, A[ki], A[ki+cstride], A[ki+2cstride])
l += 1
end
end
else
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 1:isz
ki = k+(i-1)*istride
buf[j,i] = rgb24(scalei, A[ki], A[ki+cstride], A[ki+2cstride])
end
end
end
elseif cs == "ARGB"
if !transpose
l = 1
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 0:istride:(isz-1)*istride
ki = k+i
buf[l] = argb32(scalei,A[ki],A[ki+cstride],A[ki+2cstride],A[ki+3cstride])
l += 1
end
end
else
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 1:isz
ki = k+(i-1)*istride
buf[j,i] = argb32(scalei,A[ki],A[ki+cstride],A[ki+2cstride],A[ki+3cstride])
end
end
end
elseif cs == "RGBA"
if !transpose
l = 1
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 0:istride:(isz-1)*istride
ki = k+i
buf[l] = argb32(scalei,A[ki+3cstride],A[ki],A[ki+cstride],A[ki+2cstride])
l += 1
end
end
else
for j = 1:jsz
k = firstindex + (j-1)*jstride
for i = 1:isz
ki = k+(i-1)*istride
buf[j,i] = argb32(scalei,A[ki+3cstride],A[ki],A[ki+cstride],A[ki+2cstride])
end
end
end
else
error("colorspace ", cs, " not yet supported")
end
end
return buf
end
function uint32color(img::Union(StridedArray,AbstractImageDirect), transpose::Bool, scalei::ScaleInfo = scaleinfo(Uint8, img))
w, h = widthheight(img)
if transpose
w, h = h, w
end
buf = Array(Uint32, w, h)
uint32color!(buf, img, transpose, scalei)
end
uint32color(img::Union(StridedArray,AbstractImageDirect), scalei::ScaleInfo = scaleinfo(Uint8, img)) =
uint32color(img, !isxfirst(img), scalei)
rgb24(r::Uint8, g::Uint8, b::Uint8) = convert(Uint32,r)<<16 + convert(Uint32,g)<<8 + convert(Uint32,b)
argb32(a::Uint8, r::Uint8, g::Uint8, b::Uint8) = convert(Uint32,a)<<24 + convert(Uint32,r)<<16 + convert(Uint32,g)<<8 + convert(Uint32,b)
rgb24{T}(scalei::ScaleInfo{Uint8}, r::T, g::T, b::T) = convert(Uint32,scale(scalei,r))<<16 + convert(Uint32,scale(scalei,g))<<8 + convert(Uint32,scale(scalei,b))
argb32{T}(scalei::ScaleInfo{Uint8}, a::T, r::T, g::T, b::T) = convert(Uint32,scale(scalei,a))<<24 + convert(Uint32,scale(scalei,r))<<16 + convert(Uint32,scale(scalei,g))<<8 + convert(Uint32,scale(scalei,b))
#### Color palettes ####
function lut(pal::Vector, a)
out = similar(a, eltype(pal))
n = length(pal)
for i=1:length(a)
out[i] = pal[clamp(a[i], 1, n)]
end
out
end
function indexedcolor(data, pal)
mn = min(data); mx = max(data)
indexedcolor(data, pal, mx-mn, (mx+mn)/2)
end
function indexedcolor(data, pal, w, l)
n = length(pal)-1
if n == 0
return fill(pal[1], size(data))
end
w_min = l - w/2
scale = w==0 ? 1 : w/n
lut(pal, iround((data - w_min)./scale) + 1)
end
const palette_gray32 = [0xff000000,0xff080808,0xff101010,0xff181818,0xff202020,0xff292929,0xff313131,0xff393939,
0xff414141,0xff4a4a4a,0xff525252,0xff5a5a5a,0xff626262,0xff6a6a6a,0xff737373,0xff7b7b7b,
0xff838383,0xff8b8b8b,0xff949494,0xff9c9c9c,0xffa4a4a4,0xffacacac,0xffb4b4b4,0xffbdbdbd,
0xffc5c5c5,0xffcdcdcd,0xffd5d5d5,0xffdedede,0xffe6e6e6,0xffeeeeee,0xfff6f6f6,0xffffffff]
const palette_gray64 = [0xff000000,0xff040404,0xff080808,0xff0c0c0c,0xff101010,0xff141414,0xff181818,0xff1c1c1c,
0xff202020,0xff242424,0xff282828,0xff2c2c2c,0xff303030,0xff343434,0xff383838,0xff3c3c3c,
0xff404040,0xff444444,0xff484848,0xff4c4c4c,0xff505050,0xff555555,0xff595959,0xff5d5d5d,
0xff616161,0xff656565,0xff696969,0xff6d6d6d,0xff717171,0xff757575,0xff797979,0xff7d7d7d,
0xff818181,0xff858585,0xff898989,0xff8d8d8d,0xff919191,0xff959595,0xff999999,0xff9d9d9d,
0xffa1a1a1,0xffa5a5a5,0xffaaaaaa,0xffaeaeae,0xffb2b2b2,0xffb6b6b6,0xffbababa,0xffbebebe,
0xffc2c2c2,0xffc6c6c6,0xffcacaca,0xffcecece,0xffd2d2d2,0xffd6d6d6,0xffdadada,0xffdedede,
0xffe2e2e2,0xffe6e6e6,0xffeaeaea,0xffeeeeee,0xfff2f2f2,0xfff6f6f6,0xfffafafa,0xffffffff]
const palette_fire = [0xff5a5a5a,0xff636058,0xff6c6757,0xff756e56,0xff7e7455,0xff877b54,0xff908253,0xff998851,
0xffa28f50,0xffab964f,0xffb49c4e,0xffbda34d,0xffc6aa4c,0xffcfb04a,0xffd8b749,0xffe1be48,
0xffeac447,0xfff3cb46,0xfffdd245,0xfffccc42,0xfffcc640,0xfffcc03d,0xfffbba3b,0xfffbb438,
0xfffbae36,0xfffaa833,0xfffaa231,0xfffa9c2e,0xfffa962c,0xfff99029,0xfff98a27,0xfff98424,
0xfff87e22,0xfff8781f,0xfff8721d,0xfff76c1a,0xfff76618,0xfff76015,0xfff75a13,0xfff65410,
0xfff64e0e,0xfff6480b,0xfff54209,0xfff53c06,0xfff53604,0xfff53102,0xffe72e01,0xffd92b01,
0xffcc2801,0xffbe2601,0xffb02301,0xffa32001,0xff951d01,0xff881b01,0xff7a1801,0xff6c1500,
0xff5f1300,0xff511000,0xff440d00,0xff360a00,0xff280800,0xff1b0500,0xff0d0200,0xff000000]
const palette_rainbow = [0xff0e46e9,0xff0d58ea,0xff0c6bec,0xff0c7eee,0xff0b91f0,0xff0ba4f1,0xff0ab7f3,0xff0acaf5,
0xff09ddf7,0xff09f0f9,0xff06efbd,0xff04ef81,0xff02ee45,0xff00ee0a,0xff1cee08,0xff38ee07,
0xff54ee06,0xff70ee05,0xff8dee04,0xffa9ee03,0xffc5ee02,0xffe1ee01,0xfffeee00,0xfffcd401,
0xfffbba02,0xfffaa104,0xfff98705,0xfff86e07,0xfff75408,0xfff63b0a,0xfff5210b,0xfff4080d]
redval(p) = (p>>>16)&0xff
greenval(p) = (p>>>8)&0xff
blueval(p) = p&0xff
alphaval(p) = (p>>>24)&0xff
function imadjustintensity{T}(img::AbstractArray{T}, range)
assert_scalar_color(img)
if length(range) == 0
range = [min(img) max(img)]
elseif length(range) == 1
error("incorrect range")
end
tmp = (img - range[1])/(range[2] - range[1])
tmp[tmp .> 1] = 1
tmp[tmp .< 0] = 0
out = tmp
end
# FIXME
function rgb2gray{T}(img::Array{T,3})
n, m = size(img)
wr, wg, wb = 0.30, 0.59, 0.11
out = Array(T, n, m)
if ndims(img)==3 && size(img,3)==3
for i=1:n, j=1:m
out[i,j] = wr*img[i,j,1] + wg*img[i,j,2] + wb*img[i,j,3]
end
elseif is(eltype(img),Int32) || is(eltype(img),Uint32)
for i=1:n, j=1:m
p = img[i,j]
out[i,j] = wr*redval(p) + wg*greenval(p) + wb*blueval(p)
end
else
error("unsupported array type")
end
out
end
# FIXME
rgb2gray{T}(img::Array{T,2}) = img
function sobel()
f = [1.0 2.0 1.0; 0.0 0.0 0.0; -1.0 -2.0 -1.0]
return f, f'
end
function prewitt()
f = [1.0 1.0 1.0; 0.0 0.0 0.0; -1.0 -1.0 -1.0]
return f, f'
end
# average filter
function imaverage(filter_size)
if length(filter_size) != 2
error("wrong filter size")
end
m, n = filter_size[1], filter_size[2]
if mod(m, 2) != 1 || mod(n, 2) != 1
error("filter dimensions must be odd")
end
f = ones(Float64, m, n)/(m*n)
end
imaverage() = imaverage([3 3])
# laplacian filter kernel
function imlaplacian(diagonals::String)
if diagonals == "diagonals"
return [1.0 1.0 1.0; 1.0 -8.0 1.0; 1.0 1.0 1.0]
elseif diagonals == "nodiagonals"
return [0.0 1.0 0.0; 1.0 -4.0 1.0; 0.0 1.0 0.0]
end
end
imlaplacian() = imlaplacian("nodiagonals")
# more general version
function imlaplacian(alpha::Number)
lc = alpha/(1 + alpha)
lb = (1 - alpha)/(1 + alpha)
lm = -4/(1 + alpha)
return [lc lb lc; lb lm lb; lc lb lc]
end
# 2D gaussian filter kernel
function gaussian2d(sigma::Number, filter_size)
if length(filter_size) == 0
# choose 'good' size
m = 4*ceil(sigma)+1
n = m
elseif length(filter_size) != 2
error("wrong filter size")
else
m, n = filter_size[1], filter_size[2]
end
if mod(m, 2) != 1 || mod(n, 2) != 1
error("filter dimensions must be odd")
end
g = [exp(-(X.^2+Y.^2)/(2*sigma.^2)) for X=-floor(m/2):floor(m/2), Y=-floor(n/2):floor(n/2)]
return g/sum(g)
end
gaussian2d(sigma::Number) = gaussian2d(sigma, [])
gaussian2d() = gaussian2d(0.5, [])
# difference of gaussian
function imdog(sigma::Number)
m = 4*ceil(sqrt(2)*sigma)+1
return gaussian2d(sqrt(2)*sigma, [m m]) - gaussian2d(sigma, [m m])
end
imdog() = imdog(0.5)
# laplacian of gaussian
function imlog(sigma::Number)
m = 4*ceil(sigma)+1
return [((x^2+y^2-sigma^2)/sigma^4)*exp(-(x^2+y^2)/(2*sigma^2)) for x=-floor(m/2):floor(m/2), y=-floor(m/2):floor(m/2)]
end
imlog() = imlog(0.5)
# Sum of squared differences
ssd{T}(A::AbstractArray{T}, B::AbstractArray{T}) = sum((data(A)-data(B)).^2)
# normalized by Array size
ssdn{T}(A::AbstractArray{T}, B::AbstractArray{T}) = ssd(A, B)/length(A)
# sum of absolute differences
sad{T}(A::AbstractArray{T}, B::AbstractArray{T}) = sum(abs(data(A)-data(B)))
# normalized by Array size
sadn{T}(A::AbstractArray{T}, B::AbstractArray{T}) = sad(A, B)/length(A)
# normalized cross correlation
function ncc{T}(A::AbstractArray{T}, B::AbstractArray{T})
Am = (data(A)-mean(data(A)))[:]
Bm = (data(B)-mean(data(B)))[:]
return dot(Am,Bm)/(norm(Am)*norm(Bm))
end
function _imfilter{T}(img::StridedMatrix{T}, filter::Matrix{T}, border::String, value)
si, sf = size(img), size(filter)
A = zeros(T, si[1]+sf[1]-1, si[2]+sf[2]-1)
s1, s2 = int((sf[1]-1)/2), int((sf[2]-1)/2)
# correlation instead of convolution
filter = fliplr(fliplr(filter).')
mid1 = s1+1:s1+si[1]
mid2 = s2+1:s2+si[2]
left = 1:s2
right = size(A,2)-s2+1:size(A,2)
top = 1:s1
bot = size(A,1)-s1+1:size(A,1)
if border == "replicate"
A[mid1, mid2] = img
A[mid1, left] = repmat(img[:,1], 1, s2)
A[mid1, right] = repmat(img[:,end], 1, s2)
A[top, mid2] = repmat(img[1,:], s1, 1)
A[bot, mid2] = repmat(img[end,:], s1, 1)
A[top, left] = fliplr(fliplr(img[top, left])')
A[bot, left] = img[end-s1+1:end, left]'
A[top, right] = img[top, end-s2+1:end]'
A[bot, right] = flipud(fliplr(img[end-s1+1:end, end-s2+1:end]))'
elseif border == "circular"
A[mid1, mid2] = img
A[mid1, left] = img[:, end-s2+1:end]
A[mid1, right] = img[:, left]
A[top, mid2] = img[end-s1+1:end, :]
A[bot, mid2] = img[top, :]
A[top, left] = img[end-s1+1:end, end-s2+1:end]
A[bot, left] = img[top, end-s2+1:end]
A[top, right] = img[end-s1+1:end, left]
A[bot, right] = img[top, left]
elseif border == "mirror"
A[mid1, mid2] = img
A[mid1, left] = fliplr(img[:, left])
A[mid1, right] = fliplr(img[:, end-s2+1:end])
A[top, mid2] = flipud(img[top, :])
A[bot, mid2] = flipud(img[end-s1+1:end, :])
A[top, left] = fliplr(fliplr(img[top, left])')
A[bot, left] = img[end-s1+1:end, left]'
A[top, right] = img[top, end-s2+1:end]'
A[bot, right] = flipud(fliplr(img[end-s1+1:end, end-s2+1:end]))'
elseif border == "value"
A += value
A[mid1, mid2] = img
else
error("wrong border treatment")
end
# check if separable
# U, S, Vt = svdt(filter)
SVD = svdfact(filter)
U, S, Vt = SVD[:U], SVD[:S], SVD[:Vt]
separable = true;
for i = 2:length(S)
# assumption that <10^-7 \approx 0
separable = separable && (abs(S[i]) < 1e-7)
end
if separable
# conv2 isn't suitable for this (kernel center should be the actual center of the kernel)
#C = conv2(U[:,1]*sqrt(S[1]), vec(Vt[1,:])*sqrt(S[1]), A)
x = U[:,1]*sqrt(S[1])
y = vec(Vt[1,:])*sqrt(S[1])
sa = size(A)
m = length(y)+sa[1]
n = length(x)+sa[2]
B = zeros(T, m, n)
B[int(length(x)/2)+1:sa[1]+int(length(x)/2),int(length(y)/2)+1:sa[2]+int(length(y)/2)] = A
yp = zeros(T, m)
halfy = int((m-length(y)-1)/2)
yp[halfy+1:halfy+length(y)] = y
y = fft(yp)
xp = zeros(T, n)
halfx = int((n-length(x)-1)/2)
xp[halfx+1:halfx+length(x)] = x
x = fft(xp)
C = fftshift(ifft(fft(B) .* (y * x.')))
if T <: Real
C = real(C)
end
else
#C = conv2(A, filter)
sa, sb = size(A), size(filter)
At = zeros(T, sa[1]+sb[1]-1, sa[2]+sb[2]-1)
Bt = zeros(T, sa[1]+sb[1]-1, sa[2]+sb[2]-1)
halfa1 = ifloor((size(At,1)-sa[1])/2)
halfa2 = ifloor((size(At,2)-sa[2])/2)
halfb1 = ifloor((size(Bt,1)-sb[1])/2)
halfb2 = ifloor((size(Bt,2)-sb[2])/2)
At[halfa1+1:halfa1+sa[1], halfa2+1:halfa2+sa[2]] = A
Bt[halfb1+1:halfb1+sb[1], halfb2+1:halfb2+sb[2]] = filter
C = fftshift(ifft(fft(At).*fft(Bt)))
if T <: Real
C = real(C)
end
end
sc = size(C)
out = share(img, C[int(sc[1]/2-si[1]/2):int(sc[1]/2+si[1]/2)-1, int(sc[2]/2-si[2]/2):int(sc[2]/2+si[2]/2)-1])
end
# imfilter for multi channel images
function imfilter{T}(img::AbstractArray{T}, filter::Matrix{T}, border::String, value)
assert2d(img)
cd = colordim(img)
local A
if cd == 0
A = _imfilter(data(img), filter, border, value)
else
A = similar(data(img))
coords = Any[map(i->1:i, size(img))...]
for i = 1:size(img, cd)
coords[cd] = i
simg = slice(img, coords...)
tmp = _imfilter(simg, filter, border, value)
A[coords...] = tmp[:]
end
end
share(img, A)
end
imfilter(img, filter) = imfilter(img, filter, "replicate", 0)
imfilter(img, filter, border) = imfilter(img, filter, border, 0)
function imlineardiffusion{T}(img::Array{T,2}, dt::FloatingPoint, iterations::Integer)
u = img
f = imlaplacian()
for i = dt:dt:dt*iterations
u = u + dt*imfilter(u, f, "replicate")
end
u
end
function imgaussiannoise{T}(img::AbstractArray{T}, variance::Number, mean::Number)
return img + sqrt(variance)*randn(size(img)) + mean
end
imgaussiannoise{T}(img::AbstractArray{T}, variance::Number) = imgaussiannoise(img, variance, 0)
imgaussiannoise{T}(img::AbstractArray{T}) = imgaussiannoise(img, 0.01, 0)
function rgb2ntsc{T}(img::Array{T})
trans = [0.299 0.587 0.114; 0.596 -0.274 -0.322; 0.211 -0.523 0.312]
out = zeros(T, size(img))
for i = 1:size(img,1), j = 1:size(img,2)
out[i,j,:] = trans * vec(img[i,j,:])
end
return out
end
function ntsc2rgb{T}(img::Array{T})
trans = [1 0.956 0.621; 1 -0.272 -0.647; 1 -1.106 1.703]
out = zeros(T, size(img))
for i = 1:size(img,1), j = 1:size(img,2)
out[i,j,:] = trans * vec(img[i,j,:])
end
return out
end
function rgb2ycbcr{T}(img::Array{T})
trans = [65.481 128.533 24.966; -37.797 -74.203 112; 112 -93.786 -18.214]
offset = [16.0; 128.0; 128.0]
out = zeros(T, size(img))
for i = 1:size(img,1), j = 1:size(img,2)
out[i,j,:] = offset + trans * vec(img[i,j,:])
end
return out
end
function ycbcr2rgb{T}(img::Array{T})
trans = inv([65.481 128.533 24.966; -37.797 -74.203 112; 112 -93.786 -18.214])
offset = [16.0; 128.0; 128.0]
out = zeros(T, size(img))
for i = 1:size(img,1), j = 1:size(img,2)
out[i,j,:] = trans * (vec(img[i,j,:]) - offset)
end
return out
end
function imcomplement{T}(img::AbstractArray{T})
l = limits(img)
if l[2] != 1
error("imcomplement not defined unless upper limit is 1")
end
return 1 - img
end
function rgb2hsi{T}(img::Array{T})
R = img[:,:,1]
G = img[:,:,2]
B = img[:,:,3]
H = acos((1/2*(2*R - G - B)) ./ (((R - G).^2 + (R - B).*(G - B)).^(1/2)+eps(T)))
H[B .> G] = 2*pi - H[B .> G]
H /= 2*pi
rgb_sum = R + G + B
rgb_sum[rgb_sum .== 0] = eps(T)
S = 1 - 3./(rgb_sum).*min(R, G, B)
H[S .== 0] = 0
I = 1/3*(R + G + B)
return cat(3, H, S, I)
end
function hsi2rgb{T}(img::Array{T})
H = img[:,:,1]*(2pi)
S = img[:,:,2]
I = img[:,:,3]
R = zeros(T, size(img,1), size(img,2))
G = zeros(T, size(img,1), size(img,2))
B = zeros(T, size(img,1), size(img,2))
RG = 0 .<= H .< 2*pi/3
GB = 2*pi/3 .<= H .< 4*pi/3
BR = 4*pi/3 .<= H .< 2*pi
# RG sector
B[RG] = I[RG].*(1 - S[RG])
R[RG] = I[RG].*(1 + (S[RG].*cos(H[RG]))./cos(pi/3 - H[RG]))
G[RG] = 3*I[RG] - R[RG] - B[RG]
# GB sector
R[GB] = I[GB].*(1 - S[GB])
G[GB] = I[GB].*(1 + (S[GB].*cos(H[GB] - pi/3))./cos(H[GB]))
B[GB] = 3*I[GB] - R[GB] - G[GB]
# BR sector
G[BR] = I[BR].*(1 - S[BR])
B[BR] = I[BR].*(1 + (S[BR].*cos(H[BR] - 2*pi/3))./cos(-pi/3 - H[BR]))
R[BR] = 3*I[BR] - G[BR] - B[BR]
return cat(3, R, G, B)
end
function imstretch{T}(img::AbstractArray{T}, m::Number, slope::Number)
assert_scalar_color(img)
share(img, 1./(1 + (m./(data(img) + eps(T))).^slope))
end
function imedge{T}(img::Array{T}, method::String, border::String)
# needs more methods
if method == "sobel"
s1, s2 = sobel()
img1 = imfilter(img, s1, border)
img2 = imfilter(img, s2, border)
return img1, img2, sqrt(img1.^2 + img2.^2), atan2(img2, img1)
elseif method == "prewitt"
s1, s2 = prewitt()
img1 = imfilter(img, s1, border)
img2 = imfilter(img, s2, border)
return img1, img2, sqrt(img1.^2 + img2.^2), atan2(img2, img1)
end
end
imedge{T}(img::Array{T}, method::String) = imedge(img, method, "replicate")
imedge{T}(img::Array{T}) = imedge(img, "sobel", "replicate")
# forward and backward differences
# can be very helpful for discretized continuous models
forwarddiffy{T}(u::Array{T,2}) = [u[2:end,:]; u[end,:]] - u
forwarddiffx{T}(u::Array{T,2}) = [u[:,2:end] u[:,end]] - u
backdiffy{T}(u::Array{T,2}) = u - [u[1,:]; u[1:end-1,:]]
backdiffx{T}(u::Array{T,2}) = u - [u[:,1] u[:,1:end-1]]
function imROF{T}(img::Array{T,2}, lambda::Number, iterations::Integer)
# Total Variation regularized image denoising using the primal dual algorithm
# Also called Rudin Osher Fatemi (ROF) model
# lambda: regularization parameter
s1, s2 = size(img)
p = zeros(T, s1, s2, 2)
u = zeros(T, s1, s2)
grad_u = zeros(T, s1, s2, 2)
div_p = zeros(T, s1, s2)
dt = lambda/4
for i = 1:iterations
div_p = backdiffx(p[:,:,1]) + backdiffy(p[:,:,2])
u = img + div_p/lambda
grad_u = cat(3, forwarddiffx(u), forwarddiffy(u))
grad_u_mag = sqrt(grad_u[:,:,1].^2 + grad_u[:,:,2].^2)
tmp = 1 + grad_u_mag*dt
p = (dt*grad_u + p)./cat(3, tmp, tmp)
end
return u
end
# ROF Model for color images
function imROF{T}(img::Array{T,3}, lambda::Number, iterations::Integer)
out = zeros(T, size(img))
for i = 1:size(img, 3)
out[:,:,i] = imROF(img[:,:,i], lambda, iterations)
end
return out
end
# Conversions
# function convert(cs::String, img::Image) # FIXME
# local ret
# if cs == "ARGB"
# if colorspace(img) == "RGBA"
# cd = colordim(img)
# if cd == 0
# error("Not yet supported")
# end
# c = Any[map(i->1:i, size(img))...]
# c[cd] = [4,1,2,3]
# ret = copy(img, img[c...])
# ret.properties["colorspace"] = cs
# end
# end
# ret
# end
#
# function uint8(img::Image) # FIXME
# l = limits(img)
# r = l[2]/0xff
# copy(img, uint8(ifloor(img.data/r)))
# end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment