Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

incorrect closed behavior #65

Open
johnnychen94 opened this issue Jun 2, 2021 · 9 comments
Open

incorrect closed behavior #65

johnnychen94 opened this issue Jun 2, 2021 · 9 comments
Labels

Comments

@johnnychen94
Copy link
Member

johnnychen94 commented Jun 2, 2021

I'm not sure if this is an expected behavior or not:

img = zeros(RGB{Float64}, 10, 10)

verts = [CartesianIndex(2, 2), CartesianIndex(2, 6), CartesianIndex(6, 2), CartesianIndex(2,2)]
alg = BoundaryFill(4, 4; fill_value = RGB(1), boundary_value = RGB(1))

mosaic(
    draw(img, verts, alg; closed=true),
    draw(img, verts, alg; closed=false);
    npad=2, fillvalue=0.5
)

closed=false is an all-white image:

image

cc: @ashwani-rathee

@johnnychen94
Copy link
Member Author

BTW, I noticed that usage like zeros(RGB, 10, 10) appears in the docstring. It is not a performant usage because it's not a concrete type:

julia> img = zeros(RGB, 10, 10)

julia> isconcretetype(eltype(img))
false

As an alternative, one should use fill(zero(RGB), 10, 10)

@ashwani-rathee
Copy link
Member

Isn't that the intended behavior? Since what boundary fill does is to avoid a particular color and fill everything else, and when there are no boundaries it fills everything.

Do we want it to not work at all if closed = false? Even if we do that if fill_value=boundary_value it will fill everything with fill_value.

@johnnychen94
Copy link
Member Author

Okay... So my next question is: is there a way to generate a non-constant image using BoundaryFill with closed=false?

@johnnychen94
Copy link
Member Author

Similarily, if first(verts) != last(verts), BoundaryFill becomes meaningless in all cases, e.g.,:

img = zeros(RGB{Float64}, 10, 10)

verts = [CartesianIndex(2, 2), CartesianIndex(2, 6), CartesianIndex(6, 2)]
alg = BoundaryFill(3, 3; fill_value = RGB{Float64}(1), boundary_value = RGB{Float64}(1))
draw(img, verts, alg; closed=true)

@ashwani-rathee
Copy link
Member

This is the only case I think when it will stop before filling everything

1,2,3,4 are our verts and closed=false.... and luckily there is a boundary other than the verts boundary whose boundary_color == boundary_value

As for the verts, that choice of making first and last same has something to do the way closed polygon were made here:

draw!(img, LineSegment(vertices[i], vertices[i+1]), color)

It's not optimal, we can change that. Or we can document that first vert needs to equal to last vert.

@johnnychen94
Copy link
Member Author

I never liked the original ImageDraw design and implementations; the usage is too fragile... but always find more important/urgent things to do when I try to put my hands on this package.

This is the only case I think when it will stop before filling everything

If we change res[y, x] != f.boundary_value to mapreducec(abs, +, 0.0, res[y, x] - f.boundary_value) < ϵ, will we be more lucky here?

It's not optimal, we can change that. Or we can document that first vert needs to equal to last vert.

I see two options: 1) throw an error/warning 2) silently push the first index to the last. I prefer the first version, i.e., throw an error/warning. A warning is perhaps sufficient, I guess.

@juliohm
Copy link
Member

juliohm commented Jun 2, 2021

I never liked the original ImageDraw design and implementations

Me too. I never really needed ImageDraw myself but perhaps there is good motivation to handle these geometric drawings with an existing library for geometric processing and have a single helper function that rasterizes the drawing into images? We are building so much functionality in Meshes.jl for example that it would be straightfoward to take a geometry from there and rasterize with a single function. What do you think @johnnychen94 ?

Maybe I misunderstood the goal of ImageDraw, but if is just drawing geometries in an pixelated array, I would definitely consider adding Meshes.jl or Luxor.jl as a dependency, drawing with existing functions and then writing a single rasterize function here to convert axis coordinates to image coordinates, etc.

@johnnychen94
Copy link
Member Author

What do you think @johnnychen94 ?

I'm not a graphics expert so I can't say for sure what the best targeting form of ImageDraw.jl is. Right now, it's a convenient and lightweight tool for image visualization purposes to me.

The key difference between ImageDraw.jl and other packages is that the input/output of draw/draw! are arrays so it's very easy to manipulate it.

If we plan to redesign the codes, https://github.com/GiovineItalia/Compose.jl is a pretty good interface I have in mind.

@juliohm
Copy link
Member

juliohm commented Jun 2, 2021

The key difference between ImageDraw.jl and other packages is that the input/output of draw/draw! are arrays so it's very easy to manipulate it.

Maybe a simple conversion function would do the job. One for rasterizing the vector geometries and another for vectorizing the raster images. I would definitely consider adding Compose.jl or similar library as dependency to avoid reinventing the wheel and then would concentrate the efforts on these two conversion functions. That way users could draw more advanced geometries and text on images without effort.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants