Effective QR-scanning with the Raspberry Pi and Camera Module

For a recent project I had a need for a reliable and fast QR-code scanner. I had an Raspberry Pi 2 single-board computer on hand and coupled with the Pi Camera Module and some elbow grease I managed to come up with a rather sweet setup.

Hardware

The official Raspberry Pi version 2 Camera Module consists of a 8-megapixel Sony IMX219 sensor mounted behind a fixed focus lens on a small circuit board. The board connects to the computer CSI connector via a flexible ribbon cable.

Cable

The stock ribbon cable supplied with the Camera module is too short (150 mm) to allow for a comfortable positioning of the module for QR-scanning. The are available replacement flex cables of various length that can be easily swapped in — I went with a 500 mm cable.

Focus point

The camera system has a huge depth of field but the fixed lens is still focused too far away to get sharp shots at the distances one would want in a QR-scanner. The lens is fixed with some glue but when this is broken or scratched off is it actually possible to rotate it in its assembly thus adjusting the focus point of the system.

tools

Tools of the trade.

There are many instruction videos on the net showcasing various techniques to achieve this, what worked for me was a small pliers to keep the non-rotating part of the assembly secure while applying force on the lens knobs with a tiny pointed screwdriver to force the lens to rotate counter-clockwise.

rotateReal force is actually required to break off the glue, but after this can the lens be adjusted rather easily. To determine the amount of rotation required I’d recommend to take frequent snapshots with the raspistill CLI tool shipped with Raspbian during the operation, stopping when sharp shots at 10 cm are achieved.

According to reports should it be possible to unscrew the lens from the assembly if it’s rotated too much. I’d like to think it would be quite finicky to re-attach so be careful! It’s only a matter of ~ 360° of rotation to achieve the desired focus point.

Software

The first step after attaching the camera is to enable it in  /boot/config.txt  (can be done with simple raspi-config utility), rebooting and verifying basic camera functionality with raspistill.

For the next steps are there a plethora of  write-ups. Many solutions appear to be quite fragile. I wanted something more robust, something not depending on python libraries that’s not installable with pip or downloads of binaries from unmaintained SourceForge-projects.

I finally ended up with agilerule’s QRScanner.java which utilizes the proven zxing java QR-code library (appears to be very popular in the Android eco-system) to detect QR-codes in snapshots taken by the standard raspistill command line tool. I threw in some optimizations:

  • The time consumed by zxing to detect a QR-code is proportional to the resolution of the image. The full 8 megapixel sensor resolution is very much overkill, I finally settled for 400×300 pixel snapshots (0,12 megapixel) as a compromise between detection speed and accuracy. This low resolution means that the image-acquisition, QR-detection cycle is dominated by the acquisition phase and that it’s possible to  detect ~1 QR-code/second.
  • Rather than dumping the acquired images to the root file system one can utilize tmpfs, thus saving some wear-and-tear on the SD-card and also perhaps achieving a minuscule performance improvement.

To try it:

  1. Clone the repo: git clone https://github.com/nordstrand/qr-scanner-for-raspberry-pi
  2. Install maven
  3. Run: mvn clean install exec:java

Conclusion

This QR-scanning setup is quite usable and responsive but cannot be compared with what you’d find at the super market checkout line when it comes to speed and accuracy.

The item to be scanned should ideally be positioned as parallel to the camera film plane as possible. Sharp shadow lines falling on the scanned item can cause problems. So can light sources shining directly into the lens. What worked best for me was an inverted mount, with the camera pointed down towards a dark surface. I’d also recommend to add a buzzer that can make some beeps after succesful scans.

position

~10 cm from the camera film plane to the scan target will work fine for a wide variety of QR-code sizes.

My main focus of improvement would be to increase the scanning speed. That would entail using something other than raspistill still image acquisitions, perhaps time lapses or trying to access the camera through a lower-level C interface.

 

 

Advertisements

Docker tips for java developers

Latest comes with new guarantees

Unlike the SNAPSHOT-version concept of the ubiquitous Apache Maven dependency manager the so-called “latest” tag in Docker comes with no effort to ensure that a somewhat recently published artifact/image is used. Thus will:

$ docker run myrepo.com/myimage:latest

only pull the latest  image from the repository when run the first time. On subsequent executions will Docker just re-use the myimage:latest image that was pulled into the local repository. An explicit:

$ docker pull myrepo.com/myimage:latest

is required to get the latest image.

Docker Compose up is actually quite smart

Re-running the up command on an already “up” project will check for any deviation between the running services and the configuration in the docker-compose.yml file.  A delta wrt. e.g. an environment variable value will automatically be reconciled by Docker Compose by stopping and removing any outdated container(s) followed by relaunching with the updated configuration set. This can save serious time compared the more brute-force method of tearing down and starting up all containers in the project after every docker-compose.yml change.

