Building a Portable & Lightweight PBR Surface Scanner.

7 min read

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.

Background.

Photometric Stereo.

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.

Reconstruction of a leather surface using photometric stereo with an older stationary scanner.

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 Polarization.

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.

Using a polarizing filter in front of the lens and rotating it, you can reduce specular highlights of natural light that is 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.

Lens polarizing filter blocks direct specular reflections but allows some diffuse light to pass.

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.

Parallel and cross polarised photos of the same subject using a single strobe light.

If we subtract the cross polarised photo from the parallel polarised one, we kinda “isolate” the specular layer.

Isolated specular reflectance, desaturated and remapped for display purposes.

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.

Design Specification.

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.

Elinchrom Rotalux Deep Octabox 100cm

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 :

3D printed DSLR Bowens mount adapter.

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.

One of the LED strips used for this project.

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).

LED strips fixed on the softbox.

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.

Outside view of the connection wires.

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.

Printed blueprint generated with the Houdini UV packer algorithm.

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.

Polarizing gel glued on the LEDs. Without filter, cross, and parallel polarization on the lens.

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.

PCB preview in EasyEDA. There is a 3D preview, and you can upload custom component 3D models, not bad for a free tool running in your browser!

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.

The scanner’s final PCB with all components soldered.

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.

One 4N35 optoisolator used for shutter, and another one for focus. You can also use a single two-ways optoisolator.

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.

3S battery with BMS Protection board.

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.

First test with both PCB, battery, and structure.

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.

Final scanner, ready to capture!

First Tests.

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.

Example of photos taken during a 60 × 60cm surface capture.

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.

Reconstructed diffuse albedo, diffuse normals, height, and roughness maps.

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.

Zoomed view of the previous maps.

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.

Examples of reconstructed surfaces rendered in Houdini.

Conclusion.

Here is an overview of all the different parts composing the scanner:

All the separated blocks of the surface scanner, easy to transport & store.
  1. Softbox structure. 1.9 kilograms.
  2. 3D printed DSLR Bowens mount. 0.2 kilograms.
  3. SmallRig rods. 0.1 kilograms.
  4. SmallRig DSLR rods fixation. 0.25 kilograms.
  5. Nikon D810. 1.75 kilograms.
  6. PCB. 0.1 kilograms.
  7. 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.

As the scanner weighs less than 5 kilograms, it can be used on a tripod to capture vertical surfaces.
Example of a captured wall-paint surface using the scanner in a vertical position.

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 🙂

