By: Frank Rysanek of FCC prumyslove systemy s.r.o. [rysanek (AT) fccps.cz]
This leading chapter is a shortcut. Download right here:
matrix.pl v1.0 = the original release by Frank Rysanek (orthogonal approximation)
matrix.pl v1.1 = an update with extensions by Petr Mikse [mikse AT seznam DOT cz] (including support for rotation and more)
Apart from this Perl script, you'll need the original xinput_calibrator (such as the Debian 9 standard package xinput-calibrator) and some common X cmdline tools, namely
xinput (from xinput.deb)
xrandr (from x11-xserver-utils.deb).
As many of you out there may be aware, touchscreen calibration in X-Windows
has always been a neglected child. During the last decade or so,
I seem to recall three or four different generic calibration tools for X-Windows:
It's making me wonder. X.org is such a hugely successful project.
It has defined internal standard layers and interfaces for input
device coordinate processing and calibration. And, the X.org team
do not provide a generic calibrator at the same time?
I mean - it's understandable that there's progress in the internals, and the interfaces inevitably develop in time, but what's the point if there are no calibration tools in the same box?
Kudos to the independent authors of the three (four) projects.
An obvious response might be "Oh, calibration? Where have you been
during the last decade? Projected Capacitive touchscreens with the
HID interface are all the rage now, and they come calibrated
for the native display resolution.
Oh you have some odd industrial touchscreen that needs to be
calibrated? Come on, that's ghetto hardware you have there.
Get something decent."
And that's a fine argument :-) except that in my "industrial" niche, the vendors tend to sell all sorts of different TS sensors and controllers, given by the fact that PCap unfortunately doesn't fit all the uses. $DEITY bless Linux for having vanilla drivers for all the TS controller brands out there - but, the one missing bit is a reliable and up to date vanilla calibrator in X. I need a calibrator in Linux maybe once in two years and it's always a different buggy story.
Okay I'm getting to the point now :-)
As of the time of this writing (early June 2018),
the xtcal seems pretty promising.
It purports to use an algorithm based on "least squares" to derive the "best fit model", which it then turns into the desired "coordinate transformation matrix".
Except that the result wasn't flawless on my hardware.
Xtcal compiled just fine on the build machine, I turned it
into a quick and dirty .deb package (amd64)
for the target box, it installed without a hitch, it ran just fine...
But the result is off. No matter how hard I try to touch the precise center of the crosshair marks, and avoid bias on my part due to angle of view, the resulting alignment (matrix) seems to suffer from a small rotational error - like 5 degrees up on the right side.
Based on what xinput_calibrator says, my X axis is mirrored, but that shouldn't matter to a generic calibration algorithm.
This might be a minor bug in the xtcal. I haven't reported the bug yet - I will revise this text if xtcal gets corrected.
The math is a little over my head... See the references chapter
at the end of this text. And there's hardly any formal
documentation of the "matrix" from X.org.
I generally understand that my clicks on the crosshair marks, presented by the calibrator app, provide an approximate mapping between TS sensor coordinates and scren pixel coordinates. These have to be "fitted" by some algorithm to a shape that in theory best describes a possible "composite affine transformation" = a combination of the elementary affine transformations allowed. Note that perspective transformation is not among them (not in 2D + 1). Once the measured data makes a plausible "source image", the rest is down to some matrix math - multiplications and gaussian eliminations.
Perhaps see the math.stackexchange article for the best explanation of the algorithm.
In need of a calibration tool, I ended up writing a simple wrapper script in Perl, a wrapper around the venerable xinput_calibrator. The script uses the calibrator's "debug" output, which lists the actual (miscalibrated) touch coordinates coming from the kernel's input layer. It also finds out the screen resolution and leverages inside knowledge of the pixel positions of the crosshair marks in the xinput_calibrator's window.
The script uses a set of formulas taken from the Arch Linux Wiki "Talk" on matrix
calibration (see the references down below) to turn the axis-aligned "rectangular"
four point calibration readings into a plausible matrix.
The four points used as input are preprocessed in the script for an "average fit" axis-aligned rectangle. Thus, the matrix is based on "optimal" and sanitized four points, theory-adherent in the geometric sense, which should result in a clean calibration (no foul residues from the transform).
Example output of my calibrator script in the text console:
root@debian:~# matrix.pl Using 'xinput list' to find some pointer devices, to give you a choice: 1.) Virtual core XTEST pointer 2.) Genius Optical Mouse 3.) DIALOGUE INC PenMount USB Which device do you want to calibrate? Type a number and press <enter> 3 You chose 3 = device "DIALOGUE INC PenMount USB" Screen resolution: 1024 x 768 We'd better cancel previous calibration, by inserting a unity matrix. Launching the xinput_calibrator. Click 0 : X=818, Y=154 Click 1 : X=203, Y=149 Click 2 : X=818, Y=617 Click 3 : X=204, Y=604 Matrix = -1.24979658258747, 0, 1.12337266069976, 0, 1.25490196078431, -0.122549019607843, 0, 0, 1 Will try to apply the matrix immediately. This is still just a runtime setting. Matrix update cmd: xinput set-prop "DIALOGUE INC PenMount USB" "Coordinate Transformation Matrix" -1.24979658258747, 0, 1.12337266069976, 0, 1.25490196078431, -0.122549019607843, 0, 0, 1 By now, the input device might as well be calibrated. To check, try xinput list-props . To make the changes permanent, create or edit a file called /etc/X11/xorg.conf.d/99-calibration.conf and make it look like this (feel free to copy+paste): Section "InputClass" Identifier "calibration" MatchProduct "DIALOGUE INC PenMount USB" Option "TransformationMatrix" "-1.24979658258747 0 1.12337266069976 0 1.25490196078431 -0.122549019607843 0 0 1" EndSection
Lo and behold... the calibration seems spot on.
The matrix.pl script v1.0 doesn't support rotation.
Not even "integer multiples of 90 degrees".
At the time of writing, I gave up doing all the matrix math properly (affine transforms), and I also had the impression that supporting arbitrary rotation would result in little more than "overfitting to the human imprecision of calibration touches".
A fellow tinkerer Petr Mikse has further extended my original script.
Apart from several useability enhancements and fixes, he has done the difficult matrix math and his version supports arbitrary rotation, making full use of the X11 transformation matrix.
Apparently his solution is again distilled (at a symbolic stage) into a sequence of formulas written in plain Perl, there's no generic matrix manipulation (inversion, multiplication and whatnot) = no additional libraries/dependencies.
Effectively, the most important difference between v1.0 and v1.1
is the choice of "solution fitting algorithm":