Symbian Multimarker Tracking Library
#augmentedreality
Demo-version of binary Symbian multimarker tracking library SMMT available for download.
SMMT library is a SLAM multimarker tracker for Symbian. Library can work on Symbian S60 9.1 devices like Nokia N73 and Symbian 9.2 like Nokia N95, N82. It may also work on some other later versions. This version support only landscape 320×240 resolution for algorithmical reason – size used in the optimization.
This is slightly more advanced version of the tracker used in AR Tower Defense game.
PS corrupted file fixed
Augmented reality on S60 – basics
Blair MacIntyre asked on ARForum how to get video out of the Symbian Image data structre and upload it into OpenGL ES texture. So here how I did for my games:
I get viewfinder RGB bitmap, access it’s rgb data and use glTextureImage2D to upload it into background texture, which I stretch on the background rectangle. On top of the background rectangle I draw 3d models.
This code snipped for 320×240 screen and OpenGL ES 1+ (wordpress completly screwed tabs)
PS Here is binary static library for multimarker tracking for S60 which use that method.
#define VFWIDTH 320
#define VFHEIGHT 240
Two textures used for background, because texture size should be 2^n: 256×256 and 256×64
#define BKG_TXT_SIZEY0 256
#define BKG_TXT_SIZEY1 64
Nokia camera example could be used the as the base.
1. Overwrite ViewFinderFrameReady function
void CCameraCaptureEngine::ViewFinderFrameReady(CFbsBitmap& aFrame)
{
iController->ProcessFrame(&aFrame);
}
2. iController->ProcessFrame call CCameraAppBaseContaine->ProcessFrame
void CCameraAppBaseContainer::ProcessFrame(CFbsBitmap* pFrame)
{
// here RGB buffer for background is filled
iGLEngine->FillRGBBuffer(pFrame);
//and greyscale buffer for tracking is filled
iTracker->FillGreyBuffer(pFrame);
//traking
TBool aCaptureSuccess = iTracker->Capture();
//physics
if(aCaptureSuccess)
{
iPhEngine->Tick();
}
//rendering
glClear( GL_DEPTH_BUFFER_BIT);
iGLEngine->SetViewMatrix(iTracker->iViewMatrix);
iGLEngine->Render();
iGLEngine->Swap();
};
void CGLengine::Swap()
{
eglSwapBuffers( m_display, m_surface);
};
3. now how buffers filled: RGB buffers filled ind binded to textures
inline unsigned int byte_swap(unsigned int v) { return (v<<16) | (v&0xff00) | ((v >> 16)&0xff); }
void CGLengine::FillRGBBuffer(CFbsBitmap* pFrame)
{
pFrame->LockHeap(ETrue);
unsigned int* ptr_vf = (unsigned int*)pFrame->DataAddress();
FillBkgTxt(ptr_vf);
pFrame->UnlockHeap(ETrue); // unlock global heap
BindRGBBuffer(m_bkgTxtID0, m_rgbxBuffer0, BKG_TXT_SIZEY0);
BindRGBBuffer(m_bkgTxtID1, m_rgbxBuffer1, BKG_TXT_SIZEY1);
}
void CGLengine::FillBkgTxt(unsigned int* ptr_vf)
{
unsigned int* ptr_dst0 = m_rgbxBuffer0 +
(BKG_TXT_SIZEY0-VFHEIGHT)*BKG_TXT_SIZEY0;
unsigned int* ptr_dst1 = m_rgbxBuffer1 +
(BKG_TXT_SIZEY0-VFHEIGHT)*BKG_TXT_SIZEY1;
for(int j =0; j < VFHEIGHT; j++)
for(int i =0; i < BKG_TXT_SIZEY0; i++)
{
ptr_dst0[i + j*BKG_TXT_SIZEY0] = byte_swap(ptr_vf[i + j*VFWIDTH]);
}
ptr_vf += BKG_TXT_SIZEY0;
for(int j =0; j < VFHEIGHT; j++)
for(int i =0; i < BKG_TXT_SIZEY1; i++)
{
ptr_dst1[i + j*BKG_TXT_SIZEY1] = byte_swap(ptr_vf[i + j*VFWIDTH]);
}
}
void CGLengine::BindRGBBuffer(TInt aTxtID, GLvoid* aPtr, TInt aYSize)
{
glBindTexture( GL_TEXTURE_2D, aTxtID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, aYSize, BKG_TXT_SIZEY0, 0,
GL_RGBA, GL_UNSIGNED_BYTE, aPtr);
}
4. Greysacle buffer filled, smoothed by integral image :
void CTracker::FillGreyBuffer(CFbsBitmap* pFrame)
{
pFrame->LockHeap(ETrue);
unsigned int* ptr = (unsigned int*)pFrame->DataAddress();
if(m_bIntegralImg)
{
// calculate integral image values
unsigned int rs = 0;
for(int j=0; j < VFWIDTH; j++)
{
// cumulative row sum
rs = rs+ Raw2Grey(ptr[j]);
m_integral[j] = rs;
}
for(int i=1; i< VFHEIGHT; i++)
{
unsigned int rs = 0;
for(int j=0; j = VFWIDTH)
{
m_integral[i*VFWIDTH+j] = m_integral[(i-1)*VFWIDTH+j]+rs;
}
}
}
iRectData.iData[0] = m_integral[1*VFWIDTH+1]>>2;
int aX, aY;
for(aY = 1; aY >2;
iRectData.iData[MAX_SIZE_X-1 + aY*MAX_SIZE_X] = Area(2*MAX_SIZE_X-2, 2*aY, 2, 2)>>2;
}
for(aX = 1; aX >2;
iRectData.iData[aX + (MAX_SIZE_Y-1)*MAX_SIZE_X] = Area(2*aX, 2*MAX_SIZE_Y-2, 2, 2)>>2;
}
for(aY = 1; aY < MAX_SIZE_Y-1; aY++)
for(aX = 1; aX >4;
}
}
else
{
if(V2RX == 2 && V2RY ==2)
for(int j =0; j < MAX_SIZE_Y; j++)
for(int i =0; i >2;
}
else
for(int j =0; j < MAX_SIZE_Y; j++)
for(int i =0; i UnlockHeap(ETrue); // unlock global heap
}
Background could be rendered like this
#define GLUNITY (1<<16)
static const TInt quadTextureCoords[4 * 2] =
{
0, GLUNITY,
0, 0,
GLUNITY, 0,
GLUNITY, GLUNITY
};
static const GLubyte quadTriangles[2 * 3] =
{
0,1,2,
0,2,3
};
static const GLfloat quadVertices0[4 * 3] =
{
0, 0, 0,
0, BKG_TXT_SIZEY0, 0,
BKG_TXT_SIZEY0, BKG_TXT_SIZEY0, 0,
BKG_TXT_SIZEY0, 0, 0
};
static const GLfloat quadVertices1[4 * 3] =
{
BKG_TXT_SIZEY0, 0, 0,
BKG_TXT_SIZEY0, BKG_TXT_SIZEY0, 0,
BKG_TXT_SIZEY0+BKG_TXT_SIZEY1, BKG_TXT_SIZEY0, 0,
BKG_TXT_SIZEY0+BKG_TXT_SIZEY1, 0, 0
};
void CGLengine::RenderBkgQuad()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, VFWIDTH, 0, VFHEIGHT, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, VFWIDTH, VFHEIGHT);
glClear( GL_DEPTH_BUFFER_BIT);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glColor4x(GLUNITY, GLUNITY, GLUNITY, GLUNITY);
glBindTexture( GL_TEXTURE_2D, m_bkgTxtID0);
glVertexPointer( 3, GL_FLOAT, 0, quadVertices0 );
glTexCoordPointer( 2, GL_FIXED, 0, quadTextureCoords );
glDrawElements( GL_TRIANGLES, 2 * 3, GL_UNSIGNED_BYTE, quadTriangles );
glBindTexture( GL_TEXTURE_2D, m_bkgTxtID1);
glVertexPointer( 3, GL_FLOAT, 0, quadVertices1 );
glTexCoordPointer( 2, GL_FIXED, 0, quadTextureCoords );
glDrawElements( GL_TRIANGLES, 2 * 3, GL_UNSIGNED_BYTE, quadTriangles );
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glEnable(GL_ALPHA_TEST);
}
Why 3d markerless tracking is difficult for mobile augmented reality
I often hear sentiments from users that they don’t like markers, and they are wondering, why there are so relatively few markerless AR around. First I want to say that there is no excuse for using markers in the static scene with immobile camera, or if desktop computer is used. Brute force methods for tracking like bundle adjustment and fundamental matrix are well developed and used for years and years in the computer vision and photogrammetry. However those methods in their original form could hardly produce acceptable frame rate on the mobile devices. From the other hand marker trackers on mobile devices could be made fast, stable and robust.
So why markers are easy and markerless are not ?
The problem is the structure , or “shape” of the points cloud generated by feature detector of the markerless tracker. The problem with structure is that depth coordinate of the points is not easily calculated. That is even more difficult because camera frame taken from mobile device have narrow baseline – frames taken form position close one to another, so “stereo” depth perception is quite rough. It is called structure from motion problem.
In the case of the marker tracker all feature points of the markers are on the same plane, and that allow to calculate position of the camera (up to constant scale factor) from the single frame. Essentially, if all the points produced by detector are on the same plane, like for example from the pictures lying on the table, the problem of structure from motion goes away. Planar cloud of point is essentially the same as the set of markers – for example any four points could be considered as marker and the same algorithm could apply. Structure from motion problem is why there is no easy step from “planar only” tracker to real 3d markerless tracker.
However not everything is so bad for mobile markerless tracker. If tracking environment is indoor, or cityscape there is a lot of rectangles, parallel lines and other planar structures around. Those could be used as initial approximation for one the of structure from motion algorithm, or/and as substitutes for markers.
Another approach of cause is to find some variation of structure from motion method which is fast and works for mobile. Some variation of bundle adjustment algorithm looks most promising to me.
PS PTAM tracker, which is ported to iPhone, use yet another approach – instead of using bundle adjustment for each frame, bundle adjustment is running in the separate thread asynchronously, and more simple method used for frame to frame tracking.
Nintendo DSi and Augmented Reality revisited
Returning to my old post about DSi and AR, it’s known now that main DSi CPU is 132 Mhz. That is marginally acceptable for markers based AR games. What kind of performance can be achieved for DSi ?
Here is my old Nokia 6600 demo which run at 107Mhz CPU phone. With DSi 133Mhz CPU+second 33Mhz CPU I’d estimate the same game can run on DSi at 8-10 fps. That’s is not a stellar, but nevertheless playable frame rate. Could be faster with some aggressive optimization or simplifications.
New version of Augmented Reality Tower Defense
A new version of AR Tower Defense – v0.03 Some bugs fixed (black screen bug)
and minor tracking improvement
Fullscreen version of AR Tower defense is up for download
AR Tower Defense is fullscreen now. I ‘ve also changed default mode from portrait to landscape.
Marker-based AR application and games could be viable.
Blair MacIntyre written in his blog that he consider markers for AR to be a “prop”: “As soon as your start requiring props, that makes the games less portable … a conundrum to be sure.” Whoever it could be that marker-based AR games/app are not actually so bad.
Edge report that “79 percent [of those polled say] they use their portable device in-home, far more than any other location.”
The interesting thing that in-door marker-based tracking have no disadvantages comparing with markerless. Markers could be easily placed on any flat surface, or taped/pinned to vertical surface. Most of surfaces are at the right angles, so one can even make easy to track non-planar multimaker arrangement – like putting markers both on the table and the adjacent wall. In some cases, like on smooth uniform surfaces only marker-based tracker can actually work, markerless would just fail there. Of cause markereless tracking is more scientifically impressive and fun to develop, but marker-based works right now )))
From business point of view marker based apps and games can provide interesting opportunity – non-intrusive mobile advertising. Instead of pushing ad into the face of the user, on the screen, occupying precious screen real estate, ad or logo can be put on the marker itself. That way it remain both highly visible and non-annoying. Different ad bearing markers could be keyed to different content units, thus providing ads rotation.
Augmented Reality Tower Defense game is up for download
It’s here. In this demo I’ve used the same multimarker tracker I’ve used in last demos. 3d position of the camera calculated form markers used for placing tower. Third dimension used to control tower height
If you don’t know what Tower Defense is, here is wiki entry
Marker based augmented reality on CNN
Net is buzzing about CNN hologram at election night. What this tech really is the augmented reality + 3D imaging technology. CNN had 35 cameras in a ring at Obama headquarter to capture Jessica Yellin image from any possible 2D direction, with angle delta small enough not to be noticeable. After correct frame was picked up it was inserted into main videoframe. It seems to me the red circle on the floor was used for positioning of the image, as fiduciary marker. If you pay attention to the last part of the video you can see that Jessica “float” a little over the circle. That is because the circle is not the best choice for the marker. Square is probably the best fiduciary marker possible. It have distinctive corner, which could have subpixel accuracy, because they calculated as intersection of linearized square sides, and it produce third dimension axis easily, as cross product of cross products its sides.
Phone camera as 3d pointing device
Here is a short video how phone camera could be used as precise enough 3d pointer.
This demo use the same engine as my first demo.