How can I smooth output polylines?

As I understand it, your lines are originally based on vectors (they are polylines). Polylines are resolution independent and can be scaled up as much as you want without loosing detail. If you convert them to a bitmap (ofPixels, PNG, JPG), the vector data is lost and the lines become resolution dependent. If you scale up a pixel based image it becomes pixelated.

Maybe you could explain what you are trying to achieve with these images?

Not sure if it’s silly to share this link, but just in case: Understanding Vector and Bitmap Images.

Oh I see…is there a way then to just export the polylines directly to svgs? If that is done, will the drawings still look blocky or will they be like the image on the left: https://imgur.com/a/1bfR8 ?
Other than that, maybe if there were a way to increase the polyline thickness/thickness of the drawing that might be an easier way to resolve my problem.
Basically im breaking down the drawings into smaller lines, but then segmenting them for later use in another program: Help with script

Yes, you can export the polyline to svg.

Assuming you have a polyline called stroke:

// create a test polyline
ofPolyline stroke;
for(int i=0; i<20; i++) {
    float x = 20 + i * 20;
    float y = 50 + 50 * ofNoise(i * 0.1f);
    stroke.addVertex(x, y);
}

You can save it like this:

ofBeginSaveScreenAsSVG("thePolyline001.svg");
ofSetLineWidth(10); // control the thickness
stroke.draw();
ofEndSaveScreenAsSVG();
// Note that the line won't be visible on the screen.
// If you want to see it also in your program, draw it
// again outside ofBegin../ofEndSaveScreenAsSVG()

It should look like the image on the left. You can open the resulting svg in your web browser and zoom in (CTRL+), or in Inkscape, Illustrator, etc.

2 Likes

Oh well thats good news!
So do I replace
ofSaveImage(pix, ofToDataPath("output/" + foldername + "/" + ofToString(_counter) + ".png"));
with
ofBeginSaveScreenAsSVG ?
Sorry…im a bit lost here

You have two version of addImage and I’m not sure which one you’re using.

I assume it would be something like:

void ncQuickDrawImageSave::addImage(ofPolyline & stroke, int _counter) {
  ofBeginSaveScreenAsSVG(ofToDataPath("output/" + foldername + "/" + ofToString(_counter) + ".svg"));
  ofSetLineWidth(10);
  stroke.draw();
  ofEndSaveScreenAsSVG();
}

The one that accepts a vector as argument maybe should iterate over the vector and save each polyline as a separate file?

Ok, I realized that all I actually need is:
ofSetLineWidth(10); in order for my segmentation program to recognize the lines.
They just needed to be a bit thicker so that they could be contoured properly, nevermind outputting it as an svg. https://imgur.com/a/HEIsb
However what im wondering now is, can the lines be smoothed without the need to export it as a svg?
Is there a way of rendering it more graphically pleasing like the idea they show in the second picture of: https://github.com/bgstaal/ofxShivaVG ?

Basically: can I still export as png, but correct the lines to make them smooth?

Take a look at this post. Maybe you can do something like this before drawing your stroke:

stroke= stroke.getResampledBySpacing(1);
stroke= stroke.getSmoothed(3);
stroke.draw();

Or try this one: ofxPoly

Hey hey, so you mean line 30? https://github.com/wearenocomputer/ncGoogleQuickDrawToPng/blob/master/src/ncQuickDrawImageSave.cpp
I tried and it didnt do anything unfortunately…unless its supposed to be line 15, but I get a bunch of errors.
With this ofxPoly, how do I work it?? Do I do something like
void ofxPolyToMesh(ofMesh & mesh, const ofPolyline & polySource, float normalLength);
from
Smoother, better lines from ofPolyLine?

I think there’s a bit of confusion with the terms :slight_smile: smoothing can mean different things.

What getResampledBySpacing and getSmoothed would solve is a low amount of vertices in the polyline. So if your polyline looked like a Z with only 4 vertices, by resampling and smoothing you could make it look more like an flipped S with many more vertices.

