Experiments with concepts of Image Processing

Car Pic in Matplotlib

I was using MacOS’s Preview to sign a PDF document and came across this amazing feature that lets you create a digital version of your signature by clicking a photo of it through your webcam. This intrigued me towards thinking what kind of technology goes into building a nifty feature like that. I haven’t been able to get all my answers yet but the following are a list of few things that I have learnt till now.

Setting up the Environment

I have primarily used Python 2.7.x for the experimentation. The following libraries are required :

- mahotas
- scikit-image
- matplotlib
- numpy

These libraries can be found on pip or any such python package manager.

Reading an image into memory

Image can be read by using mahotas.

1
2
3
import mahotas as mh
img = mh.imread('image.jpg')

The image is stored in the form of a multidimensional numpy array of pixels. This is useful when further processing is done on the image.

Displaying the image using pyplot

Displaying an image through various stages of processing can be useful and give insights into how the process affects the image.

1
2
import matplotlib.pyplot as plt
plt.imshow(img)

Converting an image from RGB to Gray scale

It’s difficult to handle a colour image during processing because the image becomes a 3-Dimensional array, this is usually solved by converting the image to a gray scale (“removing” the third dimension) where varying intensity of the gray colour represents the image.

1
2
from skimage import rgb2gray
img_gray = rgb2gray(img)

This function returns a numpy array of dtype float64. Care should be taken to convert it back into integer before performing tasks that require integer type values.

Converting an image array from float64 to uint8

Through the stages of processing, data type casting is a much used technique because of the varied kind of algorithms used.

1
2
import numpy as np
img_gray_int = (img_gray * 255).astype(np.uint8)
  • np.uint8 : Unsigned integer (0 to 255)
  • float64 : Double precision float: sign bit, 11 bits exponent, 52 bits mantissa

Experiment 1 : Object Detection

In order to detect an object, its borders should be detected first. For that purpose we use Gradient Vectors of pixels of an image. Roughly speaking, gradient vector is the change in x and y direction” of a pixel. Chris McCormick explains it beautifully in his blog.

Gradient vector can be calculated by using numpy’s gradient() method. This method returns two vectors of change in gradient x and gradient y respectively.

1
2
3
4
5
6
#X and Y gradients
gx, gy = np.gradient(img_gray)
#Calculating magnitude of the gradient vector
g = (gx ** 2 + gy ** 2) ** .5
#plotting g
plt.imshow(g)

Since gradient vector is the "change in x and y direction", the change will be maximum around borders in an image
The following was the outcome of the experiment:

Original Car Picture

Car in Gray Scale

Car Image after plotting g ~ magnitude of gradient vector shows borders

As can be seen we extract useful features of the image, step by step removing/ignoring the information we don’t need.

We followed the following steps :

  • Removed the colours by converting the image to gray scale
  • Replaced the pixel values by calculating pixel gradient
  • Calculated the gradient vector’s magnitude by the formula :
    g = (gx ** 2 + gy ** 2) ** .5
  • On plotting this magnitude, we can an image with borders clearly marked.

Arch Diaries : What to do when your virtual hard disk is out of memory in virtualbox?

So this happened while I was setting up my Arch Linux installation on Virtualbox. While installing LightDM I got an error saying there isn’t enough space in my / (root partition mounting point). My setup for the drive partition was :

1
2
3
4
5
NAME SIZE MOUNTPOINT
- sda
-- sda1 2GB /
-- sda2 2GB /home
-- sda3 1GB swap

I soon realised my mistake , I needed more space in my root partition but Virtualbox won’t allow me to increase the hardisk size. The only option would be to repeat the entire process ,
create a virtual machine with a larger hard drive --> install Arch.

I was looking for a smarter way to avoid repeating the entire procedure. Based on a hunch I created a new hard drive NewVirtualDisk.vdi for the Arch installation :
NewVirtualDisk

The new hard drive was mounted as /dev/sdb. My plan was to move the /home partition to the 8GB volume and give the entire 5GB to the / partition . This way both the root and home will have good amount of space.

