Introduction: Photo Images Mapped on Arbitrary 3D Shapes in Openscad, V5

About: Retired but working.

I have been importing .png files into openscad's surface() function, but I wanted to have more control over the 3D object on which the image pixels are shown. So I created my own tool to a) obtain the pixels from a png file, b) encode them into an openscad array using python, c) create a somewhat arbitrary geometric shape, and d) paste the pixels onto that shape.

I made use of the excellent nSplines library by Rudolf Huttary, Parkinbot, found on thingiverse,

nSplines does a bunch of heavy lifting, to create a single polyhedron, where I can control all aspects of the shape! Including pasting pixels onto it!

Step 1: Getting the Pixels Into Openscad

I used a python script to read some .png files, mostly I work with Photoshop to create and modify the images. This script, png-reader.png, can at least read the .pngs created by Photoshop.

This script outputs a text file to standard out, which is a 2D array of greyscale pixels. Think of the array as scanning left to right, from top to bottom, of the image. Each single datum is the brightness of one pixel. 0 is dark and 255 is fully white.

The script takes one argument on the command line, the png file name:
python3 5-6px.png

I attach a very small png file, 5-6px.png, so you can see the output. The output of processing an image should be placed in a .txt file for openscad to process. This one looks like this:

// x 5 y 6 pixels 0x7f167c5cd630> info {'greyscale': False, 'alpha': True, 'planes': 4, 'bitdepth': 8, 'interlace': 0, 'size': (5, 6)}


5_6pxpng = [

[45.0 ,45.0 ,45.0 ,0.0 ,255.0 ],

[0.0 ,0.0 ,0.0 ,0.0 ,0.0 ],

[0.0 ,0.0 ,0.0 ,27.88235294117647 ,2.6470588235294117 ],

[0.0 ,0.0 ,0.0 ,12.705882352941176 ,1.2352941176470589 ],

[0.0 ,0.0 ,0.0 ,0.0 ,0.0 ],

[0.0 ,0.0 ,0.0 ,0.0 ,45.0 ]


The 0.0 values are black pixels. Notice the fully white in the upper right corner.

Step 2: How Is a Pixel Represented on an Openscad Object?

The built in function surface() takes each greyscale pixel value and turns it into a column where the height depends upon the brightness. This means you can see an image only when the light shines across it favorably. There is no actual black to white lightness change!

Surface creates one flat polyhedron.

My goal is to create an arbitrary shape and place those pixels on it. So this experiment became forming the shape of a regular rectangular building, a capital building, and adding pixels !

This is my Openscad design, photo-analyzer-5.scad.

To understand what surface() does, take a look at my function RectImage_fromgreyarray().
It is stylized in the nSplines design, which is to form a series of 2D polygons, one per row of pixels, where each poly traces a line crossing the image, with constant increment of x coordinate, and the y coordinate is almost constant but is varied by 0..5 units based on pixel brightness.

There is one such poly for each row of pixels. Then this list of 2D polygons is fed to nSplines() which creates a polyhedron. In the attached image, on the right side, you can see the capital building image on a flat shape, much as surface() would create.

Step 3: How Is a Non-flat 3D Object Created for the Image?

Now consider the "pixel row polygon line" as tracing across the row of pixels, with the x dimension stepping by units, but now the y dimension is set to trace out the building shape. And additionally the y dimension is +- the pixel quantity. So the building shape dimension is a relative large unit amount, say facings and porch of 10s of units, while the pixel "ripple" in the line is 1-5 units.

This is the basic concept. In my design file, photo-analyzer-5.scad, I choose to do something a bit elaborate, to define the building shape. I did not just set fixed rectangles and columns, etc. Rather I use a black and white image, created in Photoshop, overlaying a building photo, to trace the building outline. Then photo-analyzer-5 finds the edges of a building surface, and uses that to guide the polygon line!

Additionally a modifying slanted line can be defined, to break away from the rectangular structure.

Step 4: Modeling the Building Shape From a Top View Outline

My model takes several png files to process, not for creating an image, but rather to discover the building shape by analyzing the photo. I start in Photoshop with a top view, then create a black and white outline for a given layer of the building, starting at ground level. See the first image attached here. The white overlay will be searched as the arrows show, to find the white leading edge to represent the building front extruded structure at ground level.

See the blue shapes in the attached openscad screen capture. In this case I have used Photoshop, looking at the top view, and created 4 black and white building outlines, from ground level, then lobby level, then square tower, then round tower.

photo-analyzer finds the front leading edge where the white portion begins, forms a line of that, extends it upwards to the next layer, and thereby extrudes the building shape! Each such line defining the start of a rectangular layer can be modified with a slanted line, typically for a roof angle.
Kind of primitive, but that is what I came up with to create building geometry.

Step 5: Converting All the Pngs to Openscad Array Definitions

Given the front image photo, and the top view building black & white geometry photos, all output from Photoshop, I feed each one through the python script, which outputs openscad array definitions.

I label these as .txt files. I attach my layer files here. Each is named in the photo-analyzer.scad design file, and is input by openscad as an include file.

It does take openscad, on a modern CPU, several minutes to absorb all this.

Step 6: Size of Front Image File to Process

300 pixel width of the front image photo takes openscad about 5 minutes to process. I also attached a 1000 pixel file, and that takes 2-3 hours to generate the polyhedron!

There is additional information in the photo-analyzer-5.scad design file.

Recognize that no openscad objects are created until the very final nSplines call for the polyhedron. Up to that point, we are manipulating arrays of numbers!

If you have any questions, feel free to post!