tw1ddle / geometrize-haxe Goto Github PK
View Code? Open in Web Editor NEW:triangular_ruler: Geometrize is a Haxe port of primitive that geometrizes images into geometric primitives
Home Page: https://www.geometrize.co.uk/
License: Other
:triangular_ruler: Geometrize is a Haxe port of primitive that geometrizes images into geometric primitives
Home Page: https://www.geometrize.co.uk/
License: Other
I was thinking: what if in shape.rasterize() you draw the svg onto an offscreen canvas and use that?
This would only apply to js - and I'm not even sure it would have better performance, probably not -, but maybe it's worth trying out. What you think?
Anyway thanks for this lib, I'm already using it. ;D
Would be nice to restrict shape size min/max per step in the options. This way I would start with huge shapes in the beginning, and progressively in later stages reduce the size when more details should be added.
( Would work great with the focus areas from #3 )
more of a convenience feature : being able to decide on strategies based on steps. e.g. first 300 steps triangles, then 300-1000 switch to ellipses, then finally 1000+ enable ellipses, lines and rectangles
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
I've been looking into how to reduce the filesize of files like this :
The .png is 66kb big, but as a svg file should be much much smaller. This could be a great use-case for frontend web images optimization.
Provided issues like #13 #7 and #6 would be implemented, the result could be very close?
Also possibly merging neighbouring same-color shapes. Maybe applying gradient on the final frame.
This is a more complex issue so not sure how feasible - however sometimes I want to keep a background that has less shapes, and focus the new shapes on a certain area in the foreground. It would be nice to be able to select an area that the shapes would be generated in for the next steps.
This is also nice when you create the initial image with e.g. triangles, and then in later steps switch strategies to e.g. ellipses/circles and so on
As a matter of fact, it is quite visible that whereas the first steps are producing large shapes to fill the larger gap between the target image and the initial one, the mean size of the found shapes is mainly decreasing.
Then I found that generating constant size shapes was a loss of computation energy:
Then you have to find a compromise and between the start of processus and the late phase.
So I tried to introduce a sizeFactor in shapes:
getSizeFactor()
method is added to shapes classes to give a feedback on the approximative sizes factor of the found shapesThen the Model get an internal shapeSizeFactor
with an initial value set to 1.0
and that is updated at each call of addShape with a low-pass filter
This shapeSizeFactor
is then used to init random shapes in the interesting size range:
This is really improving the convergence process by a much better random shape generation, and avoiding random large shapes that have a big computation cost, when not any more useful
Hi,
Thanks to all your work on Geometrize!
I'm working on a PHP version of geometrize, based on the Haxe-generated PHP code
https://github.com/Cerdic/geometrize-php with a focus on performance issue as this is in my case a real issue: I plan to compute on the fly low-weight preview svg images as a placeholder for images in web pages.
As a feedback I can point some optimizations I found that are imho applicable to this version:
The last optimization is a bit tricky and maybe not so interresting for a general use:
I added a rescale() method to shapes Cerdic/geometrize-php@995e206
allowing to start the rendering with a super small thumbnail (ie 64px) and increasing it progressively to 128px, 256px… depending of the final precision I want.
In my case this is a good optimisation as first steps generate large shapes that are slower to compute.
I saw that triangles are clamped when mutating, to stay in the bounds
https://github.com/Tw1ddle/geometrize-haxe/blob/master/geometrize/shape/Triangle.hx#L38
whereas they are not clamped in the constructor (corners 2 and 3 can be out of the bounds).
As a matter of fact it seems better to not clamp the corners while mutating, allowing to get partly out of the bound triangles, whereas this is now only possible to with initial random triangles
Hello @Tw1ddle ,
This is a question about executing the API in another target than JS and neko and also a heads up since in neko it runs very slow.
I'm writing a simple program that shows the whole user experience using haxe API. I want to be generic so the code works not only in JavaScript target but in other too.
My motivation for this is measuring the performance of real world use and writing a small documentation on how to use the haxe API since there's none.
See below a working example that creates a bitmap and generates SVG and the .hxml files used to run them in js and neko.
This kind of example, even with really big images, work fine and fast in node.js but in neko is very slow. An empty bitmap of 100x100 with default options and 20 iterations takes 8 seconds while in node takes 0.3 seconds.
I'm not familiar with neko nor I don't know if this is serious but I really would like to execute it in another target then JavaScript and so far I couldn't. I tried also in python, java, and cppia , but both throws errors, python with floats being used as array index, and Java with a symbol not being found. Probably I'm missing something...
My question is:
Were you able to execute the library in another target then js and neko ?
I wanted to know before I try in another languages...
Thanks
package issue;
import geometrize.bitmap.Bitmap;
import geometrize.bitmap.Rgba;
import geometrize.runner.ImageRunner;
import geometrize.exporter.SvgExporter;
import geometrize.runner.ImageRunnerOptions;
class IssueNeko {
public static function main():Void {
var iterations = 20;
var bitmapSize = 100;
var bitmap = Bitmap.create(bitmapSize, bitmapSize, Rgba.create(255, 255, 255, 255));
// painting a red rectangle will make it much much slower but instead is slow wihhout the rectangle
for (i in Math.round(bitmapSize / 5)...Math.round(bitmapSize / 2)) {
for (j in Math.round(bitmapSize / 5)...Math.round(bitmapSize / 2)) {
bitmap.setPixel(i, j, Rgba.create(255, 0, 0, 255));
}
}
var runner = new ImageRunner(bitmap, Rgba.create(255, 255, 255, 255));
var options:ImageRunnerOptions = {
shapeTypes: [0, 1, 2, 3, 4],
alpha: 128,
candidateShapesPerStep: 50,
shapeMutationsPerStep: 100
};
var svgData = [];
for (i in 0...iterations) {
var step0 = Date.now().getTime();
var result = runner.step(options);
trace(Date.now().getTime() - step0);
svgData.push(SvgExporter.exportShapes(result));
}
var svg = SvgExporter.getSvgPrelude() + SvgExporter.getSvgNodeOpen(bitmap.width, bitmap.height) + svgData.join('\n') + SvgExporter.getSvgNodeClose();
trace(svg);
}
}
It would be nice to have a simple haxe code example that doesn't rely on other libs. I tried at first with --interp
but that just kept going and going. I've then managed to compile a cpp version, which was super-fast, but then it kept messing up the colors. I must be doing something wrong.
I'm trying to create more gifs like these so want to make some local code that tries that with different images and different strategies, instead of using the web-demo for every frame. Mainly from .png files.
This is how for I've come so far ( however colors in final image are skewed ) :
import geometrize.shape.ShapeType;
import geometrize.runner.ImageRunner;
import geometrize.runner.ImageRunnerOptions;
import geometrize.bitmap.Bitmap;
import geometrize.Util;
import haxe.Resource;
import haxe.io.Bytes;
import format.png.Reader;
import format.png.Tools;
import geometrize.Model.ShapeResult;
import geometrize.exporter.SvgExporter;
class ImageJob {
public function new(sourceImagePath:String, imageRunnerOptions:ImageRunnerOptions) {
this.sourceImagePath = sourceImagePath;
this.imageRunnerOptions = imageRunnerOptions;
}
public var sourceImagePath:String;
public var imageRunnerOptions:ImageRunnerOptions;
}
class Main {
static public function main() {
var opts:ImageRunnerOptions = {
shapeTypes: [ ShapeType.CIRCLE, ShapeType.ELLIPSE, ShapeType.ROTATED_ELLIPSE ],
alpha: 200,
candidateShapesPerStep: 250,
shapeMutationsPerStep: 20
};
var job = new ImageJob("images/input.png", opts);
var bitmapData = readPixels(job.sourceImagePath);
var sourceBitmap = Bitmap.createFromBytes (bitmapData.width, bitmapData.height, bitmapData.data);
var backgroundColor = Util.getAverageImageColor(sourceBitmap);
var runner = new ImageRunner(sourceBitmap, backgroundColor);
var shapeData:Array<ShapeResult> = [];
for (i in 0 ... 200) {
var sData = runner.step(job.imageRunnerOptions);
for (result in sData) shapeData.push(result);
}
var svgData = SvgExporter.export(shapeData,bitmapData.width,bitmapData.height);
sys.io.File.saveContent("export/output.svg", svgData);
sys.io.File.saveContent("export/output.png", runner.getImageData());
}
static function readPixels(file:String):{data:Bytes, width:Int, height:Int} {
var handle = sys.io.File.read(file, true);
var d = new format.png.Reader(handle).read();
var hdr = format.png.Tools.getHeader(d);
var ret = {
data:format.png.Tools.extract32(d),
width:hdr.width,
height:hdr.height
};
handle.close();
return ret;
}
}
The algo could also try moving existing shapes randomly a few pixels left and right. Would make for a nice effect
For more natural "strokes", the shapes could have gradients instead of fill colors. This would obviously increase cpu by quite a factor.
Have you thought about using custom brushes? So instead of basic shapes, the algo could also try to apply certain custom shaped brushes to make it more paint like
Bonus points would then be to emulate brush strokes
Just an idea, not sure yet about format of brushes
It would be great to be able to override the maximum resolution in the web demo
Currently transparent source files will produce a black background.
Might be nice to have the slider from https://www.geometrize.co.uk/ on the web demo to compare against the original image
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.