Showing posts with label computer vision. Show all posts
Showing posts with label computer vision. Show all posts

Gramophone audio from photograph, revisited

"I am the atomic powered robot. Please give my best wishes to everybody!"

Those are the words uttered by Tommy, a childhood toy robot of mine. I've taken a look at his miniature vinyl record sound mechanism a few times before (#1, #2), in an attempt to recover the analog audio signal using only a digital camera. Results were noisy at best. The blog posts resurfaced in a recent IRC discussion which inspired me to try my luck with a slightly improved method.

Source photo

I will be using an old photo of Tommy's internal miniature record I already had from previous adventures in 2012. I don't want to perform another invasive operation on Tommy to take a new photograph, as I already broke a plastic tab last time I opened him. But it also means I don't have control over the photographing environment. It's part of the challenge.

The picture was taken with a DSLR and it's an uncompressed 8-bit color photo measuring 3000 by 3000 pixels. There's a fair amount of focus blur, chromatic aberration and similar distortions. But at this resolution, a clear pattern can be seen when zooming into the grooves.

[Image: Close-up shot of a miniature vinyl record, with a detail view of the grooves.]

This pattern superficially resembles a variable-area optical audio track seen in old film prints, and that's why I previously tried to decode it as such. But it didn't produce satisfactory results, and there is no physical reason it even should. In fact, I'm not even sure as to which physical parameter the audio is encoded in – does the needle move vertically or horizontally? How would this feature manifest itself in the photograph? Do the bright blobs represent crests in the groove, or just areas that happen to be oriented the right way in this particular lighting?

Unwrapping

To make the grooves a little easier to follow I first unwrapped the circular record into a linear image. I did this by remapping the image space from polar to 9000-wide Cartesian coordinates and then resampling it with a windowed sinc kernel:

[Image: The photo of the circular record unwrapped into a long linear strip.]

Mapping the groove path

It's not easy to automatically follow the groove. As one would imagine, it's not a mathematically perfect spiral. Sometimes the groove disappears into darkness, or blurs into the adjacent track. But it wasn't overly tedious to draw a guiding path manually. Most of the work was just copy-pasting from a previous groove and making small adjustments.

I opened the unwrapped image in Inkscape and drew a colored polyline over all obvious grooves. I tried to make sure a polyline at the left image border would neatly continue where the previous one ended on the right side.

The grooves were alternatively labeled as 'a' and 'b', since I knew this record had two different sound effects on interleaved tracks.

[Image: A zoomed-in view of the unwrapped grooves labeled and highlighted with colored lines.]

This polyline was then exported from Inkscape and loaded by a script that extracted a 3-7 pixel high column from the unwrapped original, centered around the groove, for further processing.

Pixels to audio

I had noticed another information-carrying feature besides just the transverse area of the groove: its displacement from center. The white blobs sometimes appear below or above the imaginary center line.

[Image: Parts of a few grooves shown greatly magnified. They appear either as horizontal stripes, or horizontally organized groups of distinct blobs.]

I had my script calculate the brightness mass center (weighted y average) relative to the track polyline at all x positions along the groove. This position was then directly used as a PCM sample value, and the whole groove was written to a WAV file. A noise reduction algorithm was also applied, based on sample noise from the silent end of the groove.

The results are much better than what I previously obtained (see video below, or mp3 here):

Future ideas

Several factors limit the fidelity and dynamic range obtained by this method. For one, the relationship between the white blobs and needle movement is not known. The results could possibly still benefit from more pixel resolution and color bit depth. The blob central displacement (insofar as it is the most useful feature) could also be more accurately obtained using a Gaussian fit or similar algorithm.

The groove guide could be drawn more carefully, as some track slips can be heard in the recovered audio.

Opening up the robot for another photograph would be risky, since I already broke a plastic tab before. But other ways to optically capture the signal would be using a USB microscope or a flatbed scanner. These methods would still be only slightly more complicated that just using a microphone! The linear light source of the scanner would possibly cause problems with the circular groove. I would imagine the problem of the disappearing grooves would still be there, unless some sort of carefully controlled lighting was used.

Mapping microwave relay links from video

Radio networks are often at least partially based on microwave relay links. They're those little mushroom-like appendices growing out of cell towers and building-mounted base stations. Technically, they're carefully directed dish antennas linking such towers together over a line-of-sight connection. I'm collecting a little map of nearby link stations, trying to find out how they're interconnected and which network they belong to.

Circling around

