A Julia package for enhancing and manipulating image contrast.
juliaimages / imagecontrastadjustment.jl Goto Github PK
View Code? Open in Web Editor NEWA Julia package for enhancing and manipulating image contrast.
License: MIT License
A Julia package for enhancing and manipulating image contrast.
License: MIT License
I've been mentally bikeshedding the linear contrast stretching interface discussed in this thread. I'd planned to just add a few methods to scaleminmax
in ImageCore, but I think the functionality fits better in this sub-package.
I think adjust_histogram
is a misnomer for the functions within this module that don't involve the construction or adjustment of an image histogram. Looking at scikit-image's exposure
module, a distinction is made between histogram-based and non-histogram-based intensity adjustment functions. The same is true for Matlab's image processing toolbox.
With that in mind, I'd like to propose that the non-histogram-based algorithms be moved to a new category AbstractIntensityMappingAlgorithm <: AbstractImageFilter
. This would include LinearStretching
, ConstrastStretching
, GammaCorrection
, and other non-binning, invertible maps.
So I know it's a long stretch but I am working on a project where colored images are badly treated. I sometimes run adjust_histogram(img, Equalization())
and it appears that in transform_density
, the input img
contains NaN
value and an error is returned.
Then the line
index = floor(Int, (val-first_edge)*inv_step_size) + 1
returns an error when isnan(val)
To be honest I don't really know where the NaN
values come from.
There's significant overlap between LinearStretching
and a family of related, non-deprecated functions in ImageCore
(https://juliaimages.org/latest/function_reference/#ImageCore.scaleminmax, etc.). However, the overlap isn't complete (there's no analogue here for scalesigned(min, center, max)
, and the APIs don't match, which may become a source of confusion. To reduce the size of the API surface, the missing methods should be added to ImageContrastAdjustment, and the corresponding functions in ImageCore should be deprecated.
To incorporate scalesigned(min, center, max)
and scalesigned(maxabs)
into LinearStretching
, the source -> target intensity mapping can be generalized to accept three (or more) intensity levels, representing a piecewise-linear intensity transformation. Johnny's recent PR #28 is a good base (thanks!), but the function and interface would need to be further overhauled for piecewise-linear maps.
I'd also like to cover the use-case described by @bjarthur in issue #27:
My sole use case is imadjustintensity(img, quantile(img,[0.01,0.99])), which i find quite good at eliminating outliers when adjusting the brightness.
I've typed out the exact same function call countless times in various projects over the last few years. For a more Julian interface, let's look to Percentile
. For example,
LinearStretching(Percentiles(1, 99))
LinearStretching(Quantiles(.015, .985))
LinearStretching(Percentiles(0, 50, 100), (-1, 0, 1))
would replace scalesigned(min, center, max)
LinearStretching(maxabs, (-1, 0, 1))
would replace scalesigned(maxabs)
I'm reading through various benchmark workflows to get some ideas as to how to set up my own.
I think the comment below may no longer be true.
ImageContrastAdjustment.jl/benchmark/run_benchmarks.jl
Lines 6 to 7 in 5642b3a
Combining:
I think a label trigger can be achieved with the following YAML adjustments.
on:
label:
types: [created, edited]
...
steps:
- name: Triggered by label
if: ${{ github.event_name == 'label' && github.event.label.name == 'run benchmark' }}
The label
event will only trigger a workflow run if the workflow file is on the master or default branch.
All totally untested of course.
The tag name "0.1.1" is not of the appropriate SemVer form (vX.Y.Z).
cc: @zygmuntszpak
This issue is used to trigger TagBot; feel free to unsubscribe.
If you haven't already, you should update your TagBot.yml
to include issue comment triggers.
Please see this post on Discourse for instructions and more details.
If you'd like for me to do this for you, comment TagBot fix
on this issue.
I'll open a PR within a few hours, please be patient!
I have recently faced a problem that needs adaptive linear stretching. Basically, the image has different value range at different regions, applying linear stretching globally would not be able to enhance the local contrast.
I assume there should be algorithms similar to the Contrast Limited Adaptive Histogram Equalization that can enhance local contrast. but my naive implementation (split images to regions and apply linear stretching locally) have significant edges artifacts.
if already established methods exists, it would be great help for situation I faced.
the args to imadjustintensity
specify the "from" range, whereas those of the same name to LinearStretching
are the "to" range. are there plans to add this functionality to the new API before the old is deprecated? my sole use case is imadjustintensity(img, quantile(img,[0.01,0.99]))
, which i find quite good at eliminating outliers when adjusting the brightness.
great to finally get rid of the "im" prefix! thanks for that!
adjust_histogram(img, ContrastStretching())
is suggested as a deprecation for imstretch
; with --depwarn=yes
, we get
julia> using Images
julia> img = Gray{N0f8}.([1 0; 0 1])
2×2 Array{Gray{N0f8},2} with eltype Gray{N0f8}:
Gray{N0f8}(1.0) Gray{N0f8}(0.0)
Gray{N0f8}(0.0) Gray{N0f8}(1.0)
julia> imgs = imstretch(img, 0.3, 0.4)
┌ Warning: `imstretch` will be removed in a future release, please use `adjust_histogram(img, ContrastStretching())` instead.
│ caller = top-level scope at REPL[3]:1
└ @ Core REPL[3]:1
2×2 Array{Gray{Float64},2} with eltype Gray{Float64}:
Gray{Float64}(0.618123) Gray{Float64}(0.00274462)
Gray{Float64}(0.00274462) Gray{Float64}(0.618123)
(As pointed out in JuliaImages/Images.jl#865 (comment), it would have been nice if this had suggested "please use adjust_histogram(img, ContrastStretching(; t=0.3, slope=0.4))
instead so that it was copy/pastable.)
But if we follow the suggestion, we get:
julia> adjust_histogram(img, ContrastStretching(t=0.3, slope=0.4))
2×2 Array{Gray{N0f8},2} with eltype Gray{N0f8}:
Gray{N0f8}(0.0) Gray{N0f8}(0.149)
Gray{N0f8}(0.149) Gray{N0f8}(0.0)
which is very different. However:
julia> adjust_histogram(float.(img), ContrastStretching(t=0.3, slope=0.4))
2×2 Array{Gray{Float32},2} with eltype Gray{Float32}:
Gray{Float32}(0.618123) Gray{Float32}(0.00274462)
Gray{Float32}(0.00274462) Gray{Float32}(0.618123)
indicating that it's overflow at fault.
(Perhaps, as @johnnychen94 knows,) I am currently rethinking the definition of default color spaces for YIQ
and YCbCr
in ColorTypes.jl and Colors.jl. (cf. JuliaGraphics/Colors.jl#453, JuliaGraphics/ColorTypes.jl#250)
AFAIK, this is the only package that explicitly uses YIQ
. This package is indifferent about the gamma of YIQ color space, even though it is designed to manipulate the contrast. 😅
If the implementation of the conversion from RGB
etc. to YIQ
is slightly changed, will there be any inconvenience?
In any case, for compatibility and convenience reasons, I think it might be a good idea to allow the user to explicitly specify the color space in which to manipulate the contrast.
So, what about adding the following getter and setter to the keyword arguments of the API?
getluma(c::Colorant)
setluma(c::Colorant, luma::Real)
Also, what about switching the default implementation of the getters and setters depending on the color type?
For example:
color types | luma-like value |
---|---|
(fallback) | YIQ(c).y |
Gray |
gray(c) |
HSV |
c.v |
HSL |
c.l |
HSI |
c.i |
Lab /Luv |
c.l / 100 |
XYZ /xyY |
xyY(c).Y |
Of course, the feature should be realized with outside of this package by using MappedArray
or something. My main aim is to reduce the impact of breaking changes in ColorTypes.jl and Colors.jl.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.