Docker volumes requires explicit cleanup (for now)

Removing volumes associated with containers requires an extra parameter:

docker rm --volumes mycontainer

If –volumes is left out any associated volumes will remain for ever, hogging disk space.

The Docker volume subsystem appears to be significantly reworked in the upcoming Docker 1.9 version with new features such as the listing and removal of orphaned volumes.

Testing logging behaviour sans Mockito

The most popular post in this somewhat dormant blog is Testing logging behaviour in four code lines flat. The approach described there relies on everyones favourite unit testing mocking swiss army knife – Mockito. To achieve the purpose of unit testing logging Mockito is however not a required drink, some simple Log4j coding goes a long way:

import org.apache.log4j.SimpleLayout;
import org.apache.log4j.WriterAppender;
import static org.hamcrest.CoreMatchers.is;
import org.junit.Test;
import static org.junit.Assert.assertThat;

public class FooTest {

  @Test
  public void testMethod() {

    StringWriter stringWriter = new StringWriter();

    Logger.getRootLogger().addAppender(new WriterAppender(new SimpleLayout(), stringWriter));

    doStuffThatCausesLogging();

    assertThat(stringWriter.toString(), is("WARN - doh\n"));
  }
}

The code is still acceptable and quite compact. However the expressive niceties Mockito provides are lost and making assertions about logging levels, timestamps and multiple logging invocations takes a lof of cruft. Hence I really see few reasons for this approach if Mockito is available.

How to set a custom DNS server with Java System properties

Recently I was in the position of having to override the system default DNS server configuration with a custom DNS server for a Java app. Expecting this to be easily achievable along the line of the well-known http.proxyHost/http.proxyPort JVM parameters I whipped out Google.

Turned out to not to be so simple.

Obviously I got some search hits, but no simple recipe for the simple configuration change I was looking for. After spending some time with the leads I was able to conclude that, as a consequence of  an apparent exemple of over-engineering by Sun, the following is explicitly required just to change the JVM DNS server:

//Override system DNS setting with Google free DNS server
System.setProperty("sun.net.spi.nameservice.nameservers", "8.8.8.8");
System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun");

Testing logging behaviour in four code lines flat

Update: Testing logging without Mockito is also viable.

Adding assertions for logging behaviour to my unit tests have been a long standing item om my ToDo list. This imperfection have been a nagging thorn in my side since it obvious that logging is a critical aspect (no AOP pun intended) of any commercial system of importance. But I thought that it must be hard and boring work to add tests for logging. To be honest I’m no fan of boring work. Recently I finally got around to take a shot at it and found it surprisingly easy to accomplish in a mavenized Spring project with the help of the everyone’s favorite Java mocking library: Mockito.

Originally I though I had to modify all the classes under test to accept a log4j Logger as constructor argument and mock that logger in the unit test. This would have required quite a lot of code rewrite since most classes in the project simply use:

Logger.getLogger(this.getClass())

to get access to a logger instance. Also I don’t like the idea to “pollute” the constructors with additional arguments, most classes had just enough dependencies passed in that way as it were.

Next up was an idea to write a custom log4j Appender and add a log4j.properties to src/test/resources with:

log4j.rootLogger=ERROR,TESTAPPENDER
log4j.appender.TESTAPPENDER=com.my.fantastic.MockedAppender

The main problem with this approach is that MockedAppender instance would be shared by all unit tests, forcing manual (ugly!) resets of its state between test invocations.

Then I discovered that log4j provides an API for dynamic Appender configuration at runtime! What it all boiled down to became surprisingly succinct when some Mockito magic was applied. In fact only four code lines (ignoring imports, and other noise) bought me the capability to make assertions about the logging behavior of the code under test!

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class FooTest {
	private Appender appenderMock;
	@Before
	public void setupAppender() {
		appenderMock = mock(Appender.class);
		Logger.getRootLogger().addAppender(appenderMock);
	}
	@After
	public void removeAppender() {
		Logger.getRootLogger().removeAppender(appenderMock);
	}
	@Test
	public void testMethod()  {
		doStuffThatCausesLogging();
		verify(appenderMock).doAppend((LoggingEvent) anyObject());
	}
}

Using Mockito’s handy ArgumentCaptor class it’s dead simple to make stronger assertions, with regard to for instance the level the message was logged at:

		ArgumentCaptor arguments = ArgumentCaptor.forClass(LoggingEvent.class);
		verify(appenderMock).doAppend(arguments.capture());
		assertThat(arguments.getValue().getLevel(), is(Level.WARN));

Ergo – I have no longer any excuse for settling for anything less than comprehensive unit tests, adding tests for logging is actually quite trivial using modern tools!