Use RANSAC. Let your model be a combination of Rotation and horizontal/vertical shift.
The affine transformation would work (it has slightly more degrees of freedom but is well described).
Let A_i = [x1 y1 0 0 1 0; 0 0 x1 y1 0 1] for each point i. let b_i = [x2; y2]. That gives you A and b of dimension 2n by 6, and 2n by 1, where n is the number of points.
Then solve Ax=b for x, using Least-squares.
Your affine transformation T is then
[x1 x2 x5
x3 x4 x6
0 0 1].
x5, x6 is the shift which you don't care about. The other x1 to x4 describe the rotation matrix (caveat, if you have a bit of zoom or so, it's not purely rotation, for that normalise to make the rows orthoNormal!).
Anyway, all of this is well described. Implementation should exist in both OpenCV and Matlab.
Update
I just implemented my approach. It doesn't work. This approach sees so many Non-rotating keypoints, that the proposed affine transformation with RANSAC only finds a tiny shift. Basically, I find the Identity Matrix.
Here is an image showing the inliers identified by RANSAC.
Conclusion 1
- Method 1: Identify the arrow using matching, and determine that transformation (affine would do).
- Method 2: Disregard slight camera movement (or remove first) and use a purely rotational model.
Method 1
Crop the indicated arrow from the center of rotation all the way to the outside rim. Include the center of rotation, so that the location is known later, and the rotation around that point can be calculated.
Update on Method 1
I tried this. I tried to match the crop of the arrow from the first image to the arrows in the other images. It works often but not on all frames in the sequence. A higher resolution video without that awful GIF compression would be nice. I personally think now, that this method is the one that will give better results.
Method 2
Let the purely rotational model be that x' = R x
, where x and x' are 2D vectors and R a 2x2 rotation matrix.
We could solve this using LS just as mentioned above in the affine case. (Namely A = [x y 0 0; 0 0 x y]
) However, if x and y are in image coordinates (pixels) then the model is plain wrong as it gives rotation around the origin. Automatically determining the origin is impossible from inside the model (could be possible by doing the affine transformation first and knowing the center for the first frame and thus extrapolating for every frame).
Assuming for simplicity that the center of rotation is the same in every image. Let it be described by the vector t
. Then we just have to subtract t from x and x' before estimating the rotational model.
The implementation is actually a bit more difficult because the above wouldn't enforce I = R' R
on the rotation matrix. Read https://math.stackexchange.com/a/77466 Kabsch algorithm for more.
Update on Method 2
The problem remains that virtually non-moving points have to be classified as outliers (the three groups of points you mention in your question). I tried removing the points from the translation first, and then estimating the rotation on the rest. This did not work well.
Update 2
I pushed the code to a Github repository MatlabRotationEstimation. For further progress I think higher resolution input files are needed. It would also be interesting to know, whether you need a frame by frame rotational speed or whether some agglomerative information is sufficient.