I started this surface scanner project last summer because I wanted a simple and portable device to capture textures. I already had experience building similar stationary scanners, but creating something lightweight & practical was challenging & exciting!
This project is the result of a collaboration with my friend Jan Brzeczkowski, who is working on a similar scanner.
We worked together, especially on preproduction, to make better design choices.
Let’s start introducing some background concepts needed to understand this project: Photometric Stereo and Cross Polarisation. If you are familiar with those concepts, you can scroll down to the next section.
Photometric Stereo is a technique used to estimate surface normals by observing the surface under different lighting conditions, assuming captured pixel intensity is proportional to the surface orientation & the light direction.
Since the first algorithm introduced by Woodham in 1980, it has been a pretty active research field. Now it’s possible to estimate not only the surface normals but also other properties like diffuse albedo, ambient occlusion, or specular information.
Photometric stereo is less popular than other famous 3D scanning techniques, but it has been used in production by many studios to create textures. It was also used to capture some of the assets you can find on Surface Mimics, Texturing.xyz, Substance Source, Megascans, etc.
Cross polarisation is a photography technique used to remove specular reflections from a given light source in a photograph. It exploits the fact that specular light keeps its polarisation state, while diffuse light doesn’t.
Photographers use polarizing filters quite a lot. Placed in the front of the lens, they can help to reduce specular highlights because natural light & reflections tend to be partially linear-polarised.
If we place a linear polarising sheet in front of a light source, we make sure to polarize all the emitted light in a given way.
If the filter on the lens is rotated by 90° compared to the sheet, then it will block the specular reflections generated by the light source. It’s called cross polarisation.
Additionally, we can capture a “parallel polarised” picture with both filters aligned the same way (without moving the camera) to have a reference photo with specular reflections.
We can’t just remove the filter, because polarising filters are cutting some of the light (about 1 EV) just like neutral density filters.
If we subtract the cross polarised photo from the parallel polarised one, we kinda “isolate” the specular layer.
For photometric stereo, it’s beneficial to separate specular and diffuse layers to process them independently.
A lot of photometric stereo algorithms assume the surface is Lambertian, and cross polarisation gives you something closer to a Lambertian surface.
According to the previous sections, I needed to build a portable scanner able to shoot multiple cross & parallel polarised pictures of a surface under various light directions with the following specification :
- The surface scanner has to be “truly” portable and lightweight (light enough to be used with a DSLR on a standard tripod or hand-held).
- Have small, but high-capacity battery to power it.
- Emit enough light to allow “fast” shooting (don’t want to wait during a 5 seconds exposure for each picture).
- Big enough to scan at least 60 × 60cm surfaces in a single capture.
- Fast & robust cross / parallel polarization switch.
- Have enough different light directions to produce good quality maps, but keeping the capture fast.
- Able to focus and safely trigger the DSLR.
- Ideally, the structure needs to be isolated from external light.
This excellent post on rtgfx is a good starting point. I liked the approach, but I wanted something more flexible, with a more robust structure, more light power, and able to capture larger surfaces.
The Scanner Structure Design.
After lengthy discussions with Jan, we figured out that using a photography softbox for the scanner structure would offer multiple advantages. It’s lightweight, foldable, pretty robust, and quite isolated from external light!
I got the Elinchrom Deep Octabox 100. The one-meter diameter seemed nice to have a “not-too-small” capture area, keeping the system easily portable.
Jan came up with a fresh design for a Bowens mount that would allow attaching a DSLR to the softbox. We reworked the design together and ended up with this cute 3D printed piece :
To avoid strong indirect light bounces inside the scanner. I painted the inside of the softbox in black.
Lights & Polarization Switch Design.
I chose to use eight different light directions; it’s a nice compromise to keep the scanner simple, capture quite fast, but maintain decent quality.
Simple photometric stereo approaches assume directional lighting. The good news is that directional lights don’t exist in real life!
Most people end up using distant point lights. It works quite well, but if the surface has significant height variations, it can introduce strong & sharp cast shadows that will be problematic during the process.
It’s also possible to use larger area lights. In this case, cast shadows are less problematic, but it can introduce new issues like visible “ambient occlusion” in photos, and lack of precision during the process.
For this scanner, I used vertical led strips. The lightweight and robust nature of LED strips made them perfect candidates for this portable scanner.
The strips act a bit like a point light on the horizontal axis, and like an area light on the vertical axis. This way, the lighting is directional enough but doesn’t produce too sharp cast shadows.
For the polarisation switch, there are two options :
- Switch at the lens level using a motorized rig, or liquid crystal polarization modulator.
- Switch at the light level using a motorized rig or multiple lights.
It wasn’t possible to use a motorized rig for this project, keep things fast and simple. Liquid crystal polarization modulators are super expensive if you want a custom size.
Switch at the light level using multiple lights (one cross-polarized and one parallel-polarized) is fast and easy. But it can introduce a visible offset between the two lightings in the final pictures, especially if the lights are quite close to the surface. Fortunately, using long vertical led strips should make the offset less visible.
Let’s Build It!
Base Structure Assembly.
The first step was gluing the LEDs on the softbox. For each light direction, I used a pair of 50cm strips for both polarization states (sixteen meters in total).
Then, the wiring was a bit messy! At least it looks quite good from the outside, with all the wires in a single casing, with a single Molex output connector.
Adding the polarized filters on the LEDs
The idea was to cut small rectangles out of a sizeable polarized sheet and then to glue them on the top of the LED strips.
But polarized sheets are damn expensive! To save space (and money), I used the Houdini UV packer to calculate an optimized stack of small rectangles with the required orientations. This stack was then printed on multiple A4 sheets and fixed on top of the polarized layer.
Cutting was a bit tedious, but finally, I ended up with all the required small rectangles!
The last step with the polarizers was to glue them on the top of the LED strips, alternating cross and parallel polarization for each light direction.
The Surface Scanner’s Brain
The electronic part of the project was also quite challenging! I needed to design a small PCB to control the lights, the polarisation switch, and to focus/trigger the DSLR.
I worked with JLCPCB, and I’m super happy with the service (they didn’t pay me to say this).
They offer a free circuit design tool named EasyEDA that works just well if you don’t need to do super-advanced stuff.
I also tried the SMT assembly service; I got all the small resistors, MOSFETs, and ICC switches required for LEDs control pre-soldered for a very reasonable price!
In the seeks of simplicity, I used an Arduino nano to handle the logic and robust Molex connectors for I/O.
To control the DSLR, I figured out after many kinds of research that the safest way might be to use optoisolators. This way, the camera circuits & the PCB are isolated. Here is the schematic I used for camera shutter and focus control.
For the battery box, I couldn’t find any pre-packaged lightweight product able to deliver at least eight amps at 12V, so I decided to build a DIY battery with three 18650 lithium cells and a BMS.
The BMS is essential because it protects the battery against over-charge, over-discharge, and short circuits. The one I used also balance the cells to allow charging in serial.
During discharge, the battery goes from 12.6 V to about 9V. I preferred to use it directly instead of adding a voltage regulator to save space and weight. The LEDs are a bit brighter at full charge than at full discharge, but direct use makes the whole thing more portable.
I also built an additional bigger battery with four cells and a buck converter for constant 12V output, for stationary use.
I printed an enclosure for the battery to be able to fix it on the rods and added a capacitor to check the remaining charge.
At this point, the scanner was ready for some testing!
The lighting seems pretty good, quite directional but not too sharp. Above a capture size of 50 × 50cm, corners become a bit problematic.
I will not detail the photometric stereo process in this post, maybe in a dedicated one later. But I used a custom implementation of a standard approach, using least-squares regression.
I’m always amazed by the number of details you have in a photometric stereo scan! Unlike photogrammetry, every pixel adds sharp info on the normal map.
I wasn’t super inspired (and the weather was terrible) so I tried the scanner on some indoor surfaces. The ambient light wasn’t a problem at all with the softbox.
Here is an overview of all the different parts composing the scanner:
- Softbox structure. 1.9 kilograms.
- 3D printed DSLR Bowens mount. 0.2 kilograms.
- SmallRig rods. 0.1 kilograms.
- SmallRig DSLR rods fixation. 0.25 kilograms.
- Nikon D810. 1.75 kilograms.
- PCB. 0.1 kilograms.
- 3D printed battery box. 0.25 kilograms.
The total weight of the scanner is about 2.8 kilograms (6.2 pounds) without the DSLR and 4.6 kilograms (10.1 pounds) with the heavy Nikon D810.
I’m able to shoot at 1/10 and to focus & capture the sixteen photographs in about 12 seconds. I haven’t done in-depth testing to reduce capture time. The bottleneck when shooting in raw is the internal camera buffer.
I’m pretty happy with the final result. The capture area is a bit small, but that’s the deal to have something portable.
There is plenty of room for improvements:
- There is a 12V output to control a backlight to scan translucent materials like paper or vegetation. I need to build a portable backlight.
- I also need to print a proper enclosure for the PCB.
- I’ll try to reduce the capture time a bit (12 seconds is not that bad).
- Do more testing, especially on outdoor materials.
- Try to stitch multiple captures to scan areas more significant than 60 × 60 centimeters. And maybe combine photogrammetry and photometric-stereo.
Thanks for reading, don’t hesitate to ask questions in the comments 🙂