Outreachy Week #3

Merry Christmas everyone! Week 3 is almost over – to use a cliche, how time flies.

A few things that I learnt this week:

  1. Volley is awesome! No, really, it is. So much easier to use than the standard http library. So glad my mentor suggested using it for this week’s task.
  2. How to use GSON to parse JSON data. Also, did you know that serialization/deserialization means the same thing as marshalling/unmarshalling? I didn’t. Got so confused while wading through tutorials until I figured that out.
  3. How I learn best.

There seem to be two general camps of people in the learn-to-code world – those who believe that you need a strong theoretical foundation and build up from there (Read All The Tutorials!(TM) before you start), and those who believe that you should just make stuff and figure things out along the way. I’ve tried both in the past with mediocre results, but over the last few weeks I think I might be catching on to a style that works fairly well for me – a mixture of the two.

If I try to make myself read everything first before I start anything, I’ll never get started, won’t absorb much, and get bored really fast. On the other hand, if I eschew structured tutorials entirely and just try to make things work without a decent foundation, I end up banging my head against trivial problems that a solid foundation might have solved relatively easily.

So what I have been doing is trying to make stuff and figure things out as I go until I hit a wall… and then I go back and read tutorials. I get a lot of ‘aha!’ moments along the way, noticing things that I wouldn’t otherwise have noticed if I’d tried to read it all without actually writing anything. Then once I feel I’ve gathered enough information to solve my problem, I try to solve the problem again, and if I succeed I continue coding until I reach another wall. Rinse and repeat.

Of course, this is all dependent on having the time to do so, and I’m glad that so far I do. Outreachy (or at least, Wikimedia’s Outreachy programme) seems to be structured with a bit of leeway for us to take time to learn along the way rather than just pushing for results, which I’m really grateful for. Things might be a bit more rushed over the next week or so, since we’re at a more nebulous part of the schedule now, where there isn’t a 100% clear delineation between each week’s task, and I’ll be traveling for a few days over the New Year. Hopefully I manage to keep up!

 

My code for this week’s task can be found here.

Advertisements
Outreachy Week #3

Outreachy Week #2

Boy, has it been a busy week! Implemented GPS coordinate extraction from uploaded photos, which was a much more windy road than it would seem  at first glance. We had to alter the code to temporarily stop uploads while testing (to prevent me from uploading dozens of nonsensical pictures to the actual Commons database), and then there were issues with finding where to insert the code in the app, how to convert the image Uri to a file path, issues with refactoring…

But we did it, woohoo! 🙂 Two brand new classes for the app:

  1. FilePathConverter.java
public class FilePathConverter {

    private Uri uri;
    private Context context;

    public FilePathConverter(Context context, Uri uri) {
        this.context = context;
        this.uri = uri;
    }

    /**
     * Gets file path of image from its Uri
     * May return null
     */
    public String getFilePath(){
        String filePath ="";
        String wholeID = DocumentsContract.getDocumentId(uri);

        String id = wholeID.split(":")[1];
        String[] column = { MediaStore.Images.Media.DATA };

String sel = MediaStore.Images.Media._ID + "=?";
        Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                column, sel, new String[]{id}, null);

        int columnIndex = cursor.getColumnIndex(column[0]);

        if (cursor.moveToFirst()) {
            filePath = cursor.getString(columnIndex);
        }
        cursor.close();

        Log.d("Image", "File path: " + filePath);
        return filePath;
    }
}

2. GPSExtractor.java

public class GPSExtractor {

    private String filePath;

    public GPSExtractor(String filePath){
        this.filePath = filePath;
    }

    //Extract GPS coords of image
    public String getCoords() {

        ExifInterface exif;
        String latitude = "";
        String longitude = "";
        String latitude_ref = "";
        String longitude_ref = "";
        String decimalCoords = "";

        try {
            exif = new ExifInterface(filePath);
            latitude = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
            latitude_ref = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
            longitude = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
            longitude_ref = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);

            Log.d("Image", "Latitude: " + latitude + " " + latitude_ref);
            Log.d("Image", "Longitude: " + longitude + " " + longitude_ref);

            decimalCoords = getDecimalCoords(latitude, latitude_ref, longitude, longitude_ref);

        } catch (IOException e) {
            Log.w("Image", e);
        }
        return decimalCoords;
    }

    //Converts format of coords into decimal coords as required by API for next step
    private String getDecimalCoords(String latitude, String latitude_ref, String longitude, String longitude_ref) {

        double decLatitude, decLongitude;

        if(latitude_ref.equals("N")){
            decLatitude = convertToDegree(latitude);
        }
        else{
            decLatitude = 0 - convertToDegree(latitude);
        }

        if(longitude_ref.equals("E")){
            decLongitude = convertToDegree(longitude);
        }
        else{
            decLongitude = 0 - convertToDegree(longitude);
        }

        return (String.valueOf(decLatitude) + "|" + String.valueOf(decLongitude));
    }

    private double convertToDegree(String stringDMS){
        double result;
        String[] DMS = stringDMS.split(",", 3);

        String[] stringD = DMS[0].split("/", 2);
        double d0 = Double.parseDouble(stringD[0]);
        double d1 = Double.parseDouble(stringD[1]);
        double degrees = d0/d1;

        String[] stringM = DMS[1].split("/", 2);
        double m0 = Double.parseDouble(stringM[0]);
        double m1 = Double.parseDouble(stringM[1]);
        double minutes = m0/m1;

        String[] stringS = DMS[2].split("/", 2);
        double s0 = Double.parseDouble(stringS[0]);
        double s1 = Double.parseDouble(stringS[1]);
        double seconds = s0/s1;

        result = degrees + (minutes/60) + (seconds/3600);
        return result;
    }
}
Outreachy Week #2

