Julia中轮廓之间的距离

3

你好,我正在使用Julia进行轮廓检测来检测轮廓。更新:我需要找到由折线构成的两个轮廓之间的最近距离。是否有一个函数可以找到最近的距离?我不确定连接这两个轮廓的最佳方式是什么。

我需要处理的情况是:

enter image description here

因此,我使用了链接示例链接(https://juliaimages.org/v0.21/democards/examples/contours/contour_detection/)中提供的代码。我用n元素Vector {CartesianIndex}数据类型得到了轮廓。如何连接这条线或两个轮廓?

更新:我已经尝试使用以下方法删除接近的轮廓点:

  sorted_contours = sort!(contours, by=x -> x[1])
    for i in eachindex(sorted_contours)
        if check_adjacent(sorted_contours[i], sorted_contours) >= 1
            sorted_contours[i] = CartesianIndex.(0, 0)
        end
    end
    deleteat!(sorted_contours,findall(sorted_contours.==CartesianIndex.(0, 0))) but from this [![enter image description here][3]][3] it improved to this only [![enter image description here][3]][3]

我想删除这些点,因为它们是错误的轮廓点。或者我该如何去掉引起这种情况的尖端?

5
你能否在关于你拥有什么和想要计算的结果的问题中,添加一些代码细节? - Dan Getz
3
请放置您已经尝试过的代码,这样我们就可以有效地帮助您。否则,在这里可能得不到答案。我建议您阅读以下内容:如何提出一个好问题。 - Shayan
在问题中提到:“看起来像矩形的两个轮廓(大致)”。看着图片,我觉得这个描述相当弱。这也是 https://dev59.com/-HsQtIcB2Jgan1znF8tK 的重复问题。最后,添加可运行的代码以获得最佳回答。 - Dan Getz
1
请看下面的代码 distances = [(euclidean(p1, p2), p1, p2) for p1 in points5, p2 in points10]; 其中points5和points10是您的轮廓数组(您可能需要调整类型以使euclidean()函数正常工作)。其中,d,idx = findmin(t -> t [1],distances)。 - Bill
2个回答

2

你在提问时(截至11月27日)对你使用的软件包提出的问题比较含糊。如果你正在使用Contour,以下是一种非优化的方法来查找两个轮廓之间的最小距离。你需要使用contour()函数选择两个轮廓,分别对应不同的x、y、z值集合。

using Contour
using Distances


const x = -3:0.01:3
const y = -4:0.02:5
const z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]

x5, y5 = contour(x, y, z, 5) |> lines |> first |> coordinates
points5 = [[x5[i], y5[i]] for i in eachindex(x5)]
x10, y10 = contour(x, y, z, 10) |> lines |> first |> coordinates
points10 = [[x10[i], y10[i]] for i in eachindex(x10)]

distances = [(euclidean(p1, p2), p1, p2) for p1 in points5, p2 in points10]
d, idx = findmin(t -> t[1], distances)

@show d, idx   #(d, idx) = (0.9261944913478685, CartesianIndex(918, 126))
@show distances[idx] # distances[idx] = (0.9261944913478685, [1.64, 1.52], [2.32, 2.1488372093023256])
@show points5[idx[1]] points10[idx[2]]

# points5[idx[1]] = [1.64, 1.52]
# points10[idx[2]] = [2.32, 2.1488372093023256]

1
这是展示你的努力并解释你遇到了哪些问题的最佳方法,你将得到最好的答案来解决它。虽然你的问题不符合一个好问题的要求,但由于这个话题引起了我的兴趣和好奇心,我认为它是值得的。
为了更好地检测轮廓,首先我对图像进行细化以便更容易定位轮廓。我使用以下图像作为输入,以查看更大尺寸的结果:enter image description here
using Images, FileIO, ImageBinarization

img = load("img.png")
gimg = Gray.(img)
bin = binarize(gimg, UnimodalRosin()) .> 0.5
thinned = thinning(bin, algo=GuoAlgo())

thinned 变量代表以下图片:

julia> Gray.(thinned)

在这里输入图片描述

现在,我定义了用于查找轮廓的函数:

