Monday, February 25, 2013

C++ and pthreads on Linux

If one wants to use NDK and that is JNI on Android, sooner or later he will run into threading on Linux, yes Android is Linux. Pthreads is short for POSIX threads where POSIX is Portable Operating System Interface. Since they are portable they will work on Unix, Linux, FreeBSD, Mac and so on. Pthread is defined in pthread.h and represents set of C functions, structs and defs, to discover where it is you can execute from terminal:

$ locate pthread.h

If you have NDK installed you will see that pthread.h is part of it and that arch-arm version is significantly smaller than /usr/include/pthread.h one. To cut long story short we can do Hello World and see how it looks like:


It is quite simple, we declare thread function, thread itself and then we create thread and pass function pointer and argument in pthread_create. Later we join and exit. To compile it we do:

g++ -pthread simple.cpp -o simple

That -pthread switch is linking instruction. Now cout is not thread safe and we may want to use mutex to make printing to standard output safe.


Now one can go and wrap pthread or mutex in class and make it easier to use. Only we need to be careful with that function pointer in pthread_create, that is C function and passing class method won’t work without some additional coding and static casting.
Finally we will take a look at pthread_key_create, which is recommended by Android documentation. Its signature is:

int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));

That "destructor" should free resources taken by key when thread exits. Key itself is global variable but on thread level, sort of locally global. So here is example:


When you build it and execute it you will see that cout is not thread safe. If you want to wrap pthread in class, very good reading is Implementation and Usage of a Thread Pool based on POSIX Threads by Ronald Kriemann, sorry do not have link for it. Beside mutex, there are are condition variables and semaphores to help with concurrency issues. If you are going to fork process you may want to use System V semaphores instead of pthread semaphores. Finally for any serious implementation of pthread_key_create you need to look at pthread_once_t.

Thursday, February 21, 2013

More C++ and JNI on Linux Mint

In last JNI tutorial we learned how to compile Java code, generate header and implement and compile native code. JNI declares two main groups of commonly used types. Primitive types, which are int, boolean, float and so on, and they are user friendly, no need to do cast to native types. Other group are reference types, like String, arrays or proper Java classes, and they all inherit from jobject and require special handling to map them to native types. So here is the simple example to illustrate different parameter type handling:

public class MultiCall{
    public native int add(int a, int b);
    public native boolean isOdd(long a);
    public native int sum(int[] arr);
    public native String add(String a, String b);
    static
    {
        System.loadLibrary("MultiCall");
    }
    public static void main(String[] args)
    {
        MultiCall m = new MultiCall();
        System.out.println(m.add(1, 2));
        System.out.println(m.add("Hello", "World"));
        System.out.println(m.sum(new int[]{1,2,3,4}));
        System.out.println(m.isOdd(6L));
    }
}


After we compile it and run javah tool on resulting class, we have the following method definitions:


Implementation looks like this:


Reference types require significant work to use them from native code. Also if we want to return reference type it needs to be constructed. I am using std::string because it will do deep copy of character array, at least if you are using gcc/g++, and allows me to easily manipulate strings. Code is easy to understand and doesn’t deserve further comments.
The second example is illustration how to throw exception from native code and catch it in Java code.

public class NativeException{
    public native int divide(int a, int b) throws IllegalArgumentException;
    static
    {
        System.loadLibrary("NativeException");
    }
    public static void main(String[] args)
    {
        NativeException n = new NativeException();
        try{
            System.out.println(n.divide(12, 3));
            n.divide(12, 0);
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}


Even if we marked native method with throws, javac will not complain if we try to call it out of try-catch block. One of reasons why pure Java is preferred to JNI. Also in header file, that throws is just ignored.


In implementation we do sanity check and if second parameter is zero we try to throw IllegalArgumentException.


If env fails to find IllegalArgumentException, we just return zero.

Tuesday, February 19, 2013

Simple Moon processing workflow with Open Source tools

About 50 pictures are taken through small 4.5 inch Newtonian using T-adapter. Since back-focus on this small scope is too short, Barlow x2 is used, what rises focal ratio from f8 to f16. Out of those 50 there is one or two where turbulence is not bad. After transfer of images from camera to hard drive, Rawstudio is used to preview them and find better ones. For conversion from RAW to TIFF I am using Darktable. Here you can see what processing is done in Darktable, what modules are active:



Exported TIFF is then imported in GIMP and GMIC is activated from Filters menu. We will stay in GMIC until end with exception when we are copying layers. From Colors, Tone mapping is performed, using default parameters, and we will work further with result of that transformation.



While it looks better I am not happy with amount of detail, so from the same group with default parameters Local normalization is performed and output mode is set to new image.



Again starting from tone-mapped image, using default parameters Local contrast enhancement from Enhancement group is applied.



At this moment one can decide to use those three image to create pseudo HDR using exposure blend, but I didn’t like flat border area in output, caused by local contrast enhancement. Now I copy-paste local contrast enhanced over local contrast normalized and in GMIC, using input layers all, execute Average blending in Layers group, that is the first one with [standard]. Over result of averaging I copy-paste tone-mapped image, one we started with and do again averaging. This is final result:


Saturday, February 16, 2013

Maximal exposure from tripod without star trails

For a while I was trying to find out what is origin of famous 600 rule without success. Here is what I learned so far. That would be rule applicable to picture taken from tripod, without tracking. That rule says that maximal exposure time for star with declination of 0 degrees is equal 600 divided with focal length in seconds. Here we are talking about 35mm film, so for DSLR camera we need to multiply focal length with crop factor, 1.5 for Nikon and 1.6 for Canon. Declination 0 degrees is celestial equator. Further, rule talks about 0.1mm at 254mm, reading distance, so I assume that image is printed on A4 paper. Since 35mm film went to history that 0.1 mm somehow is mapped to 8 pixels for DSLR camera. Is 8 pixels acceptable or not is another issue. There is even formula:

Maximal exposure = sidereal day * acceptable trail * pixel size /(focal length*2*π*cos(declination))

The sidereal day is 23 h 56 m 4.09 s, acceptable trail is 8 pixels, pixel size for Canon EOS 600D/Ti3 is 0.00429 mm, focal length is 80 mm (50 mm * 1.6), cos(0) is 1. All values must be expressed in the same units. When we convert sidereal day into seconds we have 86164.09 s. After substituting values into equation we got result 5.883066121 s. Some sensor data is available on http://www.sensorgen.info/, crop factor for Nikon and Sony is 1.5, what is acceptable trail for you I do not know, feel free to use it instead of suggested 8 pixels. To find out what is declination of some star, install Stellarium, ignore negative declination on southern hemisphere and use absolute value.
Trigonometric functions are available in any calculator on any OS, just switch into scientific mode. How that cosine influences result? For Orion we can neglect it, but if we want to take picture of Southern Cross about 60 degrees declination our maximal exposure doubles. For declination of 90 degrees we have singular point where exposure grows to infinity, if there is a star at celestial pole we can take whole night exposure - it is not moving. Closer to celestial pole you are, longer exposures are acceptable.

Subclassing Spinner and ArrayAdapter to change drop-down appearance

As we know, applying different layout can change text color and size, background color and so on. There is no need to do any Java code to achieve that, we just use existing Android classes. Now if we want to change drop-down item and include there more controls than just TextView and one drawable or maybe to apply custom resizing, than we have to dive into ArrayAdapter source and write custom adapter. I will not bother you with image and two TextViews, there is plenty of tutorials on Web about that, instead I will just try to resize drop-down to keep it simple. So here is complete code for minimalistic custom adapter:

public class CustomAdapter extends ArrayAdapter implements SpinnerAdapter{
    private LayoutInflater mInflater;
    private int mFieldId = 0;
    private int mResource;
    public CustomAdapter(Context context, int textViewResourceId,
            String[] objects) {
        super(context, textViewResourceId, objects);
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mResource);
    }
    @Override
    public void setDropDownViewResource(int resource) {
        this.mResource = resource;
    }
    private View createViewFromResource(int position, View convertView, ViewGroup parent,
            int resource) {
        View view;
        TextView text;
        if (convertView == null) {
            view = mInflater.inflate(resource, parent, false);
        } else {
            view = convertView;
        }
        try {
            if (mFieldId  == 0) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = (TextView) view;
            } else {
                //  Otherwise, find the TextView field within the layout
                text = (TextView) view.findViewById(mFieldId);
            }
        } catch (ClassCastException e) {
            Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
            throw new IllegalStateException(
                    "ArrayAdapter requires the resource ID to be a TextView", e);
        }
        String item = getItem(position);
        if (item instanceof CharSequence) {
            text.setText((CharSequence)item);
        } else {
            text.setText(item.toString());
        }
        view.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        return view;
    }
}


Most of createViewFromResource is Android code from ArrayAdapter. My modest contribution is only red line. If I specify there some values for width, instead of LayoutParams.FILL_PARENT then I will achieve this:


Well, items are narrower but container is still the same, so subclassing ArrayAdapter doesn’t really help. What needs to be resized and repositioned is AlertDialog which is holding those rows. We can find that out when we open Spinner source. Now I will again do minimalistic subclassing of Spinner.

public class CustomSpinner extends Spinner {
    private AlertDialog mPopup;
    public CustomSpinner(Context context) {
        super(context);
    }
    public CustomSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mPopup != null && mPopup.isShowing()) {
            mPopup.dismiss();
            mPopup = null;
        }
    }
    @Override
    public boolean performClick() {
        Context context = getContext();

        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        CharSequence prompt = getPrompt();
        if (prompt != null) {
            builder.setTitle(prompt);
        }
        mPopup = builder.setSingleChoiceItems(
                new DropDownAdapter(getAdapter()), getSelectedItemPosition(),
                this).show();
        WindowManager.LayoutParams layout = mPopup.getWindow().getAttributes();
        layout.x = -128;
        layout.y = -110;
        layout.height = 320;
        layout.width = 240;
        mPopup.getWindow().setAttributes(layout);
        return true;
    }
    @Override
    public void onClick(DialogInterface dialog, int which) {
        setSelection(which);
        dialog.dismiss();
        mPopup = null;
    }
    /*
     * here you copy and paste code for DropDownAdapter from Spinner
     */
}


Hardcoded values are good enough for illustration of subclassing. Now since we are using custom control we need to change tag in layout:


Now if we build and run application in emulator we will get this:



Not very complicated.

Thursday, February 14, 2013

JNI Hello World on Linux Mint

I wrote similar tutorial for www.linux.com about four years ago. The motivation is the same as then, in then Sun and today Oracle documentation only Solaris and Windows are treated, Linux is omitted. Also there are slight differences in compilation process on 32 bit Ubuntu 9.04 then and 64 bit Linux Mint 13 today. Otherwise there is increase in popularity of JNI thanks to Android NDK. To do native Android development one should be familiar with C, C++, JNI and Java. As in that old article I will use C++ to create shared library.
We start with Java class:

class YAHelloWorld
{
    public native void sayHi(String name);
    static
    {
        System.loadLibrary("YAHelloWorld");
    }
    public static void main(String[] args)
    {
        YAHelloWorld h = new YAHelloWorld();
        h.sayHi("World");
    }
}


Beside normal Java stuff we have request to load native library and forward declaration of native method. We save it as YAHelloWorld.java and compile it

javac YAHelloWorld.java

After that we invoke javah to create native header:

/usr/lib/jvm/java-7-oracle/bin/javah -jni YAHelloWorld

I was lazy to export path, so that is a reason for full path to javah. If you try without full path you may get following suggestion:


what is not really necessary.  Content of generated YAHelloWorld.h is:


The first parameter, JNIEnv * is pointer to array of pointers of JNI functions, jobject is sort of this pointer and jstring is Java String. Now when we know all that we can write C++ implementation:


Beside normal C++ stuff we convert Java String to C++ string at the beginning and at the end we release both of them. Compilation looks like this:

g++ -shared -fPIC -I/usr/lib/jvm/java-7-oracle/include -I/usr/lib/jvm/java-7-oracle/include/linux YAHelloWorld.cpp -o libYAHelloWorld.so

and finally we execute our Hello World example like this:

java -Djava.library.path=. YAHelloWorld

That should produce familiar Hello World output. Not too difficult.

Customizing Spinner appearance

If you want to change appearance of Button or TextView, it is very easy. You open layout subfolder in res folder, then you open activity_main.xml and add the following lines:

android:gravity="center"
android:background="#000000"
android:textColor="#ff0000"
android:textSize="32sp"


Something like that, Button text is centered anyway and TextView background is see through by default, so not all of them may be required. But if you want to change appearance of Spinner things are becoming complicated. Naturally first solution is do Google search and see how others are doing it. That gets you to Stack Overflow and there is plenty of solutions which are based on enthusiasm of contributor to say something. That eloquent guessing, without any understanding what is actually going on, goes that far that they are claiming that you must subclass ArrayAdapter to change text color. To be honest Android documentation is not very helpful here and according to modern scientific approach people go here agile, they do trial and error in plain English. If you do not have knowledge demonstrate effort. Naturally there is much better way. Android is open source project and getting Java code for it is not difficult, in Android SDK Manager one just needs to select Sources for Android SDK and download it. Now if we take a look at typical Spinner usage we see something like this:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Spinner spinner=(Spinner)findViewById(R.id.spinner1);
    spinner.setOnItemSelectedListener(this);
    adapter=new ArrayAdapter(this, android.R.layout.simple_spinner_item, items);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
}


Appearance of Spinner is defined by android.R.layout.simple_spinner_item in collapsed state and android.R.layout.simple_spinner_dropdown_item in expanded state. If we want Spinner to look differently, we need to change layout. Unfortunately android.R.layout.simple_spinner_item is not part of Sources for Android SDK but android.widget.ArrayAdapter is available. We open it and see relevant methods:

public View getView(int position, View convertView, ViewGroup parent) {
    return createViewFromResource(position, convertView, parent, mResource);
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    return createViewFromResource(position, convertView, parent, mDropDownResource);
}


Then we look for createViewFromResource, where real work is done:

private View createViewFromResource(int position, View convertView, ViewGroup parent,
        int resource) {
    View view;
    TextView text;

    if (convertView == null) {
        view = mInflater.inflate(resource, parent, false);
    } else {
        view = convertView;
    }
    try {
        if (mFieldId == 0) {
            //  If no custom field is assigned, assume the whole resource is a TextView
            text = (TextView) view;
        } else {
            //  Otherwise, find the TextView field within the layout
            text = (TextView) view.findViewById(mFieldId);
        }
    } catch (ClassCastException e) {
        Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
        throw new IllegalStateException(
                "ArrayAdapter requires the resource ID to be a TextView", e);
    }
    T item = getItem(position);
    if (item instanceof CharSequence) {
        text.setText((CharSequence)item);
    } else {
        text.setText(item.toString());
    }
    return view;
}

And there we find required information, that printed with red font. We need to supply layout which is TextView or layout containing TextView and to supply ID of TextView fot the second case. Now when we got idea what we are doing changing appearance is trivial.
Collapsed appearance layout:


Expanded appearance layout:


We save those two as custom Spinner layouts. We know that ID can be omitted and we happily omit it, less typing. We use our custom layouts like this:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Spinner spinner=(Spinner)findViewById(R.id.spinner1);
    spinner.setOnItemSelectedListener(this);
    adapter=new ArrayAdapter
(this, R.layout.col, items);
    adapter.setDropDownViewResource(R.layout.exp);
    spinner.setAdapter(adapter);
}


Obviously I saved them as col.xml and exp.xml.