Tw1ddle / geometrize-haxe

:triangular_ruler: Geometrize is a Haxe port of primitive that geometrizes images into geometric primitives
https://www.geometrize.co.uk/
Other
347 stars 31 forks source link

new type : Polylines #6

Closed mastef closed 5 years ago

mastef commented 5 years ago

Would be nice to have bend lines possible. To have them seem more natural they could also have a beginning and ending gradient into transparency

mastef commented 5 years ago
cancerberoSgx commented 5 years ago

I saw some effects in primitive twitter that seems to be made with QuadraticBezier , and when opened simulate a pencil I think are awesome.

I though that implementing that is very complex but researching in the C++ project doesn't seems so( problsably missing something), @Tw1ddle , could you briefly comment if it's viable to attempt to give it a shot ?

rasterize: https://github.com/Tw1ddle/geometrize-lib/blob/be14f7bf0d183faa03127c6500c6194877b3ee3d/geometrize/geometrize/rasterizer/rasterizer.cpp#L308

mutate: https://github.com/Tw1ddle/geometrize-lib/blob/be14f7bf0d183faa03127c6500c6194877b3ee3d/geometrize/geometrize/shape/shapemutator.cpp#L262

Tw1ddle commented 5 years ago

It shouldn't be hard. The ones in primitive look better than the ones I use in the C++ Geometrize app because they have a configurable thickness. There's also a Polyline type in there that is just multiple line segments.

cancerberoSgx commented 5 years ago

@Tw1ddle I was working on geometrizejs-cli and it looks good now. I added a couple of extra features though:

With the two later options, users can define animation templates so they only need to pass the input file and output - the rest is defined in the json. These are a couple of animations I just generated. I'm not a visual person, and I hope other users will build better ones. My objective now is to build series that clearly show the impact of each option (iterations, candidateShapesPerStep, etc) so users (and I) can better understand their meaning. I have just a couple now: https://cancerberosgx.github.io/demos/geometrizejs-cli/index.html

I'm noticing the tools is somewhat slow when working with large images and more than 1000 iterations compared with the C++. However I still think it can be improved with an option that prevent copying the buffers as they are now. Also maybe, using macros, js performance could be improved using other datatypes. However I will work on that when I feel is a real blocker - now it's not IMO.

