【问题标题】:Creating a filled rectangle within an array in Julia在 Julia 的数组中创建一个填充的矩形
【发布时间】:2020-09-24 21:39:33
【问题描述】:

我是 Julia 的新手,我正在尝试了解基本的数据可视化。我正在创建一个 2D 噪声数组:

xRange, yRange = 1:1:300, 1:1:300
maxVal = 0.3
noiseArr = rand(length(xRange),length(yRange))*maxVal

生成的数组如下所示(左)。我想识别特定的像素——由具有长度、宽度和旋转的矩形定义——并将这些值设置为已知数字。最终,我想要如下图所示的东西(右)。

我没有包偏好,但我一直在研究图像、OpenCV 等。我希望有一种直接的方法来做到这一点。

【问题讨论】:

  • 你可以自己写一个line-drawing algorithm(不难)并填写内部。
  • 也许对你有帮助youtube.com/watch?v=jj8Iy7FFMeM
  • @phipsgabler,谢谢你的建议!我在最初的搜索中简要考虑了这一点,然后认为 Julia 肯定有一个更快、开箱即用的功能,可以让人们轻松地制作线条。你知道可以在上面的噪声数组中画一条线的包吗?

标签: arrays julia overlap rectangles


【解决方案1】:

我想识别特定像素 -- 由具有长度、宽度和旋转的矩形定义

知道长度、宽度和旋转不足以在平面上唯一定位矩形。你还需要翻译。

这是一个简单的代码,它为您提供了一个示例(它不是超级高效,但对于演示目的来说足够快):

function rectangle!(x1, x2, x3, noiseArr, val)
    A = [x2-x1 x3-x1]
    b = x1
    iA = inv(A)

    for i in axes(noiseArr, 1), j in axes(noiseArr, 2)
        it, jt = iA * ([i, j]-b)
        0 <= it <= 1 && 0 <= jt <= 1 && (noiseArr[i, j] = val)
    end
end

x1 = [40, 140]
x2 = [230, 100]
x3 = [50, 170]
rectangle!(x1, x2, x3, noiseArr, 0.0)

在其中 - 而不是传递旋转、缩放和平移,我认为更容易假设您传递矩形的三个顶点 x1x2x3(假设它的边由 @ 987654325@ 和 x1-x3 对),它会计算您需要的仿射变换。 val 是矩形内的像素应该得到的值。

请注意,我们所做的基本上是计算矩形到单位正方形的反向仿射变换,并检查哪些点位于单位正方形内(这很容易)。

(正如上面提到的评论者 - 这不是一种最佳方式,因为你做了很多不需要的计算,但我希望它的好处是更容易理解;还有 Julia 的好处是编写这样一个循环不是问题,它仍然运行得足够快)

【讨论】:

  • 啊,新的 highlight.js 东西不支持 Julia。该代码被检测为 YAML!
  • 这正是我所寻找的,并且整合到足以在一个单一的、直接的函数中完成。谢谢!
  • 我很高兴能帮上忙。我希望背后的线性代数很清楚——我们使用Ax+b函数将点[0,0][1,0][0,1]转换为x1x2x3
【解决方案2】:

这是一个使用带有Luxor.jl的图元绘制它的快速示例

using Luxor

function b()
    Drawing(300, 300, "hello-world.png")
    background("black")
    sethue("white")
    #Luxor.scale(1,1)
    Luxor.translate(150, 30)
    Luxor.rotate(10 * pi / 180)
    w = 40
    h = 200
    rect(O, w, h, :fill)
    finish()
    preview()
end

现在,您可以提取转换矩阵并在其他地方使用,而不是直接使用 Luxor 绘制它。

using Plots
using GR
using LinearAlgebra

gr(size = (300, 300), legend = false)

function a(transform=Matrix{Int}(I, 3, 3))
    side = 300
    width = side
    height = side
    xs = [string("x", i) for i = 1:width]
    ys = [string("y", i) for i = 1:height]
    z = float((1:height) * reshape(1:width, 1, :))
    # Plots.heatmap(xs, ys, z, aspect_ratio = 1)

    white = maximum(z)

    # Draw a rectangle with a rotation matrix applied
    for x in 0:40
        for y in 0:200
            t = transform*[x;y;1]
            z[round(Int, t[2]), round(Int, t[1])] = white
        end
    end

    Plots.heatmap(xs, ys, z, aspect_ratio = 1)
end

using Luxor

function b()
    Drawing(300, 300, "hello-world.png")
    background("black")
    sethue("white")
    #Luxor.scale(1,1)
    Luxor.translate(100, 60)
    Luxor.rotate(-10 * pi / 180)
    w = 40
    h = 200
    rect(O, w, h, :fill)
    finish()
    preview()

    tranformation_matrix = Luxor.cairotojuliamatrix(Luxor.getmatrix())

    a(tranformation_matrix)
end

请注意,这会留下杂散像素,因为我的 for 循环在栅格化填充方面效率不高。从 Luxor 访问像素数据可能会更好,或者使用其他一些将仿射变换应用于矩阵的函数。

注意朱莉娅的情节:

第一次绘图的时间很慢。要对其进行任何真正的迭代,您应该利用Revise.jl 并将您的测试函数保存在一个文件中,并将其包含在includet("test.jl") 中。然后你的 julia 会话是持久的,你只需要等待你的 using 语句一次。

【讨论】:

    猜你喜欢
    • 2015-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多