We can find a rough direction for any link antenna by approximating a tangent for the dish shroud surface from position-stamped video footage taken while circling the tower. Optimally we would have a drone make a full circle around the tower at a constant distance and elevation to map all antennas at once; but if our DJI Phantom has run out of battery, a GPS positioned still camera at ground level will also do.

[Image: Five photos of the same directional microwave antenna, taken from different angles, and edge-detection and elliptical Hough transform results from each one, with a large and small circle for all ellipses.]

The rest can be done manually, or using Hough transform and centroid calculation from OpenCV. In these pictures, the ratio of the diameters of the concentric circles is a sinusoid function of the angle between the antenna direction and the camera direction. At its maximum, we're looking straight at the beam. (The ratio won't max out at unity in this case, because we're looking at the antenna slightly from below.) We can select the frame with the maximum ratio from high-speed footage, or we can interpolate a smooth sinusoid to get an even better value.

[Image: Diagram showing how the ratio of the diameters of the large and small circle is proportional to the angle of the antenna in relation to the camera.]

This particular antenna is pointing west-northwest with an azimuth of 290°.

What about distance?

Because of the line-of-sight requirement, we also know the maximum possible distance to the linked tower, using the formula 7140 × √(4 / 3 × h) where h is the height of the antenna from ground. If the beam happens to hit a previously mapped tower closer than this distance, we can assume they're connected!

This antenna is communicating to a tower not further away than 48 km. Judging from the building it's standing on, it belongs to a government trunked radio network.

The laser-equipped Lego train

In a previous post I was not very happy with the results of my opto-acoustic capture of the miniature gramophone record, so today I thought I'd try to illuminate the record surface more evenly.

Of course, the straightforward solution is to build a circular LEGO® railroad track around the record and have a laser-hauled train run around the track, illuminating the record surface with coherent light at a constant tangential angle, while a camera captures the image at long exposure.

[Image: A LEGO train engine chassis on a curved LEGO track, with a little laser pointer attached to it using blu-tack and cable ties. The laser is emitting red light.]

This time I didn't want to go through the trouble of positioning the high-resolution camera and only got this:

[Image: A vinyl record illuminated very unevenly with laser beams projected radially, towards the center.]

I learned that Lego is not very good for laser work in general; specifically the trains don't run very smoothly, as you can see in the above pic. Updates with audio will follow, anyway. In the meantime, here's a video.

Bonus points if you can hear what's happening in the background.

Update: I didn't post an audio update, because the audio was useless. And the whole laser thing was a dead end anyway. Instead, I edited the high-res photo I took earlier, removing the extreme shadows using Gimp's Dodge/Burn tool. Then changed my Perl code a bit so that it actually stays on track; the record turned out to contain two interleaved tracks. The result is this:

Now I can put the robot back together and close this case.

Update 7/2017: The saga continues in Gramophone audio from photograph, revisited.

The Atomic-Powered Robot

[Image: A black toy robot standing next to a My Little Pony. The robot has golden ears and arms, a speaker on its chest, and a big round button on top of its head. On its belly, it has a symbol referring to nuclear power. Text around the robot says OMNI, 024-2931:1524, and 2 MODEL-B.]

This is my mechanical baby, Tommy. He's an atomic-powered [sic] robot that can talk and walk around the room. Born in 1984, he's been with me since the early 1990s, but for the last ten years he's been quite ill and not able to talk.