It's OK if I add a small note in this project's readme (since it doesn't have a CLI I think it will help)

thanks

Tw1ddle commented 5 years ago

Thanks, that's looking great. The SVG optimization and having base configuration options are nice additions. Feel free to edit the readme to mention the CLI.

I implemented the basic quadratic bezier code: https://github.com/Tw1ddle/geometrize-haxe/commit/e6ed1ab8c3867ac0da5bfea25ee4e7204ad286be

geometrized_image (3)

Note there's a bug where it stops working sometimes, perhaps when it draws an empty curve, or one that overlaps itself. I'll take a look another time to see if I can fix that.

By the way, the primitive repo has an explanation for how the algorithm works, if that helps you understand what the options do: https://github.com/fogleman/primitive#how-it-works-part-ii

mastef commented 5 years ago

This is cool! If you could make a simple example how to use it in C++ ( #5 ) I would be very grateful! So far I've only been playing with this lib in the web demo

cancerberoSgx commented 5 years ago

Wow, that's awesome - was that using only curves? They look like much better that the current straight lines. thanks! I will try it tomorrow in node trying to reproduce the bug , BTW, on which target did it stop working ? if neko may be related to the issue already mentioned and if so I would not worry so much about it. Thanks again!

cancerberoSgx commented 5 years ago

@mastef Checkout https://github.com/Tw1ddle/geometrize-haxe-unit-tests/tree/performance-lime/tests-performance . That's my attempt for a lime base project that works fine in C++ . I will try to integrate with these changes. (did based on lime since I didn't figure out how to make work any format library). But currenlty the app doesn't show any window so it's kind of command line.

Tw1ddle commented 5 years ago

@cancerberoSgx Yes that's quadratic beziers only, and it stopped running for me in the web demo (js using a webworker) after adding several hundred shapes. It was late so I didn't look into it yet :smile:

cancerberoSgx commented 5 years ago

np, I already add the type in js project in node.js I'm not experimenting any performance difference and seems to be working with 1000 iterations (that's what you call shapes?) and didn't hang, but I didn't in the browser and extensively.

I observe that lines and quadcurves when in combination with other shapes are rendered in a very small small ratio or not at all. I I guess is because lack area the algorithm matches the other in most of the steps right ? I think this is an issue :( since lines are beatiful when in companion with the other shapes - alone the output is too sharp and never seems to "converge".

As user, I'm able to draw with lines and area-shapes in your web-demo by manually controlling the steps, so I draw 50 ellipses very transparent and after that 2000 lines more opaque:

geometrized_image (1)

geometrized_image (2)

I think there should be an API that let me do the same programatically.

I already mention my idea of implementing the step loop and APIs for controlling it in a separate project and I think that is the missing part. I did it in the jscli with the concept of series and I will move that to an API-only project for node and browser.

I think this could be a nice companion library here - just implement a basic step loop and types so user can declare these "series" and perhaps register event listeners for interesting moments. In jscli I generalized and users can change any option, even increase iterations or change the image itself. I think for start, just being able to declare step count, shape types and alpha would be great.somethign like 👍

run({
  ...currentOptions,
  series:[ {types: triangle,rectangle, steps: 15%, alpha: veryTransparent}, {types: quad_curve,line, 
  steps:85%, alpha: very opaque}, ...],
  onStepFinish: event=>{},
  onSerieStart:...

Another alternative for the line problem could be supporting shape types weights, this is configurable match coeficients but I think that tackle another less important problem.

What do you think about introducing this as separate project.

And BTW about projects:

Well sorry for the long msg, (and I have more questions / ideas I left for later though)

Thanks

Tw1ddle commented 5 years ago

Thanks for checking this out!

Yes, as I always add 1 shape each time we "step/iterate", the number of iterations == final number of shapes in the image.

I agree that having a way to specify/describe sequences of operations (add 50 ellipses, then 1000 beziers, then change settings etc) would be nice. I agree the companion library you suggest would be suitable for a target like js.

As an aside, in my C++ app I started to make such functionality scriptable, so for example the Geometrizer Twitter bot runs scripts which are themselves built from this template script: https://github.com/Tw1ddle/geometrize-twitter-bot/blob/master/script/geometrize_shape_choice_template.chai (this way is general, but also a bit weird, and I think it wouldn't make sense for a js project).

I could create a setup that lets me trigger tasks in response to pushes across multiple repos using scripts like this: https://github.com/Tw1ddle/geometrize/blob/master/.travis.yml#L92 - that could be an alternative to using a monorepo. How does that sound?

I manually upload the geometrize haxelib, so it's not always up to date. When I find some time, I'll check the quadratic bezier code soon/see what's wrong in my demo, and maybe make another basic example for a Haxe C++ target project.

cancerberoSgx commented 5 years ago

Oh I see it's there https://lib.haxe.org/p/geometrize-haxe/ - thanks! - will use that for the getting started guide I'm writing.

Thanks! My opinion regarding the sequences API and this project API it self, is that it should target non-technical people since rarely technical people have visual artistic conditions or urgencies to express things visually as the rest of the world. That's Why I think if we could define it more declarative, like I did using well known defined JSON objects, it will better reusable, for example to build a UI. But at some time, it would be awesome to script it some how (to add it behavior) and in taht case a imperative language will need to be introduced.

Don't know if I already asked, and since I see you have experience with machine learning didn't you thought about mixing the two things, like trining a classificator or neural network to somehow define a aesthetically direction (I'm researching on that topic right now but just beginner, and curious) Thanks

Tw1ddle commented 5 years ago

Thanks, I agree that a "sequences" API is the way forward, where a sequence is a collection of "commands" that can be (de)serialized as JSON. If I added scripting in Haxe later then it would be hscript (https://github.com/HaxeFoundation/hscript), but I'd keep all that implementation separate also, possibly an optional extension.

I haven't done much to combine AI or neural networks with this. I tried using face recognition in the C++ version to define people's faces as "focus areas" (same as #3), but found just controlling that by hand gave nicer results so didn't pursue it.

cancerberoSgx commented 5 years ago

I haven't done much to combine AI or neural networks with this. I tried using face recognition in the C++ version to define people's faces as "focus areas" (same as #3), but found just controlling that by hand gave nicer results so didn't pursue it.

In your app it would be awesome to select a rectangle so only that is painted. And also invert the selection. I'm taking notes for my -extra project idea.And if it could be generalized to other shapes besides rect, perfect.

Regarding ML, I was thinking more those machines that are trained to recognize what's beautifulness. I've seen two kind: those that are trained to emulate a "style" (ex "monet", "rock and roll") so they tend to produce something close to that style. These are basically feed with that style sample. I think this might make some sense here although not sure how to build the training material.

Then Ive seen machines that learn them selves (how to play their own style of music or painting" but I really didn't understand those. Also I've seen in tensorflow others that learn while the song / painting is being performed with the help of the user but also didn't fully understand. in music user is guiding this thought the keyboard or chord modes dynamically but I don't understand how that can train it.

Also I arrived to this project with hopes of using it as another image tracing technique (bitmap->SVG) , on this regard which is engineer and not art, ML could be trained to generate shapes and mutations. It could optimize rendering of one image or with luck one kind of image (landscape, city, text, face), but don't think it will work for all kind of images. Although another machine can be trained to classify the input. As I said is a new topic for me and probably will be more productive just optimising performance :(

cancerberoSgx commented 5 years ago

I could create a setup that lets me trigger tasks in response to pushes across multiple repos using scripts like this: https://github.com/Tw1ddle/geometrize/blob/master/.travis.yml#L92 - that could be an alternative to using a monorepo. How does that sound?

Aja, Question, the idea is that each project has its dependencies defined as git submodules ? as you do in geometrize-haxe-test ? If so, imagine I'm working on a feature and doing TDD. This means I will need to work on repository geometrize-haxe-test and modify its sources and also its geometrize-haxe submodule sources. When I finish working, Will I be able to push the changes I made in geometrize-haxe submodule ? Or do I need to copy the changes to "the real" local repo in order to commit and push ? If I can do all directlly in one place without copying or pull/push in between executions then I'm fine. Basically monorepos were created mainly to solve that, you have everything together in one workspsace and any change will be reflected on any project. Also you commit/push/pull all together (although this second part is not critical for me, it is critical being being able to code in different projects without having to pull/push before executing tests/probes/etc)Hope you got the idea and sorry to ask but I rarely use submodules.

It occurs to me that if in the future there are more modules, for using this technique we could have a master development repository that just have al the rest as submodules and management scripts for commit push pull, build, test, increment versions and publish (on each of them and in a certain order. You could run that one on travis since it will test all projects. If that works it will be a similar experience as monorepos. Not that we have to implement right now, just thinking if it will work.

What about dependency versions. Where are them declared and maintained ? in .gitsubmodules file ? or in an haxelib file that each project owns? Just curious since I'm not familiar with haxelib or if even supports dependency versions or if it always fetch the latest one.

I manually upload the geometrize haxelib, so it's not always up to date.

I don't think it's necessary to publish automatically on each push, at least I don't and only publish when I feel comfortable and because I often push just to be able to pull from another machine...

Thanks

Tw1ddle commented 5 years ago

@mastef Quadratic beziers are added to the library now, and I think it's working fine now I fixed a bug - scoring the beziers using differencePartial could produce NaN because sometimes pixels on the curve were covered by scanlines more than once: https://github.com/Tw1ddle/geometrize-haxe/commit/aa9a8df00b50cb89def38a2d2e36c79ba30c3653

@cancerberoSgx I tend to use submodules for my projects. I find it's easier to have things in separate repos when deploying demos, so using GitHub pages to host the most recently-built project (pushed to the gh-pages branch by Travis) for example. Lots of pros and cons with mono repos though, yes. What you suggest as a "master" repository sounds like this "super-module" Qt5 uses: https://github.com/qt/qt5 - I'll look into that.

With haxelibs you can define dependency versions through a haxelib.json file, there's a "dependencies" section: https://lib.haxe.org/documentation/creating-a-haxelib-package/