17

My goal is to overlay a standard UIKit view (for the moment, I'm just creating a UILabel but eventually I'll have custom content) over a detected shape using image tracking and the Vuforia AR SDK. I have something that works, but with a "fudge" term that I cannot account for. I'd like to understand where my error is, so I can either justify the existence of this correction or use a different algorithm that's known to be valid.

My project is based on the ImageTargets sample project in the Vuforia SDK. Where their EAGLView iterates over the results to render the OpenGL teapots, I've replaced this with a call out to my ObjC++ class TrackableObjectController. For each trackable result, it does this:

- (void)augmentedRealityView:(EAGLView *)view foundTrackableResult:(const QCAR::TrackableResult *)trackableResult
{
    // find out where the target is in Core Animation space
    const QCAR::ImageTarget* imageTarget = static_cast<const QCAR::ImageTarget*>(&(trackableResult->getTrackable()));
    TrackableObject *trackable = [self trackableForName: TrackableName(imageTarget)];
    trackable.tracked = YES;
    QCAR::Vec2F size = imageTarget->getSize();
    QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(trackableResult->getPose());
    CGFloat ScreenScale = [[UIScreen mainScreen] scale];
    float xscl = qUtils.viewport.sizeX/ScreenScale/2;
    float yscl = qUtils.viewport.sizeY/ScreenScale/2;
    QCAR::Matrix44F projectedTransform = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    QCAR::Matrix44F qcarTransform = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
    /* this sizeFudge constant is here to put the label in the correct place in this demo; I had thought that
     * the problem was related to the units used (I defined the length of the target in mm in the Target Manager;
     * the fact that I've got to multiply by ten here could be indicative of the app interpreting length in cm).
     * That turned out not to be the case, when I changed the reported length of the target it stopped drawing the
     * label at the correct size. Currently, therefore, the app and the target database are both using mm, but
     * there's the following empirically-divised fudge factor to get the app to position the correctly-sized view
     * in the correct position relative to the detected object.
     */
    const double sizeFudge = 10.0;
    ShaderUtils::translatePoseMatrix(sizeFudge * size.data[0] / 2, sizeFudge * size.data[1] / 2, 0, projectedTransform.data);
    ShaderUtils::scalePoseMatrix(xscl, -yscl, 1.0, projectedTransform.data); // flip along y axis
    ShaderUtils::multiplyMatrix(projectedTransform.data, qUtils.projectionMatrix.data, qcarTransform.data);
    ShaderUtils::multiplyMatrix(qcarTransform.data, modelViewMatrix.data, qcarTransform.data);
    CATransform3D transform = *((CATransform3D*)qcarTransform.data); // both are array[16] of float
    transform = CATransform3DScale(transform,1,-1,0); //needs flipping to draw
    trackable.transform = transform;
}

There is then other code, called on the main thread, that looks at my TrackableObject instances, applies the computed CATransform3D to the overlay view's layer and sets the overlay view as a subview of the EAGLView.

My problem is, as the comment in the code sample has given away, with this sizeFudge factor. Apart from this factor, the code I have does the same thing as this answer; but that's putting my view in the wrong place.

Empirically I find that if I do not include the sizeFudge term, then my overlay view tracks the orientation and translation of the tracked object well but is offset down and to the right on the iPad screen—this is a translation difference, so it makes sense that changing the term used for . I first thought that the problem was the size of the object as specified in Vuforia's Target Manager. This turns out not to be the case; if I create a target ten times the size then the overlay view is drawn in the same, incorrect place but ten times smaller (as the AR assumes the object it's tracking is further away, I suppose).

It's only translating the pose here that gets me where I want to be, but this is unsatisfactory as it doesn't make any sense to me. Can anyone please explain the correct way to translate from a OpenGL coordinates as supplied by Vuforia to a CATransform3D that doesn't rely on magic numbers?

** Some more data **

The problem is more complicated than I thought when I wrote this question. The location of the label actually seems to depend on the distance from the iPad to the tracked object, though not linearly. There's also an apparent systematic error.

Here's a chart constructed by moving the iPad to a certain distance away from the target (located over the black square), and marking with a pen where the centre of the view appeared. Points above and to the left of the square have the translation fudge as described above, points below and to the right have sizeFudge==0. Hopefully the relationship between distance and offset shown here clue someone with more knowledge of 3D graphics than me into what the problem with the transform is.

Chart as described in the previous paragraph.

Community
  • 1
  • 1
  • 1
    What's the coordinate system used for their OpenGL ES view? Normally, OpenGL ES scenes are set up with coordinates that go from -1 to 1, rather than the 0 to [width] or [height] of UIKit coordinates. I could see needing a translation to account for that. If they were using a coordinate system that ranged from -10 to 10, that might explain your translation fudge factor. – Brad Larson Feb 18 '13 at 20:19
  • Thanks for the insight @BradLarson. I'm not sure how I'd find this coordinate system; I can't currently see where the project sets a frustum or other camera projection. I also get the feeling that this is unrelated, because the _view's_ coordinate system would be two-dimensional in the plane of the view, wouldn't it? –  Feb 19 '13 at 10:24
  • 1
    It looks like these guys might have the answer for you or at least some helpful pointers: http://stackoverflow.com/questions/6045502/how-to-get-catransform3d-from-projection-and-modelview-matricesModelView-matrices – cb88 Mar 04 '13 at 19:14
  • @cb88 that's the question I linked to in this question; the one where I'm doing the same thing but not getting the expected result. –  Mar 04 '13 at 21:42
  • What's the size of the tracking view? What happens if you set `trackingView.center = CGPointZero`? – tc. Mar 09 '13 at 01:21

1 Answers1

1

It's probably to do with the setup of your views in the first place. A strange offset could be caused by the width and height being the wrong way around or any other possible incorrect values like using an iPhone screen-ratio on an iPad.

Is your app landscape? If so then give it a go in portrait. I've noticed in the past that apps always seem to launch with portrait screen dimensions (I haven't confirmed this though) so if your view setup happens before the screen is the 'right way' around you'll get a mismatch.

You might also try working out exactly how much it's off by. Instead of multiplying size.data as a hack: add another translation and tweak the numbers till it's right. Those numbers might give you some better insight into what's happening. *10 is probably just pure fluke and doesn't mean anything much.

Wex
  • 4,434
  • 3
  • 33
  • 47
  • That sounds like a promising route to go down, thanks. I've seen other problems in the app due to portrait/landscape orientation so I'll look into that. –  Mar 18 '13 at 11:40
  • It appears to me that there's definitely a _different_ off-by-some error in different orientations, which might be a clue. It's not the whole thing, as everything appears in (a different) wrong place in the portrait orientation too. I've found that the amount off varies with distance from the target, so it looks like a general problem with the matrix transform. –  Mar 19 '13 at 15:54