Friday, April 16, 2010

Nice Linux PDF manipulation utilities

I found myself writing many reports with LaTex lately. Using pdflatex has it advantages, but things can get quite annoying when one wants to insert a figure which was generated in Matlab or any other program.

Specially, MATLab does not do a nice job when exporting PDFs and leaves a whole blank area (the page itself actually) which is not desirable if we want to put a figure in a latex document. Fortunately, there is a linux program called pdfcrop that does the job correctly (not 100% trustable, but 90% of the times I get good results).

Another useful program is pdfimages, which extracts images from a pdf file. The pdfimages output is generally in huge pgm files, so it's better to convert it to something like png which results in smaller files, still usable with pdflatex.

Finally, pdfjoin and pdf90 allows one to join several files into a single one and rotate pages respectively. The Ubuntu package for these two is called pdfjam.

Wednesday, March 10, 2010

Ultra simple incremental backups with rsync

Recently I bought an external hard drive for backups. While searching for the best way to do the backups I found rsync, which looks well suited for these tasks.
Then I found this webpage that provides some scripts to achieve circular snapshots.

However, most scripts on the web are extremely large and complex compared to what I need. So finally I made my own script that makes automated incremental backups, with no cycling but keeping a history file to identify each backup.

Here is the code:


This script will create backup directories called backup.xxxx, where xxxx is the backup number. This number is zero for the first backup done. Rsync hard-links the unchanged files to the previous backup which is a key method to save space.

With this script I am backuping a NTFS partition and that's why the option --modify-window=1 is needed in rsyncFlags. It is important to write sourceDir without a trailing forward slash!

In order to provide easy access to the last backup, a symbolic link called HEAD will point to the latest backup. Additionally, a file called backup-history holds the exact time and date where each backup was performed.

NOTE: I am not responsible for this script and it's correctness. There might be problems such as if there are backup.something folders or files in the backup directory where the script is called, and other bugs that may arise. This is a very simple and minimalistic script!

Monday, March 1, 2010

Merging Qt and Eigen

Again in ViBOT, image segmentation assignment, Matlab is really slow, wait minutes for results...

So I decided to try to use Qt for the GUI and OS abstraction layer together with Eigen which is another amazing template-based library for matrix manipulation. The important code to write was to link both libraries, taking advantage of Qt's amazing QImage class which is able to open several file formats and perform low-level pixel access. In a few words, I had to put all the image information contained in QImage into a Eigen's matrix.

Luckily, this task is very simple. Here there is some code:



#ifndef MIMG_H
#define MIMG_H

USING_PART_OF_NAMESPACE_EIGEN

#include <QImage>

#include <Eigen/Core>
#include <Eigen/Array>

//general type, maybe float or double needed
typedef MatrixXf MImgType;

class MImg
{
public:
//creates an all-black image
MImg(unsigned int h, unsigned int w);

//creates image from QImage
MImg( const QImage &img );

MImgType R,G,B; //each component
//made public for faster access

unsigned int getHeight();
unsigned int getWidth();

QImage * toQImage(); //convert to QImage

/**
Maximizes dynamic range of three channels
independently!
**/
void maximizeIndependentDynamicRange();

private:
unsigned int mH,mW; //height, width

};

#endif // MIMG_H


#include "mimg.h"

MImg::MImg(unsigned int h, unsigned int w)
{
R = MImgType::Zero(h,w);
G = MImgType::Zero(h,w);
B = MImgType::Zero(h,w);

mH = h;
mW = w;
}

MImg::MImg( const QImage &img )
{
int w = img.width();
int h = img.height();

R = MImgType::Zero(h,w);
G = MImgType::Zero(h,w);
B = MImgType::Zero(h,w);

//now copy values..
for (int y=0; y < h; y++)
for (int x=0; x < w; x++)
{
QRgb color = img.pixel(x,y);
R(y,x) = qRed(color)/255.0;
G(y,x) = qGreen(color)/255.0;
B(y,x) = qBlue(color)/255.0;
}

return img;
}

void MImg::maximizeIndependentDynamicRange()
{
double min, max;

min = R.minCoeff(); max = R.maxCoeff();
R = (R.cwise() - min) / (max - min);

min = G.minCoeff(); max = G.maxCoeff();
G = (G.cwise() - min) / (max - min);

min = B.minCoeff(); max = B.maxCoeff();
B = (B.cwise() - min) / (max - min);
}

unsigned int MImg::getHeight() {
return mH;
}

unsigned int MImg::getWidth() {
return mW;
}



It is important to mention that this code only handles RGB and won't care about grayscale images or any other type of colour models. The advantage of having the image in this matrix form is that Eigen provides an easy syntax for matrix manipulation, along with many modules performing least squares, Cholesky, diagonalization, etc.