DIY Polarimetric Camera

Building a camera, ...scrap that, a microscope... that turns polarization into color

Public Chat
Similar projects worth following
2 years back I made a polarimetric camera to prove a concept. After I made it the company I work for acquired an industrial one, and the prototype was benched. I've always wanted to go a step further and create one that could do a higher FPS and precision, using a cheap RPI with camera. This project will showcase the original prototype and follow the progress of the new one.

The prototype

The idea is simple: rotate a linear polarization filter in front of the lens and capture an image at 0, 45, 90 and 135 degrees. Then do some math wizardry to calculate the angle of polarization based on the difference in luminance between the 4 pictures. This is how it looks:

What is it good for?

There are a number of ways a polarimetric camera is useful in computer vision. It can remove reflections, detect stress in certain materials and detect scratches. For more information on what the industry is doing see this page.

I like it for the aesthetics mostly and I have another project where I used one as a microscope.


Initialize and run the TMC5160 in motion controller mode using SPI on a raspberry pi

x-csrc - 3.22 kB - 02/18/2021 at 18:06


  • Ok ok...

    E/S Pronk10/20/2022 at 02:22 0 comments

    i scrapped this project a few days back, I’m sometimes too perfectionistic to even begin a project. So instead I’m just gonna build it out of lego, f*ck it 😅

  • TMC5160 motion controller mode

    E/S Pronk02/15/2021 at 18:02 0 comments

    The Trinamic TMC5160 has a motion controller mode which is very cool. It allows you to set things like acceleration parameters, destination, speed via SPI, instead of using the STEP / DIR pins.

    I have been using the TMC5160 SilentStepStick as a board for many applications but by default  it isn't configured as a motion controller and it doesn't expose a pin to change it.

    You can cut a trace to put it in motion controller mode, and even though the documentation says it needs to be connected to ground, I've never actually had to do so (your results may vary).

    made with the polarisation microscope

    Check out the datasheet on this page and check page 34, register IOIN. This register can be read out to see if the cut was successful, Bit 6 should be 0 now and the motion controller should be active.

    In order to test it out I wrote a simple program in C that runs on my raspberry pi. It initializes the TMC and accellerates until a maximum velocity is reached. After pressing enter it will decelerate and stop.

    #include <stdint.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <linux/types.h>
    #include <linux/spi/spidev.h>
    static const char* s_spidev = "/dev/spidev0.0";
    static uint8_t s_mode = 3;
    static uint8_t s_bits = 8;
    static uint16_t s_delay = 0;
    static uint32_t s_speed = 1000000;
    static int transfer(int fd, uint8_t reg, uint32_t val)
    	uint8_t tx[5] = { reg, 
    		(val>>24) & 0xFF, 
    		(val>>16) & 0xFF,
    		(val>> 8) & 0xFF,
    		(val>> 0) & 0xFF };
    	uint8_t rx[5] = {0};
    	struct spi_ioc_transfer tr = {
    		.tx_buf = (unsigned long) tx,
    		.rx_buf = (unsigned long) rx,
    		.len = 5,
    		.delay_usecs = s_delay,
    		.speed_hz = 0,
    		.bits_per_word = 0,
    	int rc = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    	if (rc == 1) return rc;
    	printf("%02X %02X%02X%02X%02X -> %02X %02x%02x%02x%02x\n",
    			tx[0], tx[1], tx[2], tx[3], tx[4],
    			rx[0], rx[1], rx[2], rx[3], rx[4]);
    	return 0;
    int main()
    	int rc;
    	int fd = open(s_spidev, O_RDWR);
    	if (fd < 0) { perror("SPI OPEN"); return -1; }
    	rc = ioctl(fd, SPI_IOC_WR_MODE, &s_mode);
    	if (rc < 0) { perror("SPI WR MODE"); return -1; }
    	rc = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &s_bits);
    	if (rc < 0) { perror("SPI BIT PER WORD"); return -1; }
    	rc = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &s_speed);
    	if (rc < 0) { perror("SPI MAX SPEED HZ"); return -1; }
    	transfer(fd, 0x01, 0x00000000);// READ GSTAT
    	transfer(fd, 0x04, 0x00000000);// READ IOIN
    	transfer(fd, 0x8b, 0x000000EE);// WRITE GLOBAL SCALER: 0xEE
    	transfer(fd, 0x90, 0x000003E1);// WRITE IHOLD:0x01 IRUN:0x1F
    	transfer(fd, 0x93, 0x00014000);// WRITE STEALTHCHOP UPPER VELOCITY
    	transfer(fd, 0x94, 0x00018000);// WRITE COOLSTEP LOWER VELOCITY
    	transfer(fd, 0x95, 0x0000002F);// WRITE COOLSTEP UPPER VELOCITY
    	transfer(fd, 0xA0, 0x00000001);// WRITE RAMPMODE: 0 = POSITION MODE / 1 = VELOCITY MODE
    	transfer(fd, 0xA3, 0x00000500);// WRITE START VELOCITY
    	transfer(fd, 0xA4, 0x00000600);// WRITE A1 ACCELLERATION (FROM VSTART TO V1 IN POSITION MODE)
    	transfer(fd, 0xA5, 0x00010000);// WRITE V1 VELOCITY (POSITION MODE)
    	transfer(fd, 0xAA, 0x00000D00);// WRITE D1 DECELLERATION (FROM V1 TO VSTOP IN POSITION MODE)
    	transfer(fd, 0xAB, 0x00000600);// WRITE VSTOP VELOCITY (POSITION MODE)
    	transfer(fd, 0xAC, 0x00000800);// WRITE TZEROWAIT
    	transfer(fd, 0xB3, 0x00000000);// WRITE DCSTEP = OFF
    	transfer(fd, 0xB4, 0x00000000);// WRITE SWITCH MODE NO SWITCH STUFF
    	transfer(fd, 0xEE, 0x0000001C);// WRITE DC CONTROL, GUESS
    	transfer(fd, 0xEC, 0x10410155);// WRITE CHOPCONF
    	transfer(fd, 0xA1, 0x00000000);// WRITE ACTUAL POSITION
    	transfer(fd, 0xA7, 0x00060000);// WRITE VMAX / TARGET VELOCITY
    	transfer(fd, 0xAD, 0x00400000);// WRITE TARGET POSITION...
    Read more »

  • The idea

    E/S Pronk02/15/2021 at 14:14 0 comments

    This is what I'm thinking:

    • Get a ball bearing with an inner diameter >= the diameter of the lens.
    • 3d print a gear with an inner diameter == outer diameter of the ball bearing
    • Attach a linear polarization filter to the gear so it can rotate in front of the lens.
    • Attach a stepper motor that drives the gear
    • Use a TMC5160 silentstepstick, cut a trace and put it into motion controller mode
    • Have the TMC diag pin toggle on "position reached" and have it control the shutter
    • Update the position in the TMC to trigger on the next angle
    • Add the images to a rotating buffer of size 4
    • Use the 4 most recent images as textures to a GLES shader that calculates polarization angle.

View all 3 project logs

Enjoy this project?



Esteban wrote 10/18/2022 at 02:25 point

fantastic! It's like getting a 'normal map' of reality! I wonder if an algorithm could predict depth data from this

  Are you sure? yes | no

E/S Pronk wrote 10/20/2022 at 02:19 point

Hehe yeah, polarization contains 2 of the 3 dimensions you need to calculate a normal. There are some algorithms out there, it’s called “structure from polarization”

  Are you sure? yes | no

Gavin Johnston wrote 02/23/2021 at 11:00 point

This video is showing the prototype of the camera I am looking for the fully completed camera which is ready to use. I am being an writing service blog photographer this camera will help me in my work and even make my work easy as it is having automated mode which shoots by its own if we set instructions to it.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates