Mobile UI Experiences

Tag: mobile

Augmented Reality - I

by raimon on Jul.26, 2010, under Augmented Reality

Since I had my first android phone I got curiosity into augmented reality. I have to say, compared to j2me, android is a lot more powerful and you get surprised about how easy is to achieve some things than in j2me are near impossible or rather complicated. Also seems that AR is some kind of teenager fashion, now it’s really cool to do things in AR instead of just showing a map with POIs. Let’s have the POIs floating around the user, even if it’s more confusing than showing a map, but, hey! it’s cooler.

Anyway, I had to try it by myself, otherwise I couldn’t apply the cliché of having an android phone and did some AR tests. I’ll introduce the engine I developed with different articles, explaining few parts of it, and if anyone is interested I can provide access to the svn server where the code is stored (send me an email to raimon.rafols [a] gmail.com). You can use this code for any non-commercial project you want but you need the written permission of the author for commercial usage.

One of the basic parts needed for an AR engine is to know the exact location and orientation of the device. Otherwise it won’t be possible to show the correct POIs and in the correct position in the screen. Here is a code snippet of the orientation provider.

  1. package com.fuzzion.argine.hal.android;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5. import java.util.List;
  6.  
  7. import android.app.Activity;
  8. import android.content.Context;
  9. import android.hardware.Sensor;
  10. import android.hardware.SensorEvent;
  11. import android.hardware.SensorEventListener;
  12. import android.hardware.SensorManager;
  13. import android.util.Log;
  14.  
  15. import com.fuzzion.argine.engine.OrientationListener;
  16. import com.fuzzion.argine.hal.OrientationProvider;
  17.  
  18. public class AndroidOrientationProvider implements OrientationProvider, SensorEventListener {
  19.         private SensorManager sManager;
  20.         private List<OrientationListener> listeners;
  21.        
  22.         public AndroidOrientationProvider() {
  23.                 listeners = Collections.synchronizedList(new ArrayList<OrientationListener>());
  24.         }
  25.        
  26.         @Override
  27.         public void onAccuracyChanged(Sensor sensor, int accuracy) {}
  28.  
  29.         @Override
  30.         public void onSensorChanged(SensorEvent event) {
  31.                 float values[] = event.values;
  32.                
  33.                 switch(event.sensor.getType()) {
  34.                 case Sensor.TYPE_ACCELEROMETER:
  35.                         break;
  36.                
  37.                 case Sensor.TYPE_ORIENTATION:
  38.                         for(OrientationListener listener : listeners) {
  39.                                 listener.directionChanged(values);
  40.                         }              
  41.                         break;
  42.                 }              
  43.         }
  44.        
  45.         @Override
  46.         public void registerOrientationListener(OrientationListener listener) {
  47.                 listeners.add(listener);
  48.         }
  49.  
  50.         @Override
  51.         public void removeOrientationListener(OrientationListener listener) {
  52.                 listeners.remove(listener);
  53.         }
  54.        
  55.        
  56.         public void start() {
  57.                 Activity act = AndroidPlatform.getActivity();
  58.                
  59.                 sManager = (SensorManager) act.getSystemService(Context.SENSOR_SERVICE);
  60.                 sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_FASTEST);
  61.         }
  62.        
  63.         public void stop() {
  64.                 if(sManager != null) {
  65.                         sManager.unregisterListener(this);
  66.                 }
  67.         }
  68. }

In the next entry I’ll explain the integration of all the parts (camera, orientation and position). Meanwhile you can check the code in svn.

Comments Off :, more...

Image Rotation in j2me

by raimon on Aug.26, 2009, under j2me

Lately I’ve been creating some low level image functions for Java ME just to see if low level bitmap manipulation was way too slow for doing it on real time on Java ME or it was, at least, usable. I’ll publish more functions but I’ll start with Image Rotation.

In Java ME is easy to rotate images if you want to rotate by an angle multiple of 90° but it doesn’t provide any mechanism to rotate it by an arbitrary angle (yes, ok… you could do the same using the Mobile 3D API)

I created a small function that fills that gap and allows image rotation by any angle. The resulting image will have the same size as the original (watch out for the corners..)

  1. public static void rotateImage(Image src, float angle, Graphics g) {
  2.     int sw = src.getWidth();
  3.     int sh = src.getHeight();
  4.     int[] srcData = new int[sw * sh];
  5.  
  6.     src.getRGB(srcData, 0, sw, 0, 0, sw, sh);
  7.     int[] dstData = new int[sw * sh];
  8.  
  9.     double rads = angle * Math.PI / 180.f;
  10.     float sa = (float) Math.sin(rads);
  11.     float ca = (float) Math.cos(rads);
  12.     int isa = (int) (256 * sa);
  13.     int ica = (int) (256 * ca);
  14.  
  15.     int my = - (sh >> 1);
  16.     for(int i = 0; i < sh; i++) {
  17.         int mx = - (sw  >> 1);
  18.         for(int j = 0; j < sw; j++) {
  19.             int srcx = ( mx * ica + my * isa) >> 8;
  20.             int srcy = (-mx * isa + my * ica) >> 8;
  21.  
  22.             srcx += sw >> 1;
  23.             srcy += sh >> 1;
  24.  
  25.             if(srcx < 0) srcx = 0;
  26.             if(srcy < 0) srcy = 0;
  27.             if(srcx > sw - 1) srcx = sw - 1;
  28.             if(srcy > sh - 1) srcy = sh - 1;
  29.  
  30.             dstData[j + i * sw] = srcData[srcx + srcy * sw];
  31.  
  32.             mx++;
  33.         }
  34.         my++;
  35.     }
  36.  
  37.     g.drawRGB(dstData, 0, sw, 0, 0, sw, sh, true);
  38. }