Today I finally fixed him. While doing that, I decided to do a full autopsy for the sake of science, as I've found his vocal cords especially intriguing. So please observe: Tommy's internals. (As with all medical imagery, it's not for the faint of heart.)

Tommy's belly is dominated by a pink-colored contraption that looks like it has a speaker on the front. The pink device gives Tommy his ability to utter the words "I am the atomic powered robot. Please give my best wishes to everybody!" and also make the sound of a laser gun. Below the sound player is the walking motor, which is quite simple and I'm not going to concentrate on it.

[Image: The robot opened up. A bunch of wires go from inside its head down to where its feet are, where some gears can also be seen. In the middle, a big pink box with a speaker in the front.]

Removing the cover of the pink device, we see a large funnel-shaped object that looks a bit like a speaker. It has a tense plastic membrane, like a drumhead.

[Image: Inside the pink box, a peculiar speaker with a translucent membrane.]

Now it gets really interesting. The speaker is resting on a tiny gramophone arm, which is playing a little vinyl record! There's even a simple electro-mechanical end-of-disc detection and arm-return mechanism. The vibrations of the needle are mechanically transferred to the speaker membrane; there's no electric amplification of any kind.

[Image: Still inside the speaker box, a slit reveals a little vinyl record underneath. A gramophone arm and needle are resting on it. Towards the end of the disc, there's a switch that seems to close an electronic circuit when the arm moves far enough.]

Could a gramophone record get any cuter?

[Image: Close-up of the disc being held in the author's hand, removed from the box. The disc is small enough to fit on the palm.]

And here's Tommy sending you his best wishes.

UPDATE: Okay, yeah, he's cute and all. But take another look at the above photo of the record. Don't you think it contains a lot of information about the recording? Perhaps you could even extract the audio from a good enough photograph. Just a silly thought.

Well, let's get to it.

First I'll need a good quality picture of the record's surface. My roommate lended me her expensive camera for this purpose. To get the rough surface evenly exposed, I used an exposure time of 10 seconds with an aperture of f/32. I circled a lamp around the record for 10 seconds and got this cool image.

[Image: A high-resolution photograph taken tangentially towards the record. Grooves are clearly visible as darker lines, and even the recorded signal can be seen as oscillations in the grooves. The end of the record seems to be silent.]

I'll hint the positions of the groove at every turn and then let Perl interpolate a smooth spiral:

[Image: Screenshot of Inkscape with the above image loaded and markers drawn on the spiral groove wherever it crosses the pi radians mark. Next to it, a computer-generated spiral with similar spacings.]

I'm going to read the record along the spiral at 360 RPM and just convert the pixel brightness at every point of the groove into PCM amplitude. This will probably result in something audible, although quite noisy. There appears to be two interleaved grooves: one for the speech, one for the laser sound. The groove gets randomly selected when the robot's head button is pressed, depending on where the needle happens to land. So I made a stereo sound file.

It's very noisy indeed and there's a lot of crosstalk, but something can be heard in the background. After edge detection on the image and some noise removal on the audio:

Update: Further studying of the record and better sound samples in "The laser-equipped Lego train".

Character recognition, the simple way

Recently I solved a small problem and found it funny enough to write a post.

I had a PDF document with numbers in it (ones and zeros). I needed the numbers for a program, but they were embedded as a scanned picture instead of text. Copying them by hand would be boring and error-prone. I wouldn't want any typos, seeing as the numbers themselves were supposed to be part of an error-correcting code.

[Image: A big matrix of ones and zeros.]

Then I thought: perhaps Perl could do this for me! I came up with this:

#!/usr/bin/perl
use feature "switch";
 
open(S,"convert bitit.png gray:-|");
for $y (0..434) {
  for $x (0..699) {
    read(S,$a,1);
    $b[int($x / 27)][int($y / 27)] ++ if (ord($a) < 127);
  }
}
close(S);
 
for $y (0..15) {
  $byte = 0;
  for $x (0..25) {
    $byte <<= 1;
    given ($b[$x][$y] // 0) {
      when ($_ < 10) { print "  "; }
      when ($_ < 90) { print "1 "; $byte++; }
      default        { print "0 "; }
    }
  }
  printf (" 0x%07x\n",$byte);
}

Running the script produces:

$ perl bitit.pl 
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1  0x2000077
0 1                           0 1 0 1 1 1 0 0 1 1 1  0x10002e7
0   1                         0 1 1 1 0 1 0 1 1 1 1  0x08003af
0     1                       0 1 1 0 0 0 0 1 0 1 1  0x040030b
0       1                     0 1 1 0 1 0 1 1 0 0 1  0x0200359
0         1                   0 1 1 0 1 1 1 0 0 0 0  0x0100370
0           1                 0 0 1 1 0 1 1 1 0 0 0  0x00801b8
0             1               0 0 0 1 1 0 1 1 1 0 0  0x00400dc
0               1             0 0 0 0 1 1 0 1 1 1 0  0x002006e
0                 1           0 0 0 0 0 1 1 0 1 1 1  0x0010037
0                   1         0 1 0 1 1 0 0 0 1 1 1  0x00082c7
0                     1       0 1 1 1 0 1 1 1 1 1 1  0x00043bf
0                       1     0 1 1 0 0 0 0 0 0 1 1  0x0002303
0                         1   0 1 1 0 1 0 1 1 1 0 1  0x000135d
0                           1 0 1 1 0 1 1 1 0 0 1 0  0x0000b72
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 1 0 0 1  0x00005b9
$ █

How does it do that? The script divides the image — read pixel-by-pixel via ImageMagick — into squares and counts the black pixels in every square. The character "0" has obviously more black than "1"; the threshold was found by experimenting. An empty square has nearly no black pixels at all, and depicts a zero in this example. Calculating a hex value for every row is simple.

I ended up having to write only slightly more characters than the image contained! :)