"""
    check_adjacent(loc::CartesianIndex{2}, all_locs::Vector{CartesianIndex{2}})

Return the number of adjacent locations that are in `all_locs` to `loc`.
This function is used to determine whether a location is a corner (contour) or not.

# Arguments
- `loc::CartesianIndex{2}`: the location to check.
- `all_locs::Vector{CartesianIndex{2}}`: all the locations that aren't black.

# Returns
- `Int`: the number of adjacent locations that are in `all_locs` to `loc`.
"""
function check_adjacent(loc::CartesianIndex{2}, all_locs::Vector{CartesianIndex{2}})
    conditions = [
        loc - CartesianIndex(0,1) ∈ all_locs,
        loc + CartesianIndex(0,1) ∈ all_locs,
        loc - CartesianIndex(1,0) ∈ all_locs,
        loc + CartesianIndex(1,0) ∈ all_locs,
        loc - CartesianIndex(1,1) ∈ all_locs,
        loc + CartesianIndex(1,1) ∈ all_locs,
        loc - CartesianIndex(1,-1) ∈ all_locs,
        loc + CartesianIndex(1,-1) ∈ all_locs
    ]

    return sum(conditions)
end

"""
    find_the_contour(img::BitMatrix)

Return the contours of the image `img`.

# Arguments
- `img::BitMatrix`: the image to get the contours of.

# Returns
- `Vector{CartesianIndex{2}}`: the contours of the image `img`.

"""
function find_the_contour(img::BitMatrix)
    img_matrix = convert(Array{Float64}, img)
    not_black = findall(!=(0.0), img_matrix)
    contours = Vector{CartesianIndex{2}}()
    for nb∈not_black
        t = check_adjacent(nb, not_black)
        t==1 && push!(contours, nb)
    end
    return contours
end

现在我使用find_the_contour函数:
julia> contours = find_the_contour(thinned)
4-element Vector{CartesianIndex{2}}:
 CartesianIndex(161, 334)
 CartesianIndex(256, 452)
 CartesianIndex(69, 1213)
 CartesianIndex(210, 1243)

我应该如何知道这个函数能正确定位轮廓?我定义了另一个函数来突出显示轮廓:

"""
    highlight_contours(img, contours)

Return the image `img` with the contours `contours` highlighted with red color.

# Arguments
- `img::BitMatrix`: the image to highlight the contours on.
- `contours::Vector{CartesianIndex{2}}`: the contours to highlight.
- `resize`::Bool=false: whether to resize the image to 512x512 or not.
- `scale`::Union{Int64, Float64}=1: the scale to resize the image to.

# Returns
- `img_matrix`: the image `img` with the contours `contours` highlighted with red color.
"""
function highlight_contours(img, contours; resize::Bool=false, scale::Union{Int64, Float64}=1)
    img_matrix = convert(Array{RGB, 2}, img)
    for c∈contours
        img_matrix[c] = RGB(1,0,0)
    end

    if resize
        img_matrix = typeof(scale)==Int64 ? imresize(img_matrix, size(img).*scale) : imresize(img_matrix, ratio=scale)
    end
    return img_matrix
end

然后我将thinned矩阵和contours传递给它:

julia> highlited = highlight_contours(thinned, contours)

如果你稍微放大一点,你会发现红色轮廓:enter image description here 现在我确认了轮廓的位置成功后,就开始计算轮廓之间的距离。我使用了每个轮廓的CartesianIndex之间的欧几里得距离!你可以根据自己的喜好进行调整:
"""
    distance_between_contours(V::Vector{T}, v::T) where T<:Tuple{Int64, Int64}

Return the euclidean distance between the contour `v` and the contours in `V`.

# Arguments
- `V::Vector{T}`: the contours to check the distance to.
- `v::T`: the contour to check the distance from.

# Returns
- `Float64`: the euclidean distance between the contour `v` and the contours in `V`.

"""
function distance_between_contours(V::Vector{T}, v::T) where T<:Tuple{Int64, Int64}
    return broadcast((x, y)->sqrt(sum((x.-y).^2)), V, Ref(v))
end