On the other hand, the rendering engine does not produce beautiful lines when the thickness of lines is set very high. They look broken on sharp curves.
ugly sharp curves on polylines
For that issue you can use ofxPoly, which converts a line into a mesh. ofxPolyToMesh is different to other functions, in that it does not return the result, but it puts the result into its first argument. So you would call it like this:

ofMesh resultMesh;
ofxPolyToMesh(resultMesh, stroke, 10); // 10 pixel thickness
// now draw resultMesh (which is no longer a polyline, but a mesh!)
1 Like

this code produces this result:

    ofScale(3, 3, 3);
	ofSetLineWidth(10);
	stroke.getResampledBySpacing(1);
	stroke.getSmoothed(3);
	stroke.draw();

As @hamoid said before, to avoid those artifacts we can use ofxPoly. You need to download this addon and add it to your project using project generator. Add #include "ofxPoly.h" to ncQuickDrawImageSave.h. This code produces this:

    ofScale(3, 3, 3);
	ofMesh resultMesh;
	ofxPolyToMesh(resultMesh, stroke, 1);
	resultMesh.draw();

It’s better but I think you want to achieve this? Am I right?

I tried to combine getResampledBySpacing() and getSmoothed() and ofxPoly but no success yet. Maybe someone else can help.

@SebastianSobotka Yeah thats right. Thanks for the help so far guys…ill look around as well and see if I can find anything else that can smooth those corners a bit better

Just wanted to double check…what about: ofxShivaVG (Smooth 2d graphics in oF)
?
Its a renderer, but it supports 2d polylines…

// .h
ofPolyline rough;
ofMesh smooth;

//.cpp
void ofApp::setup(){
    // create random test polyline
    for(int i=0; i<20; i++) {
        float x = 20 + i * 19;
        float y = 150 + 200 * ofNoise(i * 0.3f);
        rough.addVertex(x, y);
    }
    // add extra points to polyline
    rough = rough.getResampledBySpacing(2);
    // smooth it (make it more rounded)
    rough = rough.getSmoothed(4);
    // make it thick with ofxPoly to avoid "glitchy corners"
    ofxPolyToMesh(smooth, rough, 4);
}
void ofApp::draw(){
    ofBackground(255);
    ofSetColor(0);

    smooth.draw();

    ofTranslate(0, 100);
    ofSetLineWidth(16);
    rough.draw();
}

2 Likes

Thanks, It’s a nice example. I had the same idea but had to play a little bit more with parameters.

	image.begin();
	ofClear(255, 255, 255, 255);
	ofSetColor(0, 0, 0, 255);

	ofScale(3, 3, 3);

	// add extra points to polyline
	stroke = stroke.getResampledBySpacing(2);
	// smooth it (make it more rounded)
	stroke = stroke.getSmoothed(15);

	ofMesh resultMesh;
	ofxPolyToMesh(resultMesh, stroke, 2);
	resultMesh.draw();

	//stroke.draw();
	ofSetColor(255);
	image.end();

This is a combination of parameters getResampledBySpacing() and getSmoothed():

Looks pretty good. Still a little rough on the edges, but better than before for sure. Another thing from github: https://github.com/apitaru/ofxSmoothLines
Maybe this could help too? No idea

I think this will be ok for my application, I appreciate the help. I have another question: is there an easy way I could make the background of the images (currently white) transparent? Cheers

Yes, it’s possible. The fourth parameter in ofClear() is alpha. Set it to 0.

    image.begin();
	ofClear(255, 255, 255, 0);
	ofSetColor(0, 0, 0, 255);

Hi hamoid,

May I ask how you use this addon? It seems like really out of dated. And I got so many semantic Issues in Xcode with the ofxPoly’s example file.

THanks!!

ohhh no worries I just figured out.
just change the error part’s type to “auto” then it will works.
thankssss

1 Like