If we move all the calculations that doesn’t need to be done in the inner loop to the external loop we will have a speed improvement:

  1. public static void rotateImage(Image src, float angle, Graphics g) {
  2.     int sw = src.getWidth();
  3.     int sh = src.getHeight();
  4.     int[] srcData = new int[sw * sh];
  5.  
  6.     src.getRGB(srcData, 0, sw, 0, 0, sw, sh);
  7.     int[] dstData = new int[sw * sh];
  8.  
  9.     double rads = angle * Math.PI / 180.f;
  10.     float sa = (float) Math.sin(rads);
  11.     float ca = (float) Math.cos(rads);
  12.     int isa = (int) (256 * sa);
  13.     int ica = (int) (256 * ca);
  14.  
  15.     int my = - (sh >> 1);
  16.     for(int i = 0; i < sh; i++) {
  17.         int wpos = i * sw;
  18.  
  19.         int xacc = my * isa - (sw >> 1) * ica + ((sw >> 1) << 8);
  20.         int yacc = my * ica + (sw >> 1) * isa + ((sh >> 1) << 8);
  21.  
  22.         for(int j = 0; j < sw; j++) {
  23.             int srcx = (xacc >> 8);
  24.             int srcy = (yacc >> 8);
  25.  
  26.             if(srcx < 0) srcx = 0;
  27.             if(srcy < 0) srcy = 0;
  28.             if(srcx > sw - 1) srcx = sw - 1;
  29.             if(srcy > sh - 1) srcy = sh - 1;
  30.  
  31.             dstData[wpos++] = srcData[srcx + srcy * sw];
  32.  
  33.             xacc += ica;
  34.             yacc -= isa;
  35.         }
  36.         my++;
  37.     }
  38.  
  39.     g.drawRGB(dstData, 0, sw, 0, 0, sw, sh, true);
  40. }

And if we know beforehand the size of the image we want to rotate we could do some extra tricks (for example, here assumes the source image will be 256×256 pixels and will only work with that resolution):

  1. public static void rotateImage(Image src, float angle, Graphics g) {
  2.     int sw = src.getWidth();
  3.     int sh = src.getHeight();
  4.     int[] srcData = new int[sw * sh];
  5.  
  6.     src.getRGB(srcData, 0, sw, 0, 0, sw, sh);
  7.     int[] dstData = new int[sw * sh];
  8.  
  9.     double rads = angle * Math.PI / 180.f;
  10.     float sa = (float) Math.sin(rads);
  11.     float ca = (float) Math.cos(rads);
  12.     int isa = (int) (256 * sa);
  13.     int ica = (int) (256 * ca);
  14.  
  15.     int my = - (sh >> 1);
  16.     for(int i = 0; i < sh; i++) {
  17.         int wpos = i * sw;
  18.  
  19.         int xacc = my * isa - (sw >> 1) * ica + ((sw >> 1) << 8);
  20.         int yacc = my * ica + (sw >> 1) * isa + ((sh >> 1) << 8);
  21.  
  22.         for(int j = 0; j < sw; j++) {
  23.             int srcx = (xacc >> 8) & 0xff;
  24.             int srcy = yacc & 0xff00;
  25.  
  26.             dstData[wpos++] = srcData[srcx + srcy];
  27.  
  28.             xacc += ica;
  29.             yacc -= isa;
  30.         }
  31.         my++;
  32.     }
  33.  
  34.     g.drawRGB(dstData, 0, sw, 0, 0, sw, sh, true);
  35. }

These functions paints the rotated image in a Graphics object directly, but doing some minor changes it could generate a new Image with the content:
* Change the function declaration to:

  1. public static Image rotateImage_img(Image src, float angle) {

* Replace the drawRGB call with:

  1. return Image.createRGBImage(dstData, sw, sh, true);

Feel free to use it for whatever you want but it would be nice if you drop me a line and put me somewhere in the credits :)

4 Comments :, , more...

Service2Media is hiring…

by raimon on Jan.16, 2009, under service2media

Interested in coming to the Netherlands? :)
Go to the jobs section of Service2Media.

Comments Off :, more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Links!

    Archives

    All entries, chronologically...