From ae26de98b894e8af7109294c6a85831583acaa0b Mon Sep 17 00:00:00 2001 From: "Longhao.Chen" Date: Tue, 3 Aug 2021 22:29:30 +0800 Subject: [PATCH 1/8] Add BM3D(sparse 3D transform-domain collaborative filtering) denoising algorithm. --- Project.toml | 1 + src/ReduceNoise/BM3DDenoise.jl | 65 ++++++++++++++++++++++++++++++++++ src/ReduceNoise/ReduceNoise.jl | 3 ++ 3 files changed, 69 insertions(+) create mode 100644 src/ReduceNoise/BM3DDenoise.jl diff --git a/Project.toml b/Project.toml index 8f6ce33..298f54c 100644 --- a/Project.toml +++ b/Project.toml @@ -12,6 +12,7 @@ MappedArrays = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] ColorVectorSpace = "0.7, 0.8, 0.9" diff --git a/src/ReduceNoise/BM3DDenoise.jl b/src/ReduceNoise/BM3DDenoise.jl new file mode 100644 index 0000000..2605c3d --- /dev/null +++ b/src/ReduceNoise/BM3DDenoise.jl @@ -0,0 +1,65 @@ +using UUIDs +const BM3DDenoise = Base.PkgId(UUID("95fb3b36-088a-43fb-bb1b-b1f34fadbd7d"), "BM3DDenoise") + +# Rewrite from ImageIO.jl +function checked_import(pkgid) + Base.root_module_exists(pkgid) && return Base.root_module(pkgid) + # If not available, load the library or throw an error. + Base.require(pkgid) +end + + +@doc raw""" + BM3D(σ [, config=bm3d_config()]) + +The BM3D(sparse 3D transform-domain collaborative filtering) denoising algorithm. + +!!! info + + This feature depends on the package: `BM3DDenoise` + + You can install it by `Pkg`: + ``` + using Pkg + Pkg.add("BM3DDenoise") + ``` + +# Arguments + +* `σ::Float64` is the variance of the noise. + +* `config::bm3d_config` is `BM3DDenoise.bm3d_config`. + +# Examples + +```julia +img = testimage("lena_color_256") + +n = AdditiveWhiteGaussianNoise(0.1) +noisy_img = apply_noise(img, n) + +# use default arguments +f_denoise = BM3D(0.1) +denoised_img = reduce_noise(noisy_img, f_denoise) +``` + +See also: [`reduce_noise`](@ref), [`reduce_noise!`](@ref) +""" +struct BM3D <: AbstractImageDenoiseAlgorithm + """degree of filtering""" + σ::Float64 + """bm3d_config""" + config + function BM3D(σ, config) + σ > 0 || @warn "σ is supposed to be positive" + new(σ, config) + end +end +BM3D(σ) = BM3D(σ, Base.invokelatest(checked_import(BM3DDenoise).bm3d_config)) + +function (f::BM3D)(out::AbstractArray, + img::AbstractArray) + axes(out) == axes(img) || ArgumentError("Images should have the same axes.") + out = Base.invokelatest(checked_import(BM3DDenoise).bm3d, img, f.σ, f.config) + return out +end \ No newline at end of file diff --git a/src/ReduceNoise/ReduceNoise.jl b/src/ReduceNoise/ReduceNoise.jl index 9a8b99a..2f41354 100644 --- a/src/ReduceNoise/ReduceNoise.jl +++ b/src/ReduceNoise/ReduceNoise.jl @@ -10,11 +10,14 @@ using ColorVectorSpace import ..NoiseAPI: AbstractImageDenoiseAlgorithm, reduce_noise, reduce_noise! include("compat.jl") +include("BM3DDenoise.jl") include("NonlocalMean.jl") export reduce_noise, reduce_noise!, + # BM3D + BM3D, # Non-local mean filter for gaussian noise NonlocalMean, get_NonlocalMean_rp From 322c5456c36210dc96a39e0206429adc46733ec3 Mon Sep 17 00:00:00 2001 From: "Longhao.Chen" Date: Wed, 4 Aug 2021 13:21:01 +0800 Subject: [PATCH 2/8] Fix(BM3D): Data type. --- src/ReduceNoise/BM3DDenoise.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ReduceNoise/BM3DDenoise.jl b/src/ReduceNoise/BM3DDenoise.jl index 2605c3d..5a00afa 100644 --- a/src/ReduceNoise/BM3DDenoise.jl +++ b/src/ReduceNoise/BM3DDenoise.jl @@ -57,9 +57,9 @@ struct BM3D <: AbstractImageDenoiseAlgorithm end BM3D(σ) = BM3D(σ, Base.invokelatest(checked_import(BM3DDenoise).bm3d_config)) -function (f::BM3D)(out::AbstractArray, - img::AbstractArray) +function (f::BM3D)(out::AbstractArray{T}, + img::AbstractArray{T}) where T axes(out) == axes(img) || ArgumentError("Images should have the same axes.") - out = Base.invokelatest(checked_import(BM3DDenoise).bm3d, img, f.σ, f.config) + out .= T.(Base.invokelatest(checked_import(BM3DDenoise).bm3d, img, f.σ, f.config)) return out end \ No newline at end of file From 201c4eba41fb2bb8c802e0310b738a84627f1473 Mon Sep 17 00:00:00 2001 From: "Longhao.Chen" Date: Wed, 4 Aug 2021 13:23:03 +0800 Subject: [PATCH 3/8] add example page(BM3D) --- docs/Project.toml | 1 + docs/examples/reduce_noise/BM3D.jl | 31 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 docs/examples/reduce_noise/BM3D.jl diff --git a/docs/Project.toml b/docs/Project.toml index c2b90ee..c958aa4 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,4 +1,5 @@ [deps] +BM3DDenoise = "95fb3b36-088a-43fb-bb1b-b1f34fadbd7d" DemoCards = "311a05b2-6137-4a5a-b473-18580a3d38b5" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" diff --git a/docs/examples/reduce_noise/BM3D.jl b/docs/examples/reduce_noise/BM3D.jl new file mode 100644 index 0000000..184e1a8 --- /dev/null +++ b/docs/examples/reduce_noise/BM3D.jl @@ -0,0 +1,31 @@ +# title: The BM3D(sparse 3D transform-domain collaborative filtering) denoising algorithm. +# id: bm3d-demo +# cover: assets/bm3d_cover.png +# date: 2021-08-04 +# author: Longhao Chen +# description: This demo shows how to use the BM3D denoising algorithm to reduce gaussian noise +# --- + +using ImageNoise +using TestImages, ImageShow, ImageCore, ImageQualityIndexes, ImageTransformations +using FileIO, Random #src + +# First, load an image and and add gaussian noise to it + +gray_img = float.(imresize(testimage("cameraman"), ratio=0.5)) +n = AdditiveWhiteGaussianNoise(0.1) +noisy_img = apply_noise(gray_img, n) + +# Then calling the standard `reduce_noise` API + +f_bm3d = BM3D(0.1) +denoised_img = reduce_noise(noisy_img, f_bm3d) + +mosaicview(gray_img, noisy_img, denoised_img; nrow=1) + +# Get the PSNR using ImageQualityIndexes package: + +assess_psnr(gray_img, denoised_img) + +mkpath("assets") #src +save("assets/bm3d_cover.png", denoised_img) #src \ No newline at end of file From df649a219d114abf67d0b12a2abd6a9b7916433d Mon Sep 17 00:00:00 2001 From: "Longhao.Chen" Date: Wed, 4 Aug 2021 14:11:51 +0800 Subject: [PATCH 4/8] Fix(BM3D): Data type --- src/ReduceNoise/BM3DDenoise.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ReduceNoise/BM3DDenoise.jl b/src/ReduceNoise/BM3DDenoise.jl index 5a00afa..9064f59 100644 --- a/src/ReduceNoise/BM3DDenoise.jl +++ b/src/ReduceNoise/BM3DDenoise.jl @@ -58,7 +58,7 @@ end BM3D(σ) = BM3D(σ, Base.invokelatest(checked_import(BM3DDenoise).bm3d_config)) function (f::BM3D)(out::AbstractArray{T}, - img::AbstractArray{T}) where T + img::AbstractArray) where T axes(out) == axes(img) || ArgumentError("Images should have the same axes.") out .= T.(Base.invokelatest(checked_import(BM3DDenoise).bm3d, img, f.σ, f.config)) return out From b9d7f59dcd2c7d7688de4d98a1a69443f0da0b2b Mon Sep 17 00:00:00 2001 From: "Longhao.Chen" Date: Wed, 4 Aug 2021 14:12:29 +0800 Subject: [PATCH 5/8] Add regression test (BM3D) --- Project.toml | 3 ++- test/ReduceNoise/BM3DDenoise.jl | 14 ++++++++++++++ test/runtests.jl | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 test/ReduceNoise/BM3DDenoise.jl diff --git a/Project.toml b/Project.toml index 298f54c..1fdfe69 100644 --- a/Project.toml +++ b/Project.toml @@ -25,6 +25,7 @@ Reexport = "0.2, 1.0" julia = "1" [extras] +BM3DDenoise = "95fb3b36-088a-43fb-bb1b-b1f34fadbd7d" ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" ImageQualityIndexes = "2996bd0c-7a13-11e9-2da2-2f5ce47296a9" ImageTransformations = "02fcd773-0e25-5acc-982a-7f6622650795" @@ -33,4 +34,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990" [targets] -test = ["ImageMagick", "ImageQualityIndexes", "ImageTransformations", "ReferenceTests", "Test", "TestImages"] +test = ["BM3DDenoise", "ImageMagick", "ImageQualityIndexes", "ImageTransformations", "ReferenceTests", "Test", "TestImages"] diff --git a/test/ReduceNoise/BM3DDenoise.jl b/test/ReduceNoise/BM3DDenoise.jl new file mode 100644 index 0000000..cb28061 --- /dev/null +++ b/test/ReduceNoise/BM3DDenoise.jl @@ -0,0 +1,14 @@ +@testset "BM3DDenoise" begin + @info "Test: BM3DDenoise" + @testset "Numeric" begin + img_gray = n0f8.(imresize(testimage("lena_gray_256"); ratio=0.25)) + n = AdditiveWhiteGaussianNoise(0.05) + noisy_img = apply_noise(img_gray, n; rng=MersenneTwister(0)) + + f = BM3D(0.05) + denoised_img = reduce_noise(noisy_img, f) + # further modification shall not decrease psnr and ssim + @test assess(PSNR(), denoised_img, img_gray) >= 28. + @test assess(SSIM(), denoised_img, img_gray) >= 0.9 + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 075acf0..529a2aa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -12,6 +12,7 @@ include("ApplyNoise/AdditiveWhiteGaussianNoise.jl") # ReduceNoise @info "Test: ReduceNoise" include("ReduceNoise/NonlocalMean.jl") +include("ReduceNoise/BM3DDenoise.jl") end nothing From 4fd1864457a985218782423149ec641f510ed87f Mon Sep 17 00:00:00 2001 From: "Longhao.Chen" Date: Wed, 4 Aug 2021 18:54:58 +0800 Subject: [PATCH 6/8] Update docs/examples/reduce_noise/BM3D.jl democards grammar. Co-authored-by: Johnny Chen --- docs/examples/reduce_noise/BM3D.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/examples/reduce_noise/BM3D.jl b/docs/examples/reduce_noise/BM3D.jl index 184e1a8..667abcd 100644 --- a/docs/examples/reduce_noise/BM3D.jl +++ b/docs/examples/reduce_noise/BM3D.jl @@ -1,9 +1,10 @@ +# --- # title: The BM3D(sparse 3D transform-domain collaborative filtering) denoising algorithm. # id: bm3d-demo # cover: assets/bm3d_cover.png # date: 2021-08-04 -# author: Longhao Chen -# description: This demo shows how to use the BM3D denoising algorithm to reduce gaussian noise +# author: "[Longhao Chen](https://github.com/Longhao-Chen)" +# description: Use the BM3D denoising algorithm to reduce gaussian noise # --- using ImageNoise @@ -28,4 +29,4 @@ mosaicview(gray_img, noisy_img, denoised_img; nrow=1) assess_psnr(gray_img, denoised_img) mkpath("assets") #src -save("assets/bm3d_cover.png", denoised_img) #src \ No newline at end of file +save("assets/bm3d_cover.png", denoised_img) #src From 66393aaff0e0f149f6590eb0c42b26ae3d6d12c3 Mon Sep 17 00:00:00 2001 From: "Longhao.Chen" Date: Wed, 4 Aug 2021 19:09:08 +0800 Subject: [PATCH 7/8] Make BM3DDenoise as a direct dependency. --- Project.toml | 5 +++-- docs/Project.toml | 1 - src/ReduceNoise/BM3DDenoise.jl | 10 ---------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Project.toml b/Project.toml index c510b74..ca3e048 100644 --- a/Project.toml +++ b/Project.toml @@ -4,6 +4,7 @@ authors = ["Johnny Chen "] version = "0.1.2" [deps] +BM3DDenoise = "95fb3b36-088a-43fb-bb1b-b1f34fadbd7d" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" @@ -11,13 +12,13 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] +BM3DDenoise = "1.0" Distributions = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" ImageCore = "0.9" Reexport = "0.2, 1.0" julia = "1.6" [extras] -BM3DDenoise = "95fb3b36-088a-43fb-bb1b-b1f34fadbd7d" ImageIO = "82e4d734-157c-48bb-816b-45c225c6df19" ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" ImageQualityIndexes = "2996bd0c-7a13-11e9-2da2-2f5ce47296a9" @@ -27,4 +28,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990" [targets] -test = ["BM3DDenoise", "ImageIO", "ImageMagick", "ImageQualityIndexes", "ImageTransformations", "ReferenceTests", "Test", "TestImages"] +test = ["ImageIO", "ImageMagick", "ImageQualityIndexes", "ImageTransformations", "ReferenceTests", "Test", "TestImages"] diff --git a/docs/Project.toml b/docs/Project.toml index 70a6e8a..c16f529 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,4 @@ [deps] -BM3DDenoise = "95fb3b36-088a-43fb-bb1b-b1f34fadbd7d" DemoCards = "311a05b2-6137-4a5a-b473-18580a3d38b5" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" diff --git a/src/ReduceNoise/BM3DDenoise.jl b/src/ReduceNoise/BM3DDenoise.jl index 9064f59..36174b4 100644 --- a/src/ReduceNoise/BM3DDenoise.jl +++ b/src/ReduceNoise/BM3DDenoise.jl @@ -14,16 +14,6 @@ end The BM3D(sparse 3D transform-domain collaborative filtering) denoising algorithm. -!!! info - - This feature depends on the package: `BM3DDenoise` - - You can install it by `Pkg`: - ``` - using Pkg - Pkg.add("BM3DDenoise") - ``` - # Arguments * `σ::Float64` is the variance of the noise. From c7f9cae897caa8ad555d0fe9fd4c1f86f4feb07c Mon Sep 17 00:00:00 2001 From: Johnny Chen Date: Wed, 4 Aug 2021 19:12:44 +0800 Subject: [PATCH 8/8] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index ca3e048..ae1d120 100644 --- a/Project.toml +++ b/Project.toml @@ -12,7 +12,7 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] -BM3DDenoise = "1.0" +BM3DDenoise = "1.0.1" Distributions = "0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" ImageCore = "0.9" Reexport = "0.2, 1.0"