Skip to content

Commit

Permalink
Merge pull request #35 from rakeshksr/fileio
Browse files Browse the repository at this point in the history
Initial support for FileIO
  • Loading branch information
rakeshksr authored Oct 28, 2024
2 parents ccc99cc + dd98c04 commit 34dcb51
Show file tree
Hide file tree
Showing 13 changed files with 247 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ docs/site/
# It records a fixed state of all packages used by the project. As such, it should not be
# committed for packages, but should be committed for applications that require a static
# environment.
Manifest.toml
Manifest.toml

.vscode
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ version = "4.6.0"

[deps]
CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
OpenCV_jll = "33b9d88c-85f9-5d73-bd91-4e2b95a9aa0b"

[compat]
FileIO = "1.16"
CxxWrap = "0.16"
julia = "1.10"
julia = "1.10"
3 changes: 2 additions & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
OpenCV = "f878e3a2-a245-4720-8660-60795d644f2a"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
OpenCV = "f878e3a2-a245-4720-8660-60795d644f2a"
4 changes: 4 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ DocMeta.setdocmeta!(OpenCV, :DocTestSetup, :(using OpenCV); recursive=true)
makedocs(;
modules=[OpenCV],
sitename="OpenCV.jl",
pages = [
"OpenCV.jl" => "index.md"
"Getting started with Images" => "Getting started with Images.md"
]
)

