-
Notifications
You must be signed in to change notification settings - Fork 143
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
Histogram Equalisation #458
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -282,6 +282,7 @@ findlocalminima | |
|
||
```@docs | ||
imhist | ||
histeq | ||
``` | ||
|
||
# Filtering kernels | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1239,6 +1239,105 @@ end | |
|
||
imhist{T<:Union{Gray,Number}}(img::AbstractArray{T}, nbins, minval, maxval) = imhist(img, nbins, convert(T, minval), convert(T, maxval)) | ||
|
||
""" | ||
``` | ||
hist_equalised_img = histeq(img, nbins, dtype = "8bit") | ||
hist_equalised_img = histeq(img, nbins, minval, maxval, dtype = "8bit") | ||
``` | ||
|
||
Returns a histogram equalised image with a granularity of approximately `nbins` | ||
number of bins. An optional `dtype` argument (defaulting to 8bit) can be specified | ||
to choose the number of bits of the returned image. | ||
|
||
The `histeq` function can handle a variety of input types. The returned image depends | ||
on the input type. If the input is an `Image` then the resulting image is of the same type | ||
and has the same properties. | ||
|
||
For coloured images, the input is converted to YCbCr type and the Y channel is equalised. This | ||
is the combined with the Cb and Cr channels and the resulting image converted to the same type | ||
as the input. | ||
|
||
If minval and maxval are specified then only the intensities in the range | ||
(minval, maxval) are equalised. | ||
|
||
""" | ||
|
||
RET_TYPE = Dict("8bit" => Gray{U8}, "16bit" => Gray{FixedPointNumbers.UFixed{UInt16,16}}) | ||
Y_MIN = 16 | ||
Y_MAX = 235 | ||
|
||
function _prep_image_for_histeq(img::AbstractArray, dtype) | ||
img_shape = size(img) | ||
if dtype == "8bit" | ||
img = [convert(base_colorant_type(c){FixedPointNumbers.UFixed{UInt8,8}}, c) for c in img] | ||
elseif dtype == "16bit" | ||
img = [convert(base_colorant_type(c){FixedPointNumbers.UFixed{UInt16,16}}, c) for c in img] | ||
end | ||
img = reshape(img, img_shape) | ||
img | ||
end | ||
|
||
histeq{T<:Colorant}(img::AbstractArray{T}, nbins, dtype = "8bit") = histeq(_prep_image_for_histeq(img, dtype), nbins, zero(YCbCr), zero(YCbCr)) | ||
histeq{T<:Colorant}(img::AbstractArray{T}, nbins, minval, maxval, dtype = "8bit") = histeq(_prep_image_for_histeq(img, dtype), nbins, minval, maxval) | ||
|
||
function recompose_y(c::Color, eq_Y::Float32) | ||
c_ycbcr = convert(YCbCr, color(c)) | ||
ret_c = YCbCr(eq_Y, c_ycbcr.cb, c_ycbcr.cr) | ||
ret_c | ||
end | ||
|
||
function recompose_y(c::TransparentColor, eq_Y::Float32) | ||
c_ycbcr = convert(YCbCrA, color(c)) | ||
ret_c = YCbCrA(eq_Y, c_ycbcr.cb, c_ycbcr.cr, c_ycbcr.alpha) | ||
ret_c | ||
end | ||
|
||
function histeq{T<:Colorant}(img::AbstractArray{T}, nbins, minval, maxval) | ||
Y = [convert(YCbCr, color(c)).y for c in img] | ||
if maxval == zero(YCbCr{Float32}) | ||
eq_Y = histeq(Y, nbins, Y_MIN, Y_MAX) | ||
else | ||
eq_Y = histeq(Y, nbins, minval, maxval) | ||
end | ||
hist_equalised_img = reshape([convert(T, recompose_y(c, eq_Y[i])) for (i, c) in enumerate(img)], size(img)) | ||
hist_equalised_img | ||
end | ||
|
||
function histeq(img::AbstractImage, nbins, dtype = "8bit") | ||
hist_equalised_img = histeq(data(img), nbins, dtype) | ||
hist_equalised_img = shareproperties(img, hist_equalised_img) | ||
hist_equalised_img | ||
end | ||
|
||
function histeq(img::AbstractImage, nbins, minval, maxval, dtype = "8bit") | ||
hist_equalised_img = histeq(data(img), nbins, minval, maxval, dtype) | ||
hist_equalised_img = shareproperties(img, hist_equalised_img) | ||
hist_equalised_img | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you merge this and the previous into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Result of merging the two methods gives the following - julia> detect_ambiguities(Images)
Skipping Images.indexedcolor
Skipping Images.iterate_spatial
Skipping Images.lut
Skipping Images.palette_fire
Skipping Images.palette_gray32
Skipping Images.palette_gray64
Skipping Images.palette_rainbow
Skipping Images.uint16sc
Skipping Images.uint32sc
Skipping Images.uint8sc
1-element Array{Tuple{Method,Method},1}:
(histeq(img::Images.AbstractImage, args...) at /home/jarvis/.julia/v0.5/Images/src/algorithms.jl:1286,histeq{T<:Union{ColorTypes.Gray{T<:Union{AbstractFloat,Bool,FixedPointNumbers.FixedPoint}},Number}}(img::AbstractArray{T,N<:Any}, nbins::Int64, minval::T, maxval::T) at /home/jarvis/.julia/v0.5/Images/src/algorithms.jl:1300)
Without merging I get - julia> detect_ambiguities(Images)
Skipping Images.indexedcolor
Skipping Images.iterate_spatial
Skipping Images.lut
Skipping Images.palette_fire
Skipping Images.palette_gray32
Skipping Images.palette_gray64
Skipping Images.palette_rainbow
Skipping Images.uint16sc
Skipping Images.uint32sc
Skipping Images.uint8sc
1-element Array{Tuple{Method,Method},1}:
(histeq(img::Images.AbstractImage, nbins, minval, maxval) at /home/jarvis/.julia/v0.5/Images/src/algorithms.jl:1292,histeq{T<:Union{ColorTypes.Gray{T<:Union{AbstractFloat,Bool,FixedPointNumbers.FixedPoint}},Number}}(img::AbstractArray{T,N<:Any}, nbins::Int64, minval::T, maxval::T) at /home/jarvis/.julia/v0.5/Images/src/algorithms.jl:1300) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks easiest to solve the ambiguity if you don't merge the methods. Just make sure the last 3 arguments in the two ambiguous methods have the same signature constraints, and you should be fine. |
||
|
||
function histeq{T<:TransparentGray}(img::AbstractArray{T}, args...) | ||
opaque_img = [color(c) for c in img] | ||
hist_equalised_img = histeq(opaque_img, args...) | ||
hist_equalised_img = reshape([convert(T, AGray(hist_equalised_img[i], alpha(c))) for (i, c) in enumerate(img)], size(img)) | ||
hist_equalised_img | ||
end | ||
|
||
histeq{T<:Gray}(img::AbstractArray{T}, nbins, dtype = "8bit") = histeq(_prep_image_for_histeq(img, dtype), nbins, ColorVectorSpace.typemin(RET_TYPE[dtype]), ColorVectorSpace.typemax(RET_TYPE[dtype])) | ||
|
||
function histeq{T<:Union{Gray,Number}}(img::AbstractArray{T}, nbins::Int, minval::T, maxval::T) | ||
bins, histogram = imhist(img, nbins, minval, maxval) | ||
cdf = cumsum(histogram[2:end-1]) | ||
img_shape = size(img) | ||
cdf_length = size(cdf)[1] | ||
hist_equalised_img = [max(1,Int(ceil((x-minval)*cdf_length/(maxval-minval)))) for x in img] | ||
hist_equalised_img = [minval + ((cdf[x]-cdf[1])*(maxval-minval)/(cdf[end]-cdf[1])) for x in hist_equalised_img] | ||
hist_equalised_img = reshape(hist_equalised_img, img_shape) | ||
hist_equalised_img | ||
end | ||
|
||
histeq{T<:Number}(img::AbstractArray{T}, nbins) = histeq(img, nbins, minfinite(img), maxfinite(img)) | ||
|
||
histeq{T<:Union{Gray,Number}}(img::AbstractArray{T}, nbins, minval, maxval) = histeq(img, Int(nbins), convert(T, minval), convert(T, maxval)) | ||
|
||
""" | ||
`imgr = restrict(img[, region])` performs two-fold reduction in size | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason, images of type
Image
are not directed to this(and the next) function. These seem to give wrong answers too -There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you don't have a stale module problem? All those evaluate to
true
for me. Try a fresh julia session.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gosh. Had no idea about this issue. It worked in the new session.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's quite subtle, but the way to think about it is that if you load a module
Mod
, and thenreload
orinclude
it again, then any objects created before reloading have anOldMod
type (even though the name still prints asMod
). For your tests, you have to define new objects for the new types.