From 5753120fb8bf50ea707890f5917faf6bd7631b26 Mon Sep 17 00:00:00 2001 From: Yakir Gagnon <12.yakir@gmail.com> Date: Tue, 24 Dec 2024 12:37:21 +0100 Subject: [PATCH 1/6] add tests for chessboard corner detection --- test/Project.toml | 2 + test/runtests.jl | 3 ++ test/test_corner_detection.jl | 69 +++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 test/test_corner_detection.jl diff --git a/test/Project.toml b/test/Project.toml index 47b270c..027bfc2 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -3,5 +3,7 @@ Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" LazyArtifacts = "4af54fe1-eca0-43a8-85a7-787d91b784e3" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OpenCV = "f878e3a2-a245-4720-8660-60795d644f2a" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +XML = "72c71f33-b9b6-44de-8c94-c961784809e2" diff --git a/test/runtests.jl b/test/runtests.jl index 08c1515..6160c43 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,6 +3,8 @@ using LazyArtifacts using OpenCV using FileIO using Test +using XML +using LinearAlgebra if "OPENCV_TEST_DATA_PATH" in keys(ENV) test_dir = joinpath(ENV["OPENCV_TEST_DATA_PATH"], "cv") @@ -18,4 +20,5 @@ end include("test_objdetect.jl") include("test_dnn.jl") include("test_fileio.jl") + include("test_corner_detection.jl") end diff --git a/test/test_corner_detection.jl b/test/test_corner_detection.jl new file mode 100644 index 0000000..23cf8c1 --- /dev/null +++ b/test/test_corner_detection.jl @@ -0,0 +1,69 @@ +function _detect_corners(file, n_corners) + img = load(file) + gry = img[1:1, :, :] + cv_n_corners = OpenCV.Size{Int32}(n_corners...) + _cv_corners = OpenCV.Mat(Array{Float32}(undef, 2, 1, prod(n_corners))) + ret, cv_corners = OpenCV.findChessboardCorners(gry, cv_n_corners, _cv_corners, 0) + @assert ret "Failed to detect any corners!" + corners = reshape(vec.(eachslice(cv_corners, dims = 3)), n_corners) + return corners +end + +function parse_corners_file(file) + open(file, "r") do o + readuntil(o, "rows:") + rows = parse(Int, readuntil(o, "\n")) + readuntil(o, "cols:") + cols = parse(Int, readuntil(o, "\n")) + readuntil(o, "[") + corners = [Float32[] for i in 1:cols, j in 1:rows] + for i in 1:cols*rows, j in 1:2 + if i == cols*rows && j == 2 + break + end + push!(corners[i], parse(Float32, readuntil(o, ","))) + end + push!(corners[cols*rows], parse(Float32, readuntil(o, "]"))) + + return reverse(permutedims(corners, (2, 1)); dims = 1), (rows, cols) + end +end + +function get_list(file) + doc = read(file, LazyNode) + str = filter(≠('\"'), simple_value(doc[end][end])) + list = Dict{String, String}() + for line in split(str, '\n') + img_file, data_file = split(line) + list[img_file] = data_file + end + return list +end + +function calc_error(ps1, ps2) + s = 0.0 + for (p1, p2) in zip(ps1, ps2) + s += LinearAlgebra.norm_sqr(p1 .- p2) + end + sqrt(s/length(ps1)) +end + +@testset "detecting corners" begin + + path = joinpath(test_dir, "cameracalibration") + list = get_list(joinpath(path, "chessboard_list.dat")) + + @testset "in $k" for (k, v) in list + + img_file = joinpath(path, k) + data_file = joinpath(path, v) + + corners, n_corners = parse_corners_file(data_file) + detected_corners = _detect_corners(img_file, n_corners) + + ϵ = calc_error(corners, detected_corners) + + @test ϵ < 1 + + end +end From c82909c22903d9858de95ace4e768023d0e17383 Mon Sep 17 00:00:00 2001 From: Yakir Gagnon <12.yakir@gmail.com> Date: Tue, 24 Dec 2024 12:55:39 +0100 Subject: [PATCH 2/6] trying to pass CI with a silly repetition of the corner detection --- test/test_corner_detection.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_corner_detection.jl b/test/test_corner_detection.jl index 23cf8c1..18ddd6f 100644 --- a/test/test_corner_detection.jl +++ b/test/test_corner_detection.jl @@ -60,6 +60,7 @@ end corners, n_corners = parse_corners_file(data_file) detected_corners = _detect_corners(img_file, n_corners) + detected_corners = _detect_corners(img_file, n_corners) ϵ = calc_error(corners, detected_corners) From 38ab7e342fa2e92a9aa139a447f77fa00daff891 Mon Sep 17 00:00:00 2001 From: Yakir Gagnon <12.yakir@gmail.com> Date: Tue, 24 Dec 2024 13:09:22 +0100 Subject: [PATCH 3/6] trying to pass CI by adding an initial corner detection --- test/test_corner_detection.jl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/test_corner_detection.jl b/test/test_corner_detection.jl index 18ddd6f..061866a 100644 --- a/test/test_corner_detection.jl +++ b/test/test_corner_detection.jl @@ -48,23 +48,26 @@ function calc_error(ps1, ps2) sqrt(s/length(ps1)) end +function test_one(img_file, data_file) + corners, n_corners = parse_corners_file(data_file) + detected_corners = _detect_corners(img_file, n_corners) + calc_error(corners, detected_corners) +end + @testset "detecting corners" begin path = joinpath(test_dir, "cameracalibration") list = get_list(joinpath(path, "chessboard_list.dat")) + k, v = first(list) + test_one(joinpath(path, k), joinpath(path, v)) # why do we need this? + @testset "in $k" for (k, v) in list img_file = joinpath(path, k) data_file = joinpath(path, v) - corners, n_corners = parse_corners_file(data_file) - detected_corners = _detect_corners(img_file, n_corners) - detected_corners = _detect_corners(img_file, n_corners) - - ϵ = calc_error(corners, detected_corners) - - @test ϵ < 1 + @test test_one(img_file, data_file) < 1 end end From 6f782a21ceb561809e150becd4b4d1f6d4941313 Mon Sep 17 00:00:00 2001 From: Yakir Luc Gagnon <12.yakir@gmail.com> Date: Sun, 29 Dec 2024 14:30:07 +0100 Subject: [PATCH 4/6] Update test/test_corner_detection.jl Co-authored-by: Tim Holy --- test/test_corner_detection.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_corner_detection.jl b/test/test_corner_detection.jl index 061866a..f5437de 100644 --- a/test/test_corner_detection.jl +++ b/test/test_corner_detection.jl @@ -31,7 +31,7 @@ end function get_list(file) doc = read(file, LazyNode) - str = filter(≠('\"'), simple_value(doc[end][end])) + str = filter(≠('"'), simple_value(doc[end][end])) list = Dict{String, String}() for line in split(str, '\n') img_file, data_file = split(line) From 8c4babba0833b1e3173631f44f3b0e0679dec190 Mon Sep 17 00:00:00 2001 From: Yakir Gagnon <12.yakir@gmail.com> Date: Sun, 29 Dec 2024 15:16:23 +0100 Subject: [PATCH 5/6] address tim's points --- test/test_corner_detection.jl | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/test/test_corner_detection.jl b/test/test_corner_detection.jl index f5437de..afcc1ce 100644 --- a/test/test_corner_detection.jl +++ b/test/test_corner_detection.jl @@ -1,11 +1,13 @@ -function _detect_corners(file, n_corners) +const Point = Tuple{Float32, Float32} # just for conviniencve + +function detect_corners(file, n_corners) img = load(file) gry = img[1:1, :, :] cv_n_corners = OpenCV.Size{Int32}(n_corners...) _cv_corners = OpenCV.Mat(Array{Float32}(undef, 2, 1, prod(n_corners))) ret, cv_corners = OpenCV.findChessboardCorners(gry, cv_n_corners, _cv_corners, 0) @assert ret "Failed to detect any corners!" - corners = reshape(vec.(eachslice(cv_corners, dims = 3)), n_corners) + corners = reshape(Point.(eachslice(cv_corners, dims = 3)), n_corners) return corners end @@ -16,16 +18,10 @@ function parse_corners_file(file) readuntil(o, "cols:") cols = parse(Int, readuntil(o, "\n")) readuntil(o, "[") - corners = [Float32[] for i in 1:cols, j in 1:rows] - for i in 1:cols*rows, j in 1:2 - if i == cols*rows && j == 2 - break - end - push!(corners[i], parse(Float32, readuntil(o, ","))) - end - push!(corners[cols*rows], parse(Float32, readuntil(o, "]"))) - - return reverse(permutedims(corners, (2, 1)); dims = 1), (rows, cols) + txt = readuntil(o, "]") + num = parse.(Float32, split(txt, ',')) + corners = reverse(permutedims(Point.(eachslice(reshape(num, 2, cols, rows), dims=(2,3)))); dims = 1) + return corners, (rows, cols) end end @@ -48,9 +44,9 @@ function calc_error(ps1, ps2) sqrt(s/length(ps1)) end -function test_one(img_file, data_file) +function calc_error(img_file::AbstractString, data_file::AbstractString) corners, n_corners = parse_corners_file(data_file) - detected_corners = _detect_corners(img_file, n_corners) + detected_corners = detect_corners(img_file, n_corners) calc_error(corners, detected_corners) end @@ -60,14 +56,14 @@ end list = get_list(joinpath(path, "chessboard_list.dat")) k, v = first(list) - test_one(joinpath(path, k), joinpath(path, v)) # why do we need this? + calc_error(joinpath(path, k), joinpath(path, v)) # why do we need this? @testset "in $k" for (k, v) in list img_file = joinpath(path, k) data_file = joinpath(path, v) - @test test_one(img_file, data_file) < 1 + @test calc_error(img_file, data_file) < 1 end end From 08cf7cc347b02384df1eb2eeac2c604ecf777149 Mon Sep 17 00:00:00 2001 From: Yakir Gagnon <12.yakir@gmail.com> Date: Sun, 5 Jan 2025 18:00:04 +0100 Subject: [PATCH 6/6] use simple findChessboardCorners instead --- test/test_corner_detection.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/test_corner_detection.jl b/test/test_corner_detection.jl index afcc1ce..ba71c93 100644 --- a/test/test_corner_detection.jl +++ b/test/test_corner_detection.jl @@ -3,10 +3,7 @@ const Point = Tuple{Float32, Float32} # just for conviniencve function detect_corners(file, n_corners) img = load(file) gry = img[1:1, :, :] - cv_n_corners = OpenCV.Size{Int32}(n_corners...) - _cv_corners = OpenCV.Mat(Array{Float32}(undef, 2, 1, prod(n_corners))) - ret, cv_corners = OpenCV.findChessboardCorners(gry, cv_n_corners, _cv_corners, 0) - @assert ret "Failed to detect any corners!" + ret, cv_corners = OpenCV.findChessboardCorners(gry, OpenCV.Size{Int32}(n_corners...)) corners = reshape(Point.(eachslice(cv_corners, dims = 3)), n_corners) return corners end @@ -63,7 +60,7 @@ end img_file = joinpath(path, k) data_file = joinpath(path, v) - @test calc_error(img_file, data_file) < 1 + @test calc_error(img_file, data_file) < 2 end end