Symbian Multimarker Tracking Library updated
Symbian Multimarker Tracking Library updated to v0.5. Some bugs fixed, markers can be moved run-time now. Download is here
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);
}
The Register article mention AR Tower Defense
The Register article on Augmented Reality make a mention of AR Tower Defense.
PS. In relation to this article, if smartphone need better display for AR – what mobile AR device need first
Nokia announces Ovi Application store
Nokia announces Ovi Application store
for Flash, Java applications and other(?) content. Symbian apps are not mentioned explicitly, but presumably they will be available too. The developer or content provider would get 70% revenue share. Not much known about the store and policy yet. On the publisher site there is a form for e-mail and content submission for Nokia consideration. No online registration for publishers available yet.
PS. Symbian applications will be accepted, confirmed by Nokia.
No self-signed application allowed in the store.
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
Nokia released cleaner for the “Curse of Silence”
Nokia released tool for FP1 phones, cleaning the “Curse of Silence” exploit form the phones.
Still no high-performance Symbian device…
Just checked GLBenchmarks for Samsung INNOV8.
Samsung GT-i8510 Innov8 performance details:
High-level 3D Performance
GLBenchmark HD ES 1.0 : 1602 Frames
GLBenchmark HD ES 1.1 : 628 Frames
GLBenchmark Pro ES 1.0 : 328 Frames
GLBenchmark Pro ES 1.1 : 35 Frames
CPU Performance
CPU Performance: Float : 988
CPU Performance: Integer : 4183
For comparison –
Nokia N95 8GB performance details:
High-level 3D Performance
GLBenchmark HD ES 1.0 : 1944 Frames
GLBenchmark HD ES 1.1 : 1766 Frames
GLBenchmark Pro ES 1.0 : 395 Frames
GLBenchmark Pro ES 1.1 : 570 Frames
CPU Performance
CPU Performance: Float : 1411
CPU Performance: Integer : 4254
Old Nokia N95(8Gb) still beat best of newish Symbian devices hands down.
Other platforms had 600+ Mhz devices long time ago, Palm switched to new generation CPU – OMAP3430. After two years no one still able to produce better high-performance Symbian device ?
Detachable magnetic lens for mobile phone
Interesting accessory – detachable lens which can be attached to any mobile phone. If phone camera is not magnetic enough there in adhesive magnetic ring to glue to the phone. (through smartmobile twitter)
Markerless tracking
I’ve started experimenting with markerless tracking. I’ve captured several cityscape image sequences and processed them with SURF detector. I’ve used Nokia N95 viewfinder frames. Here descriptors were oriented:
There are some corresponding features detected in both images, but their descriptors arn’t fit.
Interesting, upright, not oriented descriptors give little different picture – some new correspondences found, some lost.