Recent Updates RSS Toggle Comment Threads | Keyboard Shortcuts

  • Aditya Bhatt 6:20 am on December 29, 2011 Permalink | Reply
    Tags: canvas, javascript, mongodb, node.js, now.js, realtime   

    Memecached: Real-Time meme sharing with node.js, now.js, and MongoDB 

    Yesterday, I wrote a web-app named Memecached. It is a service which allows you to quickly generate a meme and publish it in real-time. It went viral for quite a few hours after I tweeted about it and posted it on Hacker News, with hundreds of memes being shared, sometimes a new meme every three seconds!

    Memecached is extremely lightweight. The server is tiny, written entirely in exactly 50 lines of Javascript using node.js. It uses MongoDB as the data store and now.js for real-time, remote method invocation.

    Awkward text blackened

    Using it is fairly trivial – you open the page, and the latest N (25 by default) memes are streamed back and populated into the webpage. On the left is a collections of meme templates – you can click any one, enter the top and bottom text, and hit publish to see it reflected on each open client.

    Some Code

    On the server side, the now.js initialization didn’t work normally as sometimes the client – my chrome browser – would not perform a handshake (I’ve reported this in the now.js issue here: , so I had to fiddle around with the options till I found that xhr-polling seemed to work.

    var everyone = require("now").initialize(server, { socketio: {'transports': ['xhr-polling'] }} );
    

    Publishing a meme involves validating the meme document, inserting it into mongo, and the passing it to all clients with:

    // publish meme
    everyone.now.publish = function(meme) {
        if(meme.name && meme.text.line1 && meme.text.line2) {
            db.collection('memes', function(err, collection) {
                // add a date field and save
                meme.date = Date.now();
                collection.insert(meme, function(err) {
                    if(!err)
                        everyone.now.receiveMeme(meme);
                });
            });
        }
    };
    

    Retrieving a recent memes’ list is a trivial matter of looking up the last 25 in the ‘memes’ collecion:

    // retrieve the latest few memes of a name. If there is no name, retrieve a mixture
    everyone.now.getRecent = function(memeName) {
        var client = this;
        console.log("retrieving");
        db.collection('memes', function(err, collection) {
            if(memeName == undefined) {
                collection.find( {}, { sort: [[ "date", "desc" ]], limit: 25 }).toArray( function(err, docs) {
                    client.now.getContent(docs);
                });
            }
            else {
                collection.find( {"name": memeName}, { sort: [[ "date", "desc" ]], limit: 25 }).toArray( function(err, docs) {
                    client.now.getContent(docs);
                });
            }
        });
    };
    

    How it works

    All meme template images are stored on Dropbox.

    • When a new meme is published, the server takes a JSON object from the client, containing the meme name and text. No image whatsoever.
    • The received meme object is inserted into the mongo collection memes with a date timestamp added to it. The object is also sent to all connected clients immediately so that they may update their timelines. This also means that no further database queries are required to retrieve new memes.
    • When a client connects, the last few (25) memes are queried from the database and sent back. This can further be optimized by having an in-memory queue of the most recent memes, in addition to the database.
    • All meme generation is done entirely client-side, by drawing the text over the images using Canvas. The client doesn’t have to download images, and the server doesn’t have to handle them at all.

    How to run

    1. First, run mongod to start the Mongo daemon.
    2. Next, run the server: node app.js
    3. Point your browser to http://localhost:8080.
    4. Bask in Memetic paradise.

    Things to do

    • Upvotes/Downvotes: This should be a ten-minute job. Just add two new keys to the ‘schema’ of the doc.
    • Sharing: Memes are rendered in Canvas. Need to get the dataUrl() and allow the user to save the image to a file.
    • Line breaks: There need to be line breaks in a meme phrase. Right now, extra long sentences will make the font shrink too much to be visible.
     
    • Viranch 1:41 pm on December 29, 2011 Permalink | Reply

      Awesome! One question: Isn’t constantly sending updates to ALL clients a little expensive when there’s a really big number of clients connected?

    • Aditya Bhatt 4:10 pm on December 29, 2011 Permalink | Reply

      It is the least expensive of all operations, because only *one* meme is sent to all clients simultaneously when published, not the entire database.
      Then again, large numbers of clients are a problem for any service, the only way to fix that is to have more threads/machines and load balance. Not a problem here.

    • Malav Bhavsar 7:16 pm on December 29, 2011 Permalink | Reply

      Ah. I found out the blackened-awkward text :D

  • Aditya Bhatt 4:54 am on September 23, 2011 Permalink | Reply
    Tags: , , , php, swig, web service   

    Introducing FaceOff and How To Write a PHP Extension For Your C++ API using SWIG 

    FaceOff is a simple web service that takes photographs and returns coordinates of detected faces, encapsulated with JSON. It uses a PHP-wrapped libface for the processing.
    The source code is on GitHub.

    ***

    These days I’m into wrappers.

    As a personal exercise in wrapping C++ code with PHP, I decided to wrap libface, a C++ library for face detection that I worked on as my GSoC 2010 project for face tagging in digiKam. SWIG provides a rather simple way to do this. Here’s how to do it.

    The interface file

    SWIG gives you a ‘non-invasive’ way to wrap an API, in that you don’t have to modify the library at all. First, you’ll need to write an interface file – library_wrapped.i. Here, we’ve named it libface_php.i.

    # Wrap everything under module libface_php
    
    %module libface_php
    %{
    #include "/usr/include/libface/LibFaceConfig.h"
    #include "/usr/include/libface/Log.h"
    #include "/usr/include/libface/LibFaceCore.h"
    #include "/usr/include/libface/Face.h"
    #include "/usr/include/libface/LibFaceUtils.h"
    #include "/usr/include/libface/LibFace.h"
    #include "/usr/include/libface/Haarcascades.h"
    #include "/usr/include/libface/FaceDetect.h"
    #include "/usr/include/libface/Eigenfaces.h"
    
    #include "glue.cpp"
    
    %}
    
    %include std_string.i
    %include std_vector.i
    %include std_map.i
    %include cpointer.i
    
    %include /usr/include/libface/LibFaceConfig.h
    %include /usr/include/libface/Log.h
    %include /usr/include/libface/LibFaceCore.h
    %include /usr/include/libface/Face.h
    %include /usr/include/libface/LibFaceUtils.h
    %include /usr/include/libface/LibFace.h
    %include /usr/include/libface/Haarcascades.h
    %include /usr/include/libface/FaceDetect.h
    %include /usr/include/libface/Eigenfaces.h
    %include glue.cpp

    The %module declares the name of the PHP extension. Once compiled, it will be named as ‘libface_php.so’.
    This, of course, assumes that libface was installed under /usr – I couldn’t find a way to tell SWIG to prefix a path automatically upon invokation. The paths can be changed accordingly.

    Glue

    Next, SWIG isn’t perfect. And there are some things which make sense in one language but not in the other. For example, pointers in C++ are converted to resources in PHP. There may not be a dead-simple mapping from a vector type to an array type, for instance. To use some language-specific data structures, we need glue code.

    glue.cpp:

    #include 
    
    using namespace std;
    using namespace libface;
    
    Face* faceAt(vector v, int index)
    {
        return  (v[index]);
    }

    So now we have the interface in place. Now comes the easy part – if all went well while writing the above; if it didn’t, you’ll have to try the next steps, test the wrapper, and then wrestle with the interface a bit (or  a lot!) more and tweak it till it works.

    Generating

    First off, we have to generate a wrapper.

    swig -c++ -php libface_php.i

    This generates a file libface_php_wrap.cpp. This is the wrapper code that needs to be built and linked with libface.
    Compile it:

    g++ `php-config --includes` -fPIC -c libface_php_wrap.cpp

    The -fPIC option instructs g++ to generate position-independent code.
    Link it with libface and generate the extension:

    g++ -shared libface_php_wrap.o -o libface_php.so -lface

    The extension we wanted has now been created – libface_php.so.
    Copy this to the PHP extensions directory:

    cp libface_php.so `php-config --extension-dir`

    In your system’s php.ini (/etc/php/php.ini in Arch), don’t forget to add the line:

    extension=libface_php.so

    You’re done. While doing this, a file libface_php.php was generated. This is the sole file that you will include in your php code.

    Using it is rather simple:

    require ("libface_php.php");
    
    $instance = new Libface(DETECT);
    $filename = "test.png";
    $detected_faces = $instance->detectFaces($filename);
    $count = $detected_faces->size();
    
    // get the coordinates of the first face
    if($count >= 1)
    {
        $face = new Face(faceAt($detected_faces, 0)); // the face at index zero in the vector
        // Top left and bottom right coordinates
        echo "First face is : (" . $face->getX1() . "," . $face->getY1() . "),(" . $face->getX2() . "," . $face->getY2() . ")";
    }

    That’s it. Of course, this may not be the best way to wrap it, so suggestions are welcome.

     
    • stéphane 9:44 pm on December 9, 2011 Permalink | Reply

      Good Works but don’t work with PHP5, you must have PHP 4

      • Aditya Bhatt 8:33 pm on December 10, 2011 Permalink | Reply

        It does, I tested it with PHP5. What issues did you find?

        • Stéphane 9:41 pm on December 12, 2011 Permalink

          i find for generate a wrapper for PHP 5 the command is :

          swig -c++ -php5 libface_php.i

          else command swig -c++ -php libface_php.i generate file for PHP4

          Good jobs !

        • Aditya Bhatt 11:46 am on December 13, 2011 Permalink

          Glad it was solved. :)

  • Aditya Bhatt 5:10 am on June 10, 2011 Permalink | Reply
    Tags: DSP, , ,   

    SETI Algorithms project update 

    A quick update to list my progress with the SETI internship so far:

    So far, most of the existing simple DSP code has been open-sourced in the form of a new library. I’ve named the library SETIkit, and you can find it on GitHub. The progress is documented in a wiki page.

    The project uses CMake as the build system, and depends on

    • FFTW (Fast Fourier Transform in the West)
    • GSL (GNU Scientific Library)
    The library is split into several modules
    • sq_utils contains several useful routines for logging, error handling, noise generation, and interop with the ATA (Allen Telescope Array) data format.
    • sq_signals has functions that generate test signals. For now, we have a routine named sq_gen_sine that streams out a complex sinusoid with gaussian noise.
    • sq_dsp contains a growing list of useful DSP utils:
      • FFT
      • Power calculation
      • Hann windowing
      • Conjugate calculation
      • DC offsets, Scaling, complex rotation
      • WOLA (Weighted OverLap Add)
      • Real/Imaginary channel extraction
      • Heterodyne
    • sq_imaging is a collection of a few functions that read signal data, scale it linearly/according to the power, and write it as a PGM image.
    We now have all the code that is required to generate waterfall plots (more commonly known as spectrograms) of the SETI observation data.
    Now there is a bunch of signal processing blocks that we use in a UNIX pipeline – programs that take signal data from one stream, do some processing, and pipe the resulting data to other programs.
    A typical pipeline for generating waterfalls from the SETI data:
     cat ~/Data/2010-04-02-amc7-3693.4464-8bit-one-second.dat | ./sqsample -l 4096 | ./sqmix -c 0.0 
    | ./sqwindow -l 4096 | ./sqfft -l 4096 | ./sqpower -l 4096 | ./sqreal -l 4096 
    | perl -e 'while(read(STDIN,$bfr,4096*4)==4096*4) {syswrite(STDOUT,$bfr,1024*4,1536*4)}' 
    | ./sqpnm -c 1024 -r 1200 -p > out.pgm
    This takes data from a file that contains one second’s worth of observations of the AMC-7 geosynchronous satellite’s broadcasts.
    • The sqsample block takes 2-channel (quadrature) 8-bit data from stdin, and writes out samples (floats) to stdout in the form of alternating real and imaginary values.
    • The sqmix block heterodynes a chosen digital frequency (here 0.0 Hz, we’ll see more later)  to DC (0 Hz). That is, you can use this to move the spectrum to the left and right.
    • The sqwindow block applies a hanning (or hann) window to the signal.
    • The sqfft block streams out the Fast Fourier Transform of the windowed signal.
    • sqpower computes the instantaneous power signal.
    • sqreal extracts the real part from the information.

    The 4096 argument to all those blocks is the number of samples they can read, write, and process in one go.

    The perl code neatly arranges the signal data so that it can be visualized as an image, also giving you control over the ‘region’ of the image you want to see. The sqpnm block then takes this data, scales it, and writes it out to a binary PNM/PGM image.
    Here’s the waterfall that the above pipeline generates:

    Waterfall Plot. Horizontal: Frequency | Vertical: Time | Brightness: Frequency Intensity.

    That’s it for now.
     
  • Aditya Bhatt 1:48 am on April 29, 2011 Permalink | Reply
    Tags: , ,   

    I’m in! Google Summer of Code: The SETI Institute 

    So I got this mail in my inbox from Google:

    Dear Aditya,

    Congratulations! Your proposal “Open sourcing of Exploratory Techniques for the SETI Search” as submitted to “SETI Institute” has been accepted for Google Summer of Code 2011.

    I’m in! :-)

    I’ll be interning with the SETI Institute (Search for Extra Terrestrial Intelligence). My project’s title is Open Sourcing of Exploratory Techniques for the SETI Search. The competition was tough, and so will be the work. I’m looking forward to an exciting summer with tons of code and signal analysis.

    My mentor is Gerry Harp, who is an astrophysicist at the SETI Institute. Guided by him and Rob Ackermann, I’ll be implemeting and improving their signal search algorithms as reference implementations in C, and publishing them in the form of an official SETI library. These algorithms, together with the published SETI observation data, should enable citizen scientists and enthusiasts to analyse signals on their own, thus inching closer to Dr. Jill Tarter’s 2009 TED wish:

    I wish that you would empower Earthlings everywhere to become active participants in the ultimate search for cosmic company.

    The work will provide people with a way to analyze the data collected by the Allen Telescope Array (ATA).

    I’ll regularly be blogging about my work.

     
    • Anonymous 4:17 am on May 1, 2011 Permalink | Reply

      Looking forward to following your work.

    • Mihir 11:38 am on May 6, 2011 Permalink | Reply

      Hey,

      Congratulation once again dude :)

      All the best :D

c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel
Follow

Get every new post delivered to your Inbox.

Join 165 other followers