Monday, 28 October 2013

Annotated feature convolution code from Deformable Parts Model

The following code is an excerpt from that comes with the following paper:

A Discriminatively Trained, Multiscale, Deformable Part Model.
P. Felzenszwalb, D. McAllester, D. Ramaman.
Proceedings of the IEEE CVPR 2008.

The original code was downloaded from:

I only added some comments to make it easier to read. The comments illustrate how the data structures are designed (should also help understanding the multi-threaded and SSE-optimized implementations).
#include "mex.h"
#include <math.h>
#include <string.h>

 * This code is used for computing filter responses.  It computes the
 * response of a set of filters with a feature map.  
 * Basic version, relatively slow but very compatible.


The dimensions for A, B and C are as follows. For example:

A = A1*A2*32 single
B <2x1 cell> for each cell B{i} = B1i*B2i*32 single

Usually A is larger than B (as A is the feature map and B is the filter).

C <1x2 cell> for i-th cell is the response for the i-th filter.

C{i} = (A1-B1i+1)*(A2-B2i+1)*32 double


struct thread_data {
  float *A;
  float *B;
  double *C;
  mxArray *mxC;
  const mwSize *A_dims;
  const mwSize *B_dims;
  mwSize C_dims[2];

// convolve A and B (A is feature map, B is filter)
void process(void *thread_arg) {
  thread_data *args = (thread_data *)thread_arg;
  float *A = args->A;
  float *B = args->B;
  double *C = args->C;
  const mwSize *A_dims = args->A_dims;
  const mwSize *B_dims = args->B_dims;
  const mwSize *C_dims = args->C_dims;
  int num_features = args->A_dims[2];

  // for each feature dimension (e.g., 32 dim HOG)
  for (int f = 0; f < num_features; f++) {
    double *dst = C;
    // calibrate the pointer to the base at the f-th dimension
    float *A_src = A + f*A_dims[0]*A_dims[1];      
    float *B_src = B + f*B_dims[0]*B_dims[1];
    // for each pixel (x,y) on the response map
    for (int x = 0; x < C_dims[1]; x++) {
      for (int y = 0; y < C_dims[0]; y++) {
        double val = 0;
        // operate along the second dimension (column) of B (filter)
        // xp is the pointer/offset for the second dimension of B
        for (int xp = 0; xp < B_dims[1]; xp++) {
          // calibrate the pointer to the current column
          // for A it's (x+xp)*(number of elements per column) + (row offset)
          float *A_off = A_src + (x+xp)*A_dims[0] + y;
          // for B it's xp*(number of elements per column)
          float *B_off = B_src + xp*B_dims[0];
          // depending on the number of elements per row
          // if number of elements per row <= 20 then use the loop-less code below
          // the more general default case which uses for-loop follows
          // as for most filters number of elements per row <= 20
          // this would acclerate the process.
          switch(B_dims[0]) {
            case 20: val += A_off[19] * B_off[19];
            case 19: val += A_off[18] * B_off[18];
            case 18: val += A_off[17] * B_off[17];
            case 17: val += A_off[16] * B_off[16];
            case 16: val += A_off[15] * B_off[15];
            case 15: val += A_off[14] * B_off[14];
            case 14: val += A_off[13] * B_off[13];
            case 13: val += A_off[12] * B_off[12];
            case 12: val += A_off[11] * B_off[11];
            case 11: val += A_off[10] * B_off[10];
            case 10: val += A_off[9] * B_off[9];
            case 9: val += A_off[8] * B_off[8];
            case 8: val += A_off[7] * B_off[7];
            case 7: val += A_off[6] * B_off[6];
            case 6: val += A_off[5] * B_off[5];
            case 5: val += A_off[4] * B_off[4];
            case 4: val += A_off[3] * B_off[3];
            case 3: val += A_off[2] * B_off[2];
            case 2: val += A_off[1] * B_off[1];
            case 1: val += A_off[0] * B_off[0];
              for (int yp = 0; yp < B_dims[0]; yp++) {
                val += *(A_off++) * *(B_off++);
       *(dst++) += val;

// matlab entry point
// C = fconv(A, cell of B, start, end);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 
  if (nrhs != 4)
    mexErrMsgTxt("Wrong number of inputs"); 
  if (nlhs != 1)
    mexErrMsgTxt("Wrong number of outputs");

  // get A
  const mxArray *mxA = prhs[0];
  if (mxGetNumberOfDimensions(mxA) != 3 || 
      mxGetClassID(mxA) != mxSINGLE_CLASS)
    mexErrMsgTxt("Invalid input: A");

  // get B and start/end
  const mxArray *cellB = prhs[1];
  mwSize num_bs = mxGetNumberOfElements(cellB);  
  int start = (int)mxGetScalar(prhs[2]) - 1;
  int end = (int)mxGetScalar(prhs[3]) - 1;
  if (start < 0 || end >= num_bs || start > end)
    mexErrMsgTxt("Invalid input: start/end");
  int len = end-start+1;

  // output cell
  plhs[0] = mxCreateCellMatrix(1, len);

  // do convolutions
  thread_data td;
  const mwSize *A_dims = mxGetDimensions(mxA);
  float *A = (float *)mxGetPr(mxA);
  for (int i = 0; i < len; i++) {
    const mxArray *mxB = mxGetCell(cellB, i+start);
    td.A_dims = A_dims;
    td.A = A;
    td.B_dims = mxGetDimensions(mxB);
    td.B = (float *)mxGetPr(mxB);
    if (mxGetNumberOfDimensions(mxB) != 3 ||
        mxGetClassID(mxB) != mxSINGLE_CLASS ||
        td.A_dims[2] != td.B_dims[2])
      mexErrMsgTxt("Invalid input: B");

    // compute size of output
    int height = td.A_dims[0] - td.B_dims[0] + 1;
    int width = td.A_dims[1] - td.B_dims[1] + 1;
    if (height < 1 || width < 1)
      mexErrMsgTxt("Invalid input: B should be smaller than A");
    td.C_dims[0] = height;
    td.C_dims[1] = width;
    td.mxC = mxCreateNumericArray(2, td.C_dims, mxDOUBLE_CLASS, mxREAL);
    td.C = (double *)mxGetPr(td.mxC);
    process((void *)&td);
    mxSetCell(plhs[0], i, td.mxC);

Wednesday, 16 October 2013

Installing Linux Mint 13 Maya from hard drive in Windows 7

Here are some simple steps you need to follow if you want to install Linux Mint from your hard drive, without using USB sticks or blank DVDs. We assume you have Windows 7 installed.

1. Download Linux Mint 13 ISO from the official website. Put the ISO file at C:\.

2. Search for and download Grub4dos. Install Grub4dos by copying grldr to C:\. Create a new file C:\menu.lst and put the following contents in:
timeout 10
default 0

title Windows 7
find --set-root --ignore-floppies --ignore-cd /bootmgr
chainloader /bootmgr
3. Search for and download Bootice. Run Bootice and select your hard drive, then click on Process MBR. Choose Grub for DOS and click on Install/Config. This replaces your MBR with the one from Grub4dos.

4. Extract vmlinuz and initrd.lz files from your Linux Mint ISO and put them at C:\. They should be in a folder named casper. It is important that these files should be copied to your hard drive.

5. Restart your machine. You should be able to see the GRUB menu. From that press c for command line. Enter the following commands (for the first command you can press Tab key while entering to see list of files):
find /linuxmint-13-mate-dvd-64bit.iso
kernel (hd0,1)/vmlinuz boot=casper iso-scan/filename=/linuxmint-13-mate-dvd-64bit.iso
initrd (hd0,1)/initrd.lz
When you enter the first command you should see the partition with your Linux Mint ISO file. For all the rest commands you need to change the (hd0,1) part accordingly. Also, you can also use --set-root option to set your root to that partition but that is not necessary.

6. Once Linux Mint Live is booted, go to the terminal and run
sudo umount -l /isodevice
This will avoid errors when you attempt to modify partitions. You can then click on the shortcut on the desktop to install Linux Mint to your hard drive.

Sunday, 13 October 2013

Infinite error loop when using MATLAB with nohup

If you run MATLAB scripts remotely with ssh and nohup (to keep it running in the background), you may find MATLAB entering an infinite loop of the following errors when your script or function finishes:

Warning: Error reading character from command line


Bad file descriptor

This has nothing to do with your code, just that you will have to add "</dev/null" before the "&" symbol which is causing the error. For example, you can run a function like this:
nohup matlab -nodisplay -r "myfunc_in_current_dir('params')" > ./mylog.txt </dev/null &
Also, people suggested using the "-nojvm" option. If you are plotting in your script then this option should be avoided.

Friday, 4 October 2013

Password-less ssh logins with RSA key pairs

First, edit your local ~/.bashrc file and add the following lines:
function server1(){
This creates a command named server1 to automatically ssh log in to However you will still need to enter your password each time you run this command.

Then, run the following commands from the bash shell on your local machine:
ssh-keygen -t rsa
ssh "mkdir .ssh"
scp ~/.ssh/
For the first command, press enter three times to create public and private keys without a password. The second command creates a directory named ".ssh" in your remote home directory. The third one copies over the public key.

Finally, run the following commands on the remote machine (by logging on using ssh):
touch ~/.ssh/authorized_keys
cat ~/.ssh/ >> ~/.ssh/authorized_keys
If the file ~/.ssh/authorized_keys already exists you can skip the first command. The second command appends into authorized_keys.

That's it. Try to type server1 again from your local shell prompt and you'll not be prompted to enter password from now on.

Change MAC address for your Ethernet adapter in Linux

Run the following commands from bash shell (yes you may need to cd to /etc first):
cd /etc
sudo vim rc.local
Add the following lines before "exit 0" (change the MAC address as needed):
/sbin/ifconfig eth2 down
/sbin/ifconfig eth2 hw ether 00:00:00:00:00:00
/sbin/ifconfig eth2 up
Restart your system and it should be OK.

If you want to temporarily change your MAC address, simply run the 3 lines of commands at bash shell prompt.

Converting 16-bit images to 8-bit images in OpenCV

Here is a simple example to convert 16-bit images to 8-bit images in OpenCV (for a single pixel). Note that the conversion is lossy.
// the original depth image is 16-bit (IPL_DEPTH_16U)
IplImage *dimg_original = cvLoadImage( filename, CV_LOAD_IMAGE_UNCHANGED );
CvScalar s = cvGet2D(dimg_original, 0, 0);
printf("16-bit depth value is %d, ",(int)s.val[0]);

// convert the original 16-bit depth image into 8-bit
IplImage *dimg = cvCreateImage(cvGetSize(dimg_original), IPL_DEPTH_8U,dimg_original->nChannels);
cvConvertScale(dimg_original, dimg, 1./40); //40 is the scaling factor to map 16-bit into 8-bit
CvScalar s1 = cvGet2D(dimg, 0, 0);
printf("8-bit depth value is %d\n",(int)s1.val[0]);
A few notes:
1. index in cvGet2D() and cvSet2D() starts with zero, and is in column-major order, i.e., cvGet2D(img, y, x)
2. If the scaling factor is greater than 1./256 (note that 65536 / 256 = 256, in the above example we set the factor to 1./40), pixels with larger values will all be mapped to 255 (no difference any more for larger values).
3. This method can also be used to convert 32-bit images to 8-bit images.

MATLAB error message during startup on Linux

If you install your MATLAB at /usr/local/, you may not be able to start MATLAB (getting a long error message saying that MATLAB is exiting with a fatal error and no GUI shows up).

Alternatively MATLAB may start with the error message "The desktop configuration was not saved successfully".

In these cases you could try to change the owner of your ~/.matlab folder (change twang to your Linux username):
sudo chown -R twang ~/.matlab
This should fix the problem.

Improved HOG feature in Deformable Parts Model (CVPR 2008)

The following code is an excerpt from that comes with the following paper:

A Discriminatively Trained, Multiscale, Deformable Part Model.
P. Felzenszwalb, D. McAllester, D. Ramaman.
Proceedings of the IEEE CVPR 2008.

The original code was downloaded from:

I only added some comments to make it easier to read. This improved HOG feature performs a little bit better than the original HOG implementation in OpenCV. It is easy to understand, tweak, and very popular in the community.
#include <math.h>
#include "mex.h"

// small value, used to avoid division by zero
#define eps 0.0001

// unit vectors used to compute gradient orientation
double uu[9] = {1.0000, 
double vv[9] = {0.0000, 

static inline double min(double x, double y) { return (x <= y ? x : y); }
static inline double max(double x, double y) { return (x <= y ? y : x); }

static inline int min(int x, int y) { return (x <= y ? x : y); }
static inline int max(int x, int y) { return (x <= y ? y : x); }

// main function:
// takes a double color image and a bin size 
// returns HOG features
mxArray *process(const mxArray *mximage, const mxArray *mxsbin) {
  double *im = (double *)mxGetPr(mximage);
  const int *dims = mxGetDimensions(mximage);
  if (mxGetNumberOfDimensions(mximage) != 3 ||
      dims[2] != 3 || // must be a 3-channel image
      mxGetClassID(mximage) != mxDOUBLE_CLASS)
    mexErrMsgTxt("Invalid input");

  int sbin = (int)mxGetScalar(mxsbin); // pixel size for the HOG cells

  // memory for caching orientation histograms & their norms
  int blocks[2];
  blocks[0] = (int)round((double)dims[0]/(double)sbin); // how many cells along the cloumn
  blocks[1] = (int)round((double)dims[1]/(double)sbin); // how many cells along the row
  double *hist = (double *)mxCalloc(blocks[0]*blocks[1]*18, sizeof(double)); // level histogram into 18 orientation bins
  double *norm = (double *)mxCalloc(blocks[0]*blocks[1], sizeof(double)); // store the norm for gradient in each cell

  // memory for HOG features
  int out[3];
  out[0] = max(blocks[0]-2, 0);
  out[1] = max(blocks[1]-2, 0);
  out[2] = 27+4+1; 
  mxArray *mxfeat = mxCreateNumericArray(3, out, mxDOUBLE_CLASS, mxREAL);
  double *feat = (double *)mxGetPr(mxfeat);
  int visible[2];
  visible[0] = blocks[0]*sbin; // number of pixels along cloumn
  visible[1] = blocks[1]*sbin; // number of pixels along row
  for (int x = 1; x < visible[1]-1; x++) { // NOTE: in this loop row comes first, and x and y are iterated from 1 to visible[]-1,
    for (int y = 1; y < visible[0]-1; y++) { // in this way both x and y cooridnates leave out 1 pixel at the edges

      // first color channel
      double *s = im + min(x, dims[1]-2)*dims[0] + min(y, dims[0]-2); // NOTE: matlab matrices are stored in cloumns, to get access to rows 
      // we need to multiply by dims[0] (number of cells along the cloumn)
      double dy = *(s+1) - *(s-1);
      double dx = *(s+dims[0]) - *(s-dims[0]);
      double v = dx*dx + dy*dy;

      // second color channel
      s += dims[0]*dims[1]; // moves to the next channel
      double dy2 = *(s+1) - *(s-1);
      double dx2 = *(s+dims[0]) - *(s-dims[0]);
      double v2 = dx2*dx2 + dy2*dy2;

      // third color channel
      s += dims[0]*dims[1]; // moves to the next channel
      double dy3 = *(s+1) - *(s-1);
      double dx3 = *(s+dims[0]) - *(s-dims[0]);
      double v3 = dx3*dx3 + dy3*dy3;

      // pick channel with strongest gradient
      if (v2 > v) {
        v = v2;
        dx = dx2;
        dy = dy2;
      if (v3 > v) {
        v = v3;
        dx = dx3;
        dy = dy3;

      // snap to one of 18 orientations
      double best_dot = 0;
      int best_o = 0;
      for (int o = 0; o < 9; o++) {
        double dot = uu[o]*dx + vv[o]*dy;
        if (dot > best_dot) {
          best_dot = dot;
          best_o = o;
        } else if (-dot > best_dot) {
          best_dot = -dot;
          best_o = o+9;
      // add to 4 histograms around pixel using linear interpolation
      double xp = ((double)x+0.5)/(double)sbin - 0.5;
      double yp = ((double)y+0.5)/(double)sbin - 0.5;
      int ixp = (int)floor(xp);
      int iyp = (int)floor(yp);
      double vx0 = xp-ixp;
      double vy0 = yp-iyp;
      double vx1 = 1.0-vx0;
      double vy1 = 1.0-vy0;
      v = sqrt(v);

      if (ixp >= 0 && iyp >= 0) {
        *(hist + ixp*blocks[0] + iyp + best_o*blocks[0]*blocks[1]) += 

      if (ixp+1 < blocks[1] && iyp >= 0) {
        *(hist + (ixp+1)*blocks[0] + iyp + best_o*blocks[0]*blocks[1]) += 

      if (ixp >= 0 && iyp+1 < blocks[0]) {
        *(hist + ixp*blocks[0] + (iyp+1) + best_o*blocks[0]*blocks[1]) += 

      if (ixp+1 < blocks[1] && iyp+1 < blocks[0]) {
        *(hist + (ixp+1)*blocks[0] + (iyp+1) + best_o*blocks[0]*blocks[1]) += 

  // compute energy in each block by summing over orientations
  for (int o = 0; o < 9; o++) {
    double *src1 = hist + o*blocks[0]*blocks[1];
    double *src2 = hist + (o+9)*blocks[0]*blocks[1];
    double *dst = norm;
    double *end = norm + blocks[1]*blocks[0];
    while (dst < end) {
      *(dst++) += (*src1 + *src2) * (*src1 + *src2);

  // compute features
  for (int x = 0; x < out[1]; x++) {
    for (int y = 0; y < out[0]; y++) {
      double *dst = feat + x*out[0] + y;      
      double *src, *p, n1, n2, n3, n4;

      p = norm + (x+1)*blocks[0] + y+1;
      n1 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);
      p = norm + (x+1)*blocks[0] + y;
      n2 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);
      p = norm + x*blocks[0] + y+1;
      n3 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);
      p = norm + x*blocks[0] + y;      
      n4 = 1.0 / sqrt(*p + *(p+1) + *(p+blocks[0]) + *(p+blocks[0]+1) + eps);

      double t1 = 0;
      double t2 = 0;
      double t3 = 0;
      double t4 = 0;

      // contrast-sensitive features
      src = hist + (x+1)*blocks[0] + (y+1);
      for (int o = 0; o < 18; o++) {
        double h1 = min(*src * n1, 0.2);
        double h2 = min(*src * n2, 0.2);
        double h3 = min(*src * n3, 0.2);
        double h4 = min(*src * n4, 0.2);
        *dst = 0.5 * (h1 + h2 + h3 + h4);
        t1 += h1;
        t2 += h2;
        t3 += h3;
        t4 += h4;
        dst += out[0]*out[1];
        src += blocks[0]*blocks[1];

      // contrast-insensitive features
      src = hist + (x+1)*blocks[0] + (y+1);
      for (int o = 0; o < 9; o++) {
        double sum = *src + *(src + 9*blocks[0]*blocks[1]);
        double h1 = min(sum * n1, 0.2);
        double h2 = min(sum * n2, 0.2);
        double h3 = min(sum * n3, 0.2);
        double h4 = min(sum * n4, 0.2);
        *dst = 0.5 * (h1 + h2 + h3 + h4);
        dst += out[0]*out[1];
        src += blocks[0]*blocks[1];

      // texture features
      *dst = 0.2357 * t1;
      dst += out[0]*out[1];
      *dst = 0.2357 * t2;
      dst += out[0]*out[1];
      *dst = 0.2357 * t3;
      dst += out[0]*out[1];
      *dst = 0.2357 * t4;

      // truncation feature
      dst += out[0]*out[1];
      *dst = 0;

  return mxfeat;

// matlab entry point
// F = features(image, bin)
// image should be color with double values
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 
  if (nrhs != 2)
    mexErrMsgTxt("Wrong number of inputs"); 
  if (nlhs != 1)
    mexErrMsgTxt("Wrong number of outputs");
  plhs[0] = process(prhs[0], prhs[1]);

Thursday, 3 October 2013

Redirecting all traffic to add www prefix with Apache

It may be useful to add the "www." prefix automatically for all traffic if your visitors are not typing them. With Apache you need to have mod_rewrite enabled to use this method.

1. Allow mod_rewrite override for your current website. Go to your site configuration file (located at /etc/apache2/sites-enabled/000-default if you are using Ubuntu) and add the following lines into the <VirtualHost *:80> section:
<Directory /var/www/>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride all
    Order allow,deny
    allow from all
2. Go to your document root (e.g., /var/www), create a new file named .htaccess and with the following content:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
That's it. Restart Apache and it should work by now.

Installing JDK on Ubuntu

This is an example of how to install JDK on Ubuntu. I wrote this when I was using JDK 7 with Ubuntu 10.04 -- so you may want to check Oracle's website for the latest version.

1. Download one of the following files: (for 32-bit) (for 64-bit)

2. Decompress the .tar.gz file.

3. Move the JDK files to /usr/lib/jvm/jdk1.7.0 or somewhere else as appropriate.

4. Run from bash shell:
sudo vim /etc/environment
You will see something like
Change the file to something like (also change the installation path if needed)
And then reload .bashrc file:
source ~/.bashrc
5. Run the following commands from bash shell:
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.7.0/bin/java 300
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk1.7.0/bin/javac 300
sudo update-alternatives --install /usr/bin/javap javap /usr/lib/jvm/jdk1.7.0/bin/javap 300
sudo update-alternatives --install /usr/bin/javadoc javadoc /usr/lib/jvm/jdk1.7.0/bin/javadoc 300
Installation is now complete. Run the following command from bash shell for a test:
java -version

Upgrading/compiling OpenCV on Linux from source code and use with Eclipse

In order to upgrade your OpenCV to the latest version (versions on APT are usually obsolete), or if you modified the source code in OpenCV and need to recompile it, you can follow the following steps as an example:

1. Download the latest source tarball from OpenCV’s website.

2. Extract the .tar.gz file to a directory, say ~/opencv_src. This is just a temporary directory for the source code.

3. Create another directory for build files, say ~/opencv_build. Change to this directory (do not stay in the source folder). Make the build files using CMAKE (you may change the options where necessary):
Note: You could refer to CMakeLists.txt in ~/opencv_src for more options (for example, to install OpenNI support you need to set WITH_OPENNI to YES). Another important thing is to check OpenCV website for required APT packages. Install those packages using apt-get. Otherwise you will get some error information when trying to run the above command.

4. Should the command is executed successfully, you will have the build files. Note that we have set CMAKE_INSTALL_PREFIX to /usr. This is by default /usr/local but if we need to replace the old versions that comes with APT, we need to set the prefix to /usr. This is where apt-get installs programs. For /usr/local, it is usually for self-maintained packages. So actually it is up to you to use /usr or /usr/local.

5. Type “make” and “sudo make install” to install the files to the desired location. If we set prefix to /usr then files will be copied to locations like /usr/lib, /usr/include/opencv. The make command will take a little while.

You should have installed OpenCV now. Following steps are for using OpenCV with Eclipse CDT.

6. Open Eclipse (with CDT installed), create a new C++ project. And then click on Menu -> Project -> Properties -> C/C++ Build -> Settings -> Tool Settings. We need to change:

(1) GCC C++ Compiler -> Includes. Add “/usr/include/opencv”

(2) GCC C++ Linker -> Library search path. Add “/usr/lib”

(3) GCC C++ Linker -> Libraries. Add “opencv_core” and “opencv_highgui” (for a complete list of libraries available, check the libopencv_***.so files located at /usr/lib. When adding their names, simply remove "lib" at front and any extensions. For example, use "opencv_core" for "").

7. To give it a go, use the following sample program:
#include <highgui.h>

int main( int argc, char** argv )

 IplImage* img = cvLoadImage( "/path/to/an/image.jpg" ); // change this to a valid filename
 cvNamedWindow( "Example1", CV_WINDOW_AUTOSIZE );
 cvShowImage( "Example1", img );
 cvReleaseImage( &img );
 cvDestroyWindow( "Example1" );


C++ linking error with Linux 3.x

If you are linking your C/C++ program on Linux 3.x (e.g., Ubuntu 12.04), you may need to put the libraries at the end of the shell command, i.e.,
$(CC) -o $@ $+ $(OPT) $(LIBDIRS) $(LIBS)
(This is like if you use Makefile, same rule applies if you don't use Makefile)

For my example with OpenCV, here
INCLUDES = -I/usr/include/opencv
LIBS = -lcxcore -lcv -lcvaux -lhighgui -lml
LIBDIRS = -L/usr/lib
OPT = -O3 -Wno-deprecated
If you put $(LIBDIRS) and $(LIBS) earlier in this command, it would successfully link with earlier distros (I suppose those with Linux kernel version 2.x, such as Ubuntu 10.04), but not on the newer distros. As a result, you would get the following error message:
*****.cpp:(.text+0x2db3): undefined reference to `cvLoadImage'
*****.cpp:(.text+0x2ef7): undefined reference to `cvCreateImage'
*****.cpp:(.text+0x2feb): undefined reference to `cvCreateImage'
*****.cpp:(.text+0x3041): undefined reference to `cvConvertScale'
*****.cpp:(.text+0x3088): undefined reference to `cvSaveImage'
*****.cpp:(.text+0x3099): undefined reference to `cvReleaseImage'
*****.cpp:(.text+0x30ca): undefined reference to `cvReleaseImage'
*****.cpp:(.text+0x30f9): undefined reference to `cvReleaseImage'
That is, every function call in the libraries will end up with "undefined reference". Pretty tricky! I would appreciate if anyone points to me the stuff under the bonnet here.

Probing system memory info in MATLAB with Linux

I came across a MATLAB library lately which checks for available memory before proceeding, so that the algorithm knows how much memory it should use (e.g., use up to 10% of available memory).

On Windows the function memory() comes in handy for this need, while in Linux we will have to write a few lines of code.
function [ totalmem, freemem ] = linuxMemory()
% Usage: No input arguments needed.
% Returns total and free memory in Kilobytes.

    % probe system memory information
    [~,meminfo] = system('cat /proc/meminfo');

    % get total memory
    tokens = regexpi(meminfo,'^MemTotal:\s*(\d+)\s', 'tokens');
    totalmem = str2double(tokens{1}{1});

    % get available memory
    tokens = regexpi(meminfo,'^*MemFree:\s*(\d+)\s','tokens');
    freemem = str2double(tokens{1}{1});