deploydocs(;
Expand Down
106 changes: 106 additions & 0 deletions docs/src/Getting started with Images.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Reading and Writing of Images

OpenCV provides a wide range of functions for image processing, including reading and writing images.

OpenCV.jl provides 2 ways to read and write images
1. OpenCV native api
2. FileIO.jl api

OpenCV provides `imread` and `imwrite`, while FileIO privides `load` and `save` for similar functionalities


!!! note

FileIO api not suppport all image formats currently but it support major formats.
If FileIO api not works then use OpenCV native api

## Reading Images

```julia
using OpenCV

img_path = "/path/to/image"
img = OpenCV.imread(img_path)
```
with FileIO
```julia
using OpenCV, FileIO

img_path = "/path/to/image"
img = load(img_path)
```

in both cases `img` has same data. Both methods accept same reading flags[^imreadflags].

```julia
using OpenCV

img_path = "/path/to/image"
flag = OpenCV.IMREAD_UNCHANGED
img = OpenCV.imread(img_path, flag)
```
with FileIO
```julia
using OpenCV, FileIO

img_path = "/path/to/image"
flag = OpenCV.IMREAD_UNCHANGED
img = load(img_path, flag)
```

## Writing Images
```julia
using OpenCV

img = rand(UInt8, 1000, 1000) |> OpenCV.Mat
img_path = "/path/to/image"
OpenCV.imwrite(img_path, img)
```
with FileIO
```julia
using OpenCV, FileIO

img = rand(UInt8, 1000, 1000) |> OpenCV.Mat
img_path = "/path/to/image"
save(img_path, img)
```

Both methods accept same writing flags[^imwriteflags].

```julia
using OpenCV

img = rand(UInt8, 1000, 1000) |> OpenCV.Mat
img_path = "/path/to/image"
flag = Int32[OpenCV.IMWRITE_JPEG_QUALITY, 100]
OpenCV.imwrite(img_path, img, flag)
```
with FileIO
```julia
using OpenCV, FileIO

img = rand(UInt8, 1000, 1000) |> OpenCV.Mat
img_path = "/path/to/image"
flag = Int32[OpenCV.IMWRITE_JPEG_QUALITY, 100]
save(img_path, img, flag)
```

## Displaying Images

When working with images, it's obviously helpful to be able to look at them. If you use Julia through Pluto, VSCode, or IJulia, images should display automatically.

Preview from Pluto.jl

![pluto preview](assets/pluto.png)

`OpenCV.imshow` method display image on Qt window.

![qt preview](assets/qt.png)

`Plots.jl` To-do

`Makie.jl` To-do

## Notes
[^imreadflags]: https://docs.opencv.org/4.x/d8/d6a/group__imgcodecs__flags.html#ga61d9b0126a3e57d9277ac48327799c80
[^imwriteflags]: https://docs.opencv.org/4.x/d8/d6a/group__imgcodecs__flags.html#ga292d81be8d76901bff7988d18d2b42ac
Binary file added docs/src/assets/pluto.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/src/assets/qt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/OpenCV.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
module OpenCV

using OpenCV_jll
using FileIO
using FileIO: DataFormat, File, Stream, stream

include(joinpath(OpenCV_jll.artifact_dir, "OpenCV", "src", "OpenCV.jl"))

include("fileio.jl")
include("show.jl")

end
58 changes: 58 additions & 0 deletions src/fileio.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const _IMAGE_DATA_FORMATS = Union{
format"BMP",
format"JP2",
format"JPEG",
format"PNG",
format"TIFF",
}

function _get_format_extension(fmt)
FileIO.info(fmt)[2]
end

## Load Images

function load(f::File{T}) where {T<:_IMAGE_DATA_FORMATS}
data = imread(f.filename)
return data
end

function load(f::File{T}, flags::Int) where {T<:_IMAGE_DATA_FORMATS}
data = imread(f.filename, flags)
return data
end

function load(s::Stream{T}) where {T<:_IMAGE_DATA_FORMATS}
data = read(stream(s))
img = imdecode(reshape(data, 1, 1, :))
return img
end

function load(s::Stream{T}, flags::Int) where {T<:_IMAGE_DATA_FORMATS}
data = read(stream(s))
img = imdecode(reshape(data, 1, 1, :), flags)
return img
end

## Save Images

function save(f::File{T}, image::InputArray) where {T<:_IMAGE_DATA_FORMATS}
imwrite(f.filename, image)
end

function save(f::File{T}, image::InputArray, params::Array{Int32,1}) where {T<:_IMAGE_DATA_FORMATS}
imwrite(f.filename, image, params)
end

function save(s::Stream{T}, image::InputArray) where {T<:_IMAGE_DATA_FORMATS}
ext = _get_format_extension(T)
enc_img = imencode(ext, image)[2]
Base.write(stream(s), enc_img)
end

function save(s::Stream{T}, image::InputArray, params::Vector{Int32}) where {T<:_IMAGE_DATA_FORMATS}
ext = _get_format_extension(T)
enc_img = imencode(ext, image, params)[2]
Base.write(stream(s), enc_img)
end

5 changes: 5 additions & 0 deletions src/show.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
_format_stream(format, io) = Stream{format}(io)

function Base.show(io::IO, ::MIME"image/png", image::Mat{T}) where {T<:dtypes}
save(_format_stream(DataFormat{:PNG}, io), image)
end
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[deps]
Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
LazyArtifacts = "4af54fe1-eca0-43a8-85a7-787d91b784e3"
OpenCV = "f878e3a2-a245-4720-8660-60795d644f2a"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Artifacts
using LazyArtifacts
using OpenCV
using FileIO
using Test

if "OPENCV_TEST_DATA_PATH" in keys(ENV)
Expand All @@ -16,4 +17,5 @@ end
include("test_imgproc.jl")
include("test_objdetect.jl")
include("test_dnn.jl")
include("test_fileio.jl")
end
58 changes: 58 additions & 0 deletions test/test_fileio.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
tmpdir = mktempdir()

images_path = joinpath(opencv_extra_path, "testdata", "python", "images")
images = readdir(images_path, join=true)

bmp_images = filter(endswith(".bmp"), images)
# jp2_images = filter(endswith(".jp2"), images) # Not available
jpg_images = filter(endswith(".jpg"), images)
png_images = filter(endswith(".png"), images)
tiff_images = filter(endswith(".tiff"), images)

@testset "BMP" begin
for (idx, img_path) in enumerate(bmp_images)
img1 = load(img_path)
f = joinpath(tmpdir, "img_$idx.bmp")
save(f, img1)
img2 = load(f)
@test img1 == img2
end
end

# @testset "JP2" begin
# img1 = rand(UInt8, 3, 1024, 1024) |> OpenCV.Mat
# f = joinpath(tmpdir, "img.jp2")
# save(f, img1)
# img2 = load(f)
# @test OpenCV.PSNR(img1, img2) > 15
# end

@testset "JPG" begin
for (idx, img_path) in enumerate(jpg_images)
img1 = load(img_path)
f = joinpath(tmpdir, "img_$idx.jpg")
save(f, img1)
img2 = load(f)
@test OpenCV.PSNR(img1, img2) > 30
end
end

@testset "PNG" begin
for (idx, img_path) in enumerate(png_images)
img1 = load(img_path)
f = joinpath(tmpdir, "img_$idx.png")
save(f, img1)
img2 = load(f)
@test img1 == img2
end
end

@testset "TIFF" begin
for (idx, img_path) in enumerate(tiff_images)
img1 = load(img_path)
f = joinpath(tmpdir, "img_$idx.tiff")
save(f, img1)
img2 = load(f)
@test img1 == img2
end
end

0 comments on commit 34dcb51

Please sign in to comment.