The first step was to format the raw 8GB volume into ext4 and make a primary partition in it :

1
$ sudo mkfs.ext4 /dev/sdb #format /dev/sdb to ext4

1
2
3
4
5
$ sudo umount /dev/sdb
$ sudo fdisk /dev/sdb
$(fdisk console) p #print existing partition table
$(fdisk console) n #create a new partition
$(fdisk console) w #commit the changes

The new partition looked like this :

1
2
3
4
5
6
7
8
$ lsblk
NAME SIZE MOUNTPOINT
- sda
-- sda1 2GB /
-- sda2 2GB /home
-- sda3 1GB swap
- sdb
-- sdb1 8GB

Great now I had my hard drive and partitions ready, next step was to safely mount /home in /dev/sdb1 instead of current /dev/sda2.

Here comes the interesting part, for making changes to the mounting point of /home we need to first edit the fstab file which we generated during our installation.

The fstab or File Systems Table is a system configuration file that typically lists all available disk partitions indicating how they are to be initialized or otherwise integrated into the larger file system structure. It is read by mount command, which happens automatically at boot time to determine the overall file system structure.

fstab is found at /etc/fstab and can be set up in two modes , either using the uuid or label of the partitions. Both the label and uuid info of partitions can be found by :

1
$ lsblk -f

To make changes to fstab one needs root priviledges :

1
$ sudo nano /etc/fstab

In the fstab, we have to replace the label or uuid of sda2 with sdb1 in /home mount point section. This is how my fstab looked like after the changes :
fstab

As can be seen , /home is now supposed to be mounted on /dev/sdb1.

Now since the mount command reads fstab just a single unmounting and remounting process will mount /home correctly onto /dev/sdb1 but we need to change to / before we can unmount/mount /home because you can’t unmount the file system you are currently in.

1
2
3
$ cd / # switch to root
$ sudo umount /home
$ sudo mount /home

Doing lsblk now showed /home is correctly mounted on /dev/sdb1 but there was an issue, when I tried changing to my home directly it threw an error.

1
2
$ cd
error : could not find home/sanad

This error took me quite long to understand. What this meant was there was no sanad directory in our new /home. This was because the installation was done on sda2 and the entire folder of user sanad was there. What to do now? Simple, Copy all the contents of the folder from the other partition ! (by the way this was a hunch)

First I needed to mount the previous partition /dev/sda2 at a temporary place. Google helped me find that /mnt is used for the very same purpose.

1
2
$ sudo mount /dev/sda2 /mnt
$ sudo cp -r -v /mnt/sanad/ home/

The above did the trick. The new /home had all the settings , data of the user sanad. Everything should work fine right? This time when I tried to CD to home I got another error :

1
2
$ cd
error : permission denied

This was because I didn’t had enough permissions to read/execute/write to the sanad folder. A simple setting of ownerships and permissions fixed it.

1
2
3
4
5
6
7
$ sudo chown -R sanad home/sanad # change ownership of home folder to sanad
$ sudo chmod u+rwx home/sanad # give the read,write and execute permissions to the current owner (in this case 'sanad')
$ cd #change directory to home/sanad will work
$ ls -l #check permissions and ownership
total 8
drwx------ 2 root root 4096 Nov 3 11:59 lost+found
drwx------ 4 sanad root 4096 Nov 3 12:37 sanad

finally, cd took me to my home directory and I was able to use it normally :)

This is how the setup looked like after the last step:
final setup

This was just the first step, now the next steps would be :

1) Delete the partitions sda2 and sda3

2) Extend sda1 to use entire 5GB volume (by maybe using chroot and fdisk)

3) Resize the file system for the new size of the partition ( maybe resize2fs).

P.S. : I would like to thank amazing Arch Linux Community and OracleVirtualBox Team and Community for all their support. You guys rock! I am learning a lot by this method of self exploring because of DIY nature of Arch , thanks for that too.

Till then, stay tuned and Happy Hacking!

-Sanad
For corrections/suggestions : mohdsanadzakirizvi@gmail.com