"""
    distance_between_contours(all_contours::Vector{CartesianIndex{2}})

Return the euclidean distance between each pair of contours in `all_contours`.

# Arguments
- `all_contours::Vector{CartesianIndex{2}}`: the contours to calculate the distance between.

# Returns
- `Matrix{Float64}`: the euclidean distance between each pair of contours in `all_contours`.
"""
function distance_between_contours(all_contours::Vector{CartesianIndex{2}})
    n = length(all_contours)
    distances = Matrix{Float64}(undef, n, n)

    for j in eachindex(all_contours)
        distances[:, j] .= distance_between_contours(
            Tuple.(all_contours),
            Tuple(all_contours[j])
        )
    end

    return distances
end

现在我将传递给它contours并计算每个之间的配对欧几里得距离:
julia> distance_between_contours(contours)
4×4 Matrix{Float64}:
   0.0    151.489  883.801  910.32
 151.489    0.0    783.639  792.336
 883.801  783.639    0.0    144.156
 910.32   792.336  144.156    0.0

在这个矩阵中,例如,151.489 的值显示了第一个轮廓和第二个轮廓之间的距离。请记住,第一个和第二个轮廓分别是以下内容:
 CartesianIndex(161, 334)
 CartesianIndex(256, 452)

我按照同样的步骤处理了您的图像,以下是距离和轮廓:

julia> distance_between_contours(contours)
6×6 Matrix{Float64}:
   0.0      27.7308  88.6397  168.6     166.676    170.188
  27.7308    0.0     60.9262  140.872   139.284    142.622
  88.6397   60.9262   0.0      80.1311   79.2465    82.0061
 168.6     140.872   80.1311    0.0      26.2488    19.2354
 166.676   139.284   79.2465   26.2488    0.0        8.06226
 170.188   142.622   82.0061   19.2354    8.06226    0.0

highlited = highlight_contours(thinned, contours, resize=true, scale=2)

这里输入图片描述 这里输入图片描述

简述

代码:

using Images, FileIO, ImageBinarization

function check_adjacent(loc::CartesianIndex{2}, all_locs::Vector{CartesianIndex{2}})
    conditions = [
        loc - CartesianIndex(0,1) ∈ all_locs,
        loc + CartesianIndex(0,1) ∈ all_locs,
        loc - CartesianIndex(1,0) ∈ all_locs,
        loc + CartesianIndex(1,0) ∈ all_locs,
        loc - CartesianIndex(1,1) ∈ all_locs,
        loc + CartesianIndex(1,1) ∈ all_locs,
        loc - CartesianIndex(1,-1) ∈ all_locs,
        loc + CartesianIndex(1,-1) ∈ all_locs
    ]

    return sum(conditions)
end

function find_the_contour(img::BitMatrix)
    img_matrix = convert(Array{Float64}, img)
    not_black = findall(!=(0.0), img_matrix)
    contours = Vector{CartesianIndex{2}}()
    for nb∈not_black
        t = check_adjacent(nb, not_black)

        t==1 && push!(contours, nb)
    end
    return contours
end

function distance_between_contours(V::Vector{T}, v::T) where T<:Tuple{Int64, Int64}
    return broadcast((x, y)->sqrt(sum((x.-y).^2)), V, Ref(v))
end

function distance_between_contours(all_contours::Vector{CartesianIndex{2}})
    n = length(all_contours)
    distances = Matrix{Float64}(undef, n, n)

    for j in eachindex(all_contours)
        distances[:, j] .= distance_between_contours(
            Tuple.(all_contours),
            Tuple(all_contours[j])
        )
    end

    return distances
end

img = load("img.png")
gimg = Gray.(img)
bin = binarize(gimg, UnimodalRosin()) .> 0.5
thinned = thinning(bin, algo=GuoAlgo())
contours = find_the_contour(thinned)
distance_between_contours(contours)

谢谢Shayan。我正在研究它。我不能在highlighted上使用imshow()吗? - h612
@h612,一种解决方法可以使用VSCode。使用VSCode中已激活的绘图窗格运行代码。然后,您可以将结果显示为图像甚至保存它。 - Shayan
我没有那个选项。我已经检查了显示图形设置,它已经开启了。 - h612
@h612,激活时,请使用“Ctrl + Shift + p”并搜索“启用绘图窗格”,然后选择它。然后重新运行代码。 - Shayan
我遇到了一个问题,所以我更新了问题并尝试修复它。 - h612

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接