【问题标题】:How to draw a circular sector in the Julia language?如何在 Julia 语言中绘制圆形扇区?
【发布时间】:2022-01-09 18:15:10
【问题描述】:

我是 Julia 语言的新手,需要在图像上绘制一个圆形扇区(灰色版本的二维 UInt8 数组或 RGB 版本的 3 维 UInt8 数组)。之后此图像将用作掩码以选择其他数组中的数据,因此我需要结果,而不是图像对象,而是布尔值或整数数组。

有办法通过ImageDraw包画圆:

draw!(img, Ellipse(CirclePointRadius(350,200,100), fill = tue))

但找不到提供开始和结束角度的方法。

【问题讨论】:

    标签: julia draw


    【解决方案1】:

    你可以使用Luxor.jl's pie or sector function:

    
    julia> begin 
           img = readpng("/path/Images/deepam.png")
           Drawing(img.width, img.height, "sector-on-img.png")
           placeimage(img)
           origin()
    
           sethue("orange")
           pie(0, 0, 100, π/2, π, :fill)
    
           sethue("olive")
           sector(25, 125, 3π/2, 0, 15, :fill)
    
           finish()
           end
    true
    

    结果

    (原始 png 图像按比例缩小,用于比较: )

    【讨论】:

    • 非常感谢@Sundar,这个解决方案很有效,但我需要一个更具体的解决方案。我需要将生成的图像作为一个数组,以便用作其他数组的掩码,并且这个库似乎创建了一个对象。我在 Luxor 中看到了 image_as_matrix() 函数来转换为矩阵,但它返回一个 ARGB32 数组,之后应该将其转换为二维 UInt8 数组。我认为这一切都是不必要的开销。
    【解决方案2】:

    我认为 Julia 是一门很棒的语言,因为(除其他外)所有库都以相同的语言实现,并且您可以轻松访问它们的源代码。

    并且通过这种方式,我已经能够修改 ImageDraw 库的 ellipse2d.jl 脚本了。

    修改包括添加另一个平局定义!椭圆对象的函数(Julia 的多次调度也很棒),它接受开始和结束角度。

    我认为最好的方法是定义新对象 ellipse_sector 和 circle_sector,它们与 ellipse 和 circle 对象相同,但多了两个成员:start_angle 和 end_angle。然后应该实现相应的绘图功能。我想写信给 ImageDraw 包开发者,以便提出这个建议,甚至让我做出这些改变,但我不知道 github 的管理。

    相反,我的解决方案不修改任何现有对象,只是在绘图中添加一个方法!接受另外两个参数的函数:startAngle 和 endAngle。

    这里是代码,要复制到 ellipse2d.jl 脚本的末尾:

    function draw!(img::AbstractArray{T, 2}, ellipse::Ellipse, startAng::Real, endAng::Real, color::T) where T<:Colorant
        # Solution to find out if an angle lies between two given ones, borrowed from:
        # https://stackoverflow.com/questions/11406189/determine-if-angle-lies-between-2-other-angles/11412077#11412077
    
        # Make all angles to lie in [0, 2π)
        # rem2pi(ϕ, RoundNearest) returns the remainder of the division by 2π in the range [−π,π]
        # mod2pi returns the remainder of the division by 2π in the range [0,2π)
        Angle1 = mod2pi(startAng)
        Angle2 = mod2pi(endAng)
    
        # make the angle from angle1 to angle2 to be <= 180 degrees
        rAngle = mod2pi( mod2pi(Angle2 - Angle1) + 2π)
        if rAngle >= π
            Angle1, Angle2 = Angle2, Angle1 # Swaps the values
        end # if
    
        ys = Int[]
        xs = Int[]
        break_point = 0
        if ellipse.fill == false
            break_point = ((ellipse.ρy - ellipse.thickness) / ellipse.ρy) ^ 2 + ((ellipse.ρx - ellipse.thickness) / ellipse.ρx) ^ 2 
        end
        for i in ellipse.center.y - ellipse.ρy : ellipse.center.y + ellipse.ρy
            for j in ellipse.center.x - ellipse.ρx: ellipse.center.x + ellipse.ρx
                y = i - ellipse.center.y
                x = j - ellipse.center.x
                val = (x / ellipse.ρy) ^ 2 + (y / ellipse.ρx) ^ 2
                # atan(y, x) returns the angle in the correct quadrant [−π,π], not like atan(y/x)
                # But make it to be in the range [0, 2π)by means of mod2pi()
                ang = mod2pi( atan(y, x) )
    
                # Test if the angle lies betwen the startAngle and the endAngle
                if (Angle1 <= Angle2)
                    AngleIsBetween = ang >= Angle1 && ang <= Angle2
                else
                    AngleIsBetween = ang >= Angle1 || ang <= Angle2
                end # if
                if val < 1 && val >= break_point && AngleIsBetween
                    push!(ys, i)
                    push!(xs, j)
                end
            end
        end
        for (yi, xi) in zip(ys, xs)
            drawifinbounds!(img, yi, xi, color)
        end
        img
    end
    

    【讨论】:

    • 我已经编辑了代码,因为旧代码没有考虑 pi 断点每一侧的开始和结束角度。
    猜你喜欢
    • 2014-02-07
    • 2011-10-08
    • 2011-09-07
    • 2016-08-03
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多