20 Replies to “Building a Portable & Lightweight PBR Surface Scanner.”

  1. Hi Paul,

    This portable scanner is amazing. I want to make something similar for attach multiple scans togheter.

    Any idea of commercialize it?

    1. Hi Ricardo, thanks for your comment.
      I have no commercialization plans, would require a huge amount of work. I’m just sharing, and hope other people will also share if they make something better starting from that post 🙂
      Stitching scans is quite challenging because of perspective, but it’s the way to go if you want more than 50×50 cm area with a portable device.

      1. Curios to see the next post….I hope to see a photogrammetry and photometric stereo combined togheter.

    1. Not yet :), but it can work, the problem is you need to shoot pretty fast to capture a moving subject.
      Maybe shooting fewer photos and raising the ISO, it should be able to capture full sequence in less than 2 seconds.

      I’ll probably do another post with more in-depth testing and results.

  2. Thanks a lot for sharing. I’ve been looking online for ideas on PBR scanning and this is super cool to see. Even printing your own board?! Impressive stuff. Really looking forward to the post about the photometric stereo.

  3. Hi,

    Thank you for fantastic article.
    This is first time I see cross polarization done on pure light level only, but I am confused by this setup..could I please ask you if you would be willing to explain it further?
    – At beginning of article you mention parallel polarization as purely optional for control. If I don’t need that, would I still build the polarization at lights the same way as you did here? With both cross-polarized and parallel polarized strips?
    – You show 3 images of the strips (cross, parallel and no filter). Is the 3rd (no filter) just for information? If I understand it correctly, all 8 directions feature just the setup of cross and parallel. Looping back to my first question, do I need the parallel strip?

    Last :- D The 0/1/2/3/4 is to account for curvature of your dome ?

    I’ve been building a simpler setup with rotating filter at lens level but even there got stuck. I wish I could find someone to help with consultation, would pay anything for that.

    1. Hi George, glad you liked the article.

      For cross-polarization / co-polarization, you need a filter in front of the lens and another filter in front of the light source. In this setup, the polarization switch happen at the light level.

      – Parallel polarization is helpful to have a reference image with specular reflection, with the same exposure as the cross-polarized one. In my case, I use it to estimate roughness / specular maps. If you don’t need it, you can polarize the full rig in a single configuration to shoot only cross-polarized pictures with more light.

      – For the “cross”, “parallel” and “no filter” images. I was talking about the filter placed on the camera actually used to take the picture. a 0° filter block some of the strips, and 90° filter block the other ones.

      – The 0/1/2/3/4 on the polarizing filter cuts are indeed here to retrieve the correct orientation.

      Setups with rotating filters in front of the lens work well too 🙂 They tend to be slower, and would require more engineering skils to make something robust & portable. The advantage with a switch at lens level it that you end up with more light power, and better light consistency between cross and parallel polarized shots.

  4. Hey, I’ve had a quick look online for programs that can do this kind of capture but so far I haven’t found any.
    What software do you use?
    is there a free option (though I know its probably not likely)
    Thanks a lot!

    1. Hi Strike_Digital,
      You can obtain good results with Substance Designer, or Dabarti capture (this one is commercial, but based on opensource GitHub code).
      I use some custom python code. If you have some programming skills, you can search for “photometric stereo” on GitHub/GitLab and you’ll find plenty of implementations to test/learn how it works, and eventually develop your own software.

      We (at Adobe) are working with HP on a plug-and-play device for photometric-stereo capture, search for project Captis 😉 .

  5. Thank you a lot for sharing your valuable experience with others generously. Would you please send the main papers and algorithms you have used for your BRDF data processing. I need to know the theoric aspect of processing precisely. for example,
    1- How do you model strip light in BRDF computations?
    2- How do you compute Roughness and Metalness and Ambient Occlusion from Specular image (difference of parallel and cross-polarized images)?

    Thank up again, good man!

  6. Hi Paul,

    Thanks for posting such a great article on all of your hard work. I have also been building a similar scanner and wondered if there were any chance at all you could post your optimised Houdini UV cut out sheet for the polarising film it would be massively appreciated.

    Keep up the good work,

    Best

    Oliver

  7. Hi Paul,

    Thank you for your superb article, it has very much informed the direction I’ll take with a system I plan to build.

    I see you designed your own board to control the camera and LEDs, do you mind me asking you what made you go down this route as opposed to using an off the shelf Arduino, RaspberryPi or similar? Also, I wonder if you are able to share the camera mount design you used here? I’m afraid I don’t have the skills to rustle something similar up, perhaps you would sell one?

    Anyway, great piece, thanks.

    DJ

    1. Hi DJ,

      Actually the brain IS an Arduino 🙂 I just designed a simple board with connectors and plugged the Arduino in (as you can see in the pictures). Having a custom board makes the whole thing more portable & clean (instead of having messy cables everywhere).

      About the camera mount, it’s really specific to the Nikon D810 and was originally designed by my friend Jan, so I can’t share it here.

      1. Hi Paul,

        Thanks for the reply. I’m hoping to incorporate an Arduino myself.

        No problem on the custom mount, I’ve mocked up a rig which will hopefully work, a buddy has offered his assistance with the printing. Really looking forward to seeing the results.

        Stay safe and have a good one.

        DJ

    1. Hi Jack, Thanks.

      The article from rtgfx was really good alma matter. Actually, there is already a link in my article 🙂 .

  8. How is this roughness map made? Did you measure it with a photometric scanner? Can you tell me your method?

Leave a Reply

Your email address will not be published. Required fields are marked *