How I fastened the speedometer to the tanks

Once I saw a video a long time ago where a man was playing some kind of car simulator and on his desk were 2 large dial indicators (voltmeters, if I’m not mistaken), which played the role of a speedometer and tachometer. A few years later I decided to repeat something similar.
I played only in World of Tanks (and I abandoned it a long time ago without having reached the 10th level), so I decided to crank everything up with the tanks. I must say right away that all development, with the exception of debugging, was done on linux, the code running on a PC is written in python. Yes, it’s slow and I’m ashamed to show the code, so we can do without it.
Speedometer
As a speedometer, I also decided to use something with an arrow, this role fell to the old, cheap, Chinese multimeter with an arrow indication.
It was decided that the speedometer would be controlled by ATMEGA16, since there was a debug board with all the necessary harnesses on board. Communication PC -> MK is organized through a serial port.
Display and MK



The firmware is primitive, the algorithm is something like this:
- In an endless loop, listen to USART.
- When receiving speed data, they were checked for validity and with the help of PWM, the required voltage level was set.
This was the simplest part, then it was necessary to get the speed value. 2 ideas came up right away: Get data from the game process (wool memory in the hope of finding a coveted address) or scan the value directly from the interface itself and recognize it. The last one for me was a completely dark forest and sounded interesting.
Getting the treasured speed
First we get a screenshot of the game, I naively believed that there would be no problems, but as it turned out, capturing the screen in DirectX mode is not the easiest thing, but it can be solved of course. Instead of the game interface, Malevich’s rectangles were obtained, i.e. useless images, without thinking twice, I switched to window mode and expanded the game window to full screen, the difference in information content with the full-screen mode is minimal, but the screen began to be remarkably captured.
I didn’t capture the entire screen, but a small area of 200x200 approximately pixels, I already worked with it.
Game interface screenshot and damage panel



Then I discovered for myself such a wonderful thing as OpenCV, with it I bleached the picture and inverted the colors (initially the background is dark and the numbers are bright).
Our speed is a maximum two-digit number, and in a monospaced font, which also pleased, because the bits occupied a strictly defined place and did not shift when the speed value changed. It only remained to select these 2 positions and recognize them.



Recognition
Recognition of the value I have reduced to comparison with the standard. The comparison was based on the difference in image hashes: the smaller the difference, the higher the probability that this is the exact number. I made a lot of standards of all numbers (for example, 50 pieces of the number 3 from the first and second category), captured our positions, numbered, then manually sorted into folders according to the face value. And then he compared the hash in the inside of one nominal (i.e., units with units, etc.) to find out how much the same values are very different from each other. Then he mixed in similar styles (for example, to 3 - 8) and again considered the difference. This information was key in determining accuracy. But as it turned out, there were boundary values, i.e. sometimes all the same 3 and 8 and 9 were confused, though not often, but not pleasantly. The reason for this was a translucent background and the very small size of the numbers themselves.
I had to go into the client and change the standard damage panel to the custom one, on which I doubled the font, changed the background color, and completely turned off the transparency. I conducted tests with a new panel and, as expected, the recognition accuracy increased by an order of magnitude. I also refused color inversion.
New panel and numbers











I collected all the code together, wrapped it in a loop and drove off, in principle, what came out on the video. The WoT client itself after the last update began to slow down significantly, while during lags the speedometer (in the interface) sometimes shows completely inadequate values. The work is not perfect, but I am pleased with the result.
For capture used Python Imaging Library (PIL) .
To work with the image: OpenCV .
I apologize for the rough writing, this is my first article on Habré.