Outreachy Week #1

Woohoo, I’ve survived Week 1! 😀

(Background information about the project is at my About page)

No real coding this week, but a lot of API research, querying, and testing – we were trying to identify the best strategy/APIs to find Commons categories within a certain radius of specified GPS coordinates. Basically, Phase 1 of the project will involve using the chosen strategy to match an uploaded picture’s GPS coordinates with Commons categories that are found nearby, in order to display category suggestions to the user. Currently the only suggestions displayed to the user are ‘previously used categories’, so the goal for Phase 1 is to provide more suggestions that are tailored to the locality in which the picture was taken.

We were initially considering 3 strategies/APIs:

  1. The WikiData API that was suggested by Magnus on Nicolas (co-mentor)’s StackOverflow threadUnrelated note: I later found out via Stephen (mentor) that Magnus has made a whole lot of other contributions to Wikimedia, and curiosity led me to his wikipedia page, which stated that he was one of those who worked on the initial software that all of the wikis are now based on. Oooh. Small world. 🙂
  2. The Commons API
  3. The “search for existing pics at that location” strategy, code-named Method C. Instead of querying directly for Commons categories, this strategy searches for existing pictures on the Commons database that have GPS coordinates close to the uploaded picture’s coordinates, and retrieves their categories. Pretty nifty.

I eventually found out that the Commons API was not suitable, so we distilled the comparison down to WikiData vs Method C. In both of those cases there were, fortunately, external tools to aid in running queries on the API quickly and easily for testing purposes – TABernacle for WikiData and the Commons MediaWiki API Sandbox for Method C. I used 10 sample pictures and categorized them manually (by taking the current categories given by the Commons community, and adding any of my own that I saw fit), then ran them through WikiData and Method C to see how many pertinent categories were picked up. All of the results are on the GitHub wiki.

Long story short, the WikiData API worked out fine – not many false positives and not many good categories suggested, but still a huge improvement to the current app’s suggestions. But Method C performed even better, retrieving more good categories despite finding more false positives. As Nicolas mentioned, though, a false positive isn’t as big a deal as lack of good category suggestions, because if the good category wasn’t present in the suggestion list, the user would have to try and guess the right category and potentially scroll through dozens of other ‘false positives’ in the alphabetical-ordered list.

So, we’ll probably go with Method C (or its successor Method D, which involves manipulating the radius), but that will likely be decided during our next weekly meeting. The last meeting we had was incredibly productive – brainstorming with Stephen and Nicolas was a huge help in overcoming the “oh no, this doesn’t work! what to do next??” block that I encountered halfway through.

The next task involves finding a library to extract the GPS coordinates of uploaded pictures, and implementing it. Finding the library itself shouldn’t be too hard, I reckon, but I’m still a little nervous about the implementation. This app is a fair bit more complex than any other app I’ve tinkered with so far, and while I’ve already made some modifications to it for the microtasks required for my application, they were mostly simple activity/UI tweaks or bugfixes – none of them involved actually getting down and dirty with the actual uploading/categorization code. I’ve spent quite a bit of time over the past few weeks looking at the existing upload/categorization code and trying to understand it, but I don’t think I’m anywhere close to 100% on that just yet.

Outreachy Week #1

Comfort zones, and the start of Outreachy

I like comfort zones. I don’t like going out of them. But I’m forced to acknowledge that doing so is often the only way forward.

I’m nervous as all heck about Outreachy. Excited, sure, but nervous as well. This is my first large project outside of academia/research, and pretty much my first open source project, period, so there’s a lot of learning the ropes as I go. I try to believe in both “you can do anything you set your mind to” and “fail early, fail often, fail quickly”… but I sure as hell hope the former will describe the outcome of this particular attempt, not the latter. :p

A big part of the reason for my nervousness is that I took an unconventional route into the coding arena, and I’ve felt like I’m always playing catch up. A few years ago, I made a career switch, took advantage of the Graduate Diploma option for people with previous degrees, and plunged into third-year classes without prereqs despite barely having written a “Hello World” before. Amazingly, I survived, graduated, and went on to grad school! And I’ve come quite a way from my pre-hello-world days, if I may say so myself. But I often feel that my foundation is weak. Occasionally things crop up that I’m pretty sure I should know, should have learnt in what should have been my first year of compsci classes… but, well, didn’t.

So, I figure I just have to keep plugging on. I need to work on both my competency and confidence, and I can hardly think of a better way to do it than this. My mentors, for the record, have been AMAZING. 🙂 Getting one-on-one guidance from experienced developers has been so invaluable, I regret not having participated in mentorship programs earlier on. Heck, everyone I’ve talked to in Wikimedia has been incredibly helpful and encouraging. Definitely one of the best communities I’ve been in.

Outreachy officially starts next week. Here’s to hoping for a successful run – wish me luck. 🙂

 

Comfort zones, and the start of Outreachy