close

# OpenCV-Python

### OpenCV Python Tutorials

opencvpython.blogspot.com

## Histograms - 4 : Backprojection

Hi friends,

Today, we will look into histogram back-projection. It was proposed by Michael J. Swain , Dana H. Ballard in their paper "Indexing via color histograms".

Well, what is it actually in simple words? It is used for image segmentation or finding objects of interest in an image. In simple words, it creates an image of the same size (but single channel) as that of our input image, where each pixel corresponds to the probability of that pixel belonging to our object. So in short, the output image will have our object of interest in white and remaining part in black. Well, that is an intuitive explanation.

(In this article, I would like to use a beautiful image of a bunch of rose flowers. And the image credit goes to "mi9.com". You can get the image from this link : http://imgs.mi9.com/uploads/flower/4649/rose-flower-wallpaper-free_1920x1080_83181.jpg)

How do we do it ? We create a histogram of an image containing our object of interest (in our case, the rose flower, leaving leaves and background). The object should fill the image as far as possible for better results. And a color histogram is preferred over grayscale histogram, because color of the object is more better way to define the object than its grayscale intensity. ( A red rose flower and its green leaves may have same intensity in grayscale images, but easily distinguishable in color image). We then "back-project" this histogram over our test image where we need to find the object, ie in other words, we calculate the probability of every pixel belonging to rose flower and show it. The resulting output on proper thresholding gives us the rose flower alone.

So let's see how it is done.

Algorithm :

1 - First we need to calculate the color histogram of both the object we need to find (let it be 'M') and the image where we are going to search (let it be 'I').

`import cv2import numpy as npfrom matplotlib import pyplot as plt#roi is the object or region of object we need to findroi = cv2.imread('rose_red.png')hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)#target is the image we search intarget = cv2.imread('rose.png')hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)# Find the histograms. I used calcHist. It can be done with np.histogram2d alsoM = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )I = cv2.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] )`

2 - Find the ratio R = M/I

`R = M/(I+1)`

3 - Now backproject R, ie use R as palette and create a new image with every pixel as its corresponding probability of being target. ie B(x,y) = R[h(x,y),s(x,y)] where h is hue and s is saturation of the pixel at (x,y). After that apply the condition B(x,y) = min[B(x,y), 1].

`h,s,v = cv2.split(hsvt)B = R[h.ravel(),s.ravel()]B = np.minimum(B,1)B = B.reshape(hsvt.shape[:2])`

4 - Now apply a convolution with a circular disc, B = D * B, where D is the disc kernel.

`disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))cv2.filter2D(B,-1,disc,B)B = np.uint8(B)cv2.normalize(B,B,0,255,cv2.NORM_MINMAX)`

5 - Now the location of maximum intensity gives us the location of object. If we are expecting a region in the image, thresholding for a suitable value gives a nice result.

`ret,thresh = cv2.threshold(B,50,255,0)`

Below is one example I worked with. I used the region inside blue rectangle as sample object and I wanted to extract all the red roses. See, ROI is filled with red color only :

 Histogram Backprojection

Backprojection in OpenCV

OpenCV provides an inbuilt function cv2.calcBackProject(). Its parameters are almost same as the cv2.calcHist() function. One of its parameter is histogram which is histogram of the object and we have to find it. Also, the object histogram should be normalized before passing on to the backproject function. It returns the probability image. Then we convolve the image with a disc kernel and apply threshold. Below is my code and output :

`import cv2import numpy as nproi = cv2.imread('rose_green.png')hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)target = cv2.imread('rose.png')hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)# calculating object histogramroihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )# normalize histogram and apply backprojectioncv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)# Now convolute with circular discdisc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))cv2.filter2D(dst,-1,disc,dst)# threshold and binary ANDret,thresh = cv2.threshold(dst,50,255,0)thresh = cv2.merge((thresh,thresh,thresh))res = cv2.bitwise_and(target,thresh)res = np.vstack((target,thresh,res))cv2.imwrite('res.jpg',res)`

Below is the output. Here ROI is not just flower, but some green part is also included. Still output is good. On close analysis of the center image, you can see the leaf parts slightly which will be removed on threshold :

 Histogram Backprojection in OpenCV

Summary

So we have looked on what is Histogram backprojection, how to calculate it, how it is useful in object detection etc. It is also used in more advanced object tracking methods like camshift. We will do that later.

Regards,
Abid Rahman K.

References :

1 - "Indexing via color histograms", Swain, Michael J. , Third international conference on computer vision,1990.
2 - http://www.codeproject.com/Articles/35895/Computer-Vision-Applications-with-C-Part-II
3 - http://theiszm.wordpress.com/tag/backprojection/

## Skeletonization using OpenCV-Python

I see people asking an algorithm for skeletonization very frequently. At first, I had no idea about it. But today, I saw a which demonstrates simple method to do this. Code was in C++, so I would like to convert it to Python here.

What is Skeletonization?

Answer is just right in the term. Simply, it make a thick blob very thin, may be one pixel width. Visit the wikipedia page for more details : Topological Skeleton

Code :

`import cv2import numpy as npimg = cv2.imread('sofsk.png',0)size = np.size(img)skel = np.zeros(img.shape,np.uint8)ret,img = cv2.threshold(img,127,255,0)element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))done = Falsewhile( not done):    eroded = cv2.erode(img,element)    temp = cv2.dilate(eroded,element)    temp = cv2.subtract(img,temp)    skel = cv2.bitwise_or(skel,temp)    img = eroded.copy()    zeros = size - cv2.countNonZero(img)    if zeros==size:        done = Truecv2.imshow("skel",skel)cv2.waitKey(0)cv2.destroyAllWindows()`

Below is the result I got:

References :

1) http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/

## Drawing Histogram in OpenCV-Python

Hi Friends,

Do you want to draw a histogram for an image as below?

See the histogram for above image for RGB channels.

The code:

`import cv2import numpy as npimg = cv2.imread('zzzyj.jpg')h = np.zeros((300,256,3))bins = np.arange(256).reshape(256,1)color = [ (255,0,0),(0,255,0),(0,0,255) ]for ch, col in enumerate(color):    hist_item = cv2.calcHist([img],[ch],None,[256],[0,256])    cv2.normalize(hist_item,hist_item,0,255,cv2.NORM_MINMAX)    hist=np.int32(np.around(hist_item))    pts = np.column_stack((bins,hist))    cv2.polylines(h,[pts],False,col)h=np.flipud(h)cv2.imshow('colorhist',h)cv2.waitKey(0)`

You can see the same code written using numpy functions on histogram here  : Drawing histogram in OpenCV- Python.

With Regards,
Abid Rahman K.

## Simple Digit Recognition OCR in OpenCV-Python

Hi Friends,

It is  a long since i have posted an article.

Now i present you a Simple Digit Recognition OCR using kNearestNeighbour features in OpenCV-Python.

It demonstrats how to train the data and recongnize digits from previously trained data.

The code is using new Python interface, cv2. ( OpenCV v 2.3+)

The code and explanation can be found here:

# Simple Digit Recognition OCR in OpenCV-Python

Test Image:

Result image:

Abid Rahman K.

## Contour features

For more details on contours, visit :

1) Contours - 1 : Getting Started

2) Contours - 2 : Brotherhood

''' filename : contourfeatures.py

This sample calculates some useful parameters of a contour. This is an OpenCV implementation of regionprops function in matlab with some additional features.

Benefit : Learn to find different parameters of a contour region.
Get familier with different contour functions in OpenCV.

Level : Beginner or Intermediate

Usage : python contourfeatures.py <image_file>

Abid Rahman 3/25/12 '''

import cv2
import numpy as np

class Contour:
''' Provides detailed parameter informations about a contour

Create a Contour instant as follows: c = Contour(src_img, contour)
where src_img should be grayscale image.

Attributes:

c.area -- gives the area of the region
c.parameter -- gives the perimeter of the region
c.moments -- gives all values of moments as a dict
c.centroid -- gives the centroid of the region as a tuple (x,y)
c.bounding_box -- gives the bounding box parameters as a tuple => (x,y,width,height)
c.bx,c.by,c.bw,c.bh -- corresponds to (x,y,width,height) of the bounding box
c.aspect_ratio -- aspect ratio is the ratio of width to height
c.equi_diameter -- equivalent diameter of the circle with same as area as that of region
c.extent -- extent = contour area/bounding box area
c.convex_hull -- gives the convex hull of the region
c.convex_area -- gives the area of the convex hull
c.solidity -- solidity = contour area / convex hull area
c.center -- gives the center of the ellipse
c.majoraxis_length -- gives the length of major axis
c.minoraxis_length -- gives the length of minor axis
c.orientation -- gives the orientation of ellipse
c.eccentricity -- gives the eccentricity of ellipse
c.filledImage -- returns the image where region is white and others are black
c.filledArea -- finds the number of white pixels in filledImage
c.convexImage -- returns the image where convex hull region is white and others are black
c.pixelList -- array of indices of on-pixels in filledImage
c.maxval -- corresponds to max intensity in the contour region
c.maxloc -- location of max.intensity pixel location
c.minval -- corresponds to min intensity in the contour region
c.minloc -- corresponds to min.intensity pixel location
c.meanval -- finds mean intensity in the contour region
c.leftmost -- leftmost point of the contour
c.rightmost -- rightmost point of the contour
c.topmost -- topmost point of the contour
c.bottommost -- bottommost point of the contour
c.distance_image((x,y)) -- return the distance (x,y) from the contour.
c.distance_image() -- return the distance image where distance to all points on image are calculated
'''
def __init__(self,img,cnt):
self.img = img
self.cnt = cnt
self.size = len(cnt)

# MAIN PARAMETERS

#Contour.area - Area bounded by the contour region'''
self.area = cv2.contourArea(self.cnt)

# contour perimeter
self.perimeter = cv2.arcLength(cnt,True)

# centroid
self.moments = cv2.moments(cnt)
if self.moments['m00'] != 0.0:
self.cx = self.moments['m10']/self.moments['m00']
self.cy = self.moments['m01']/self.moments['m00']
self.centroid = (self.cx,self.cy)
else:
self.centroid = "Region has zero area"

# bounding box
self.bounding_box=cv2.boundingRect(cnt)
(self.bx,self.by,self.bw,self.bh) = self.bounding_box

# aspect ratio
self.aspect_ratio = self.bw/float(self.bh)

# equivalent diameter
self.equi_diameter = np.sqrt(4*self.area/np.pi)

# extent = contour area/boundingrect area
self.extent = self.area/(self.bw*self.bh)

### CONVEX HULL ###

# convex hull
self.convex_hull = cv2.convexHull(cnt)

# convex hull area
self.convex_area = cv2.contourArea(self.convex_hull)

# solidity = contour area / convex hull area
self.solidity = self.area/float(self.convex_area)

### ELLIPSE  ###

self.ellipse = cv2.fitEllipse(cnt)

# center, axis_length and orientation of ellipse
(self.center,self.axes,self.orientation) = self.ellipse

# length of MAJOR and minor axis
self.majoraxis_length = max(self.axes)
self.minoraxis_length = min(self.axes)

# eccentricity = sqrt( 1 - (ma/MA)^2) --- ma= minor axis --- MA= major axis
self.eccentricity = np.sqrt(1-(self.minoraxis_length/self.majoraxis_length)**2)

### CONTOUR APPROXIMATION ###

self.approx = cv2.approxPolyDP(cnt,0.02*self.perimeter,True)

### EXTRA IMAGES ###

# filled image :- binary image with contour region white and others black
self.filledImage = np.zeros(self.img.shape[0:2],np.uint8)
cv2.drawContours(self.filledImage,[self.cnt],0,255,-1)

# area of filled image
filledArea = cv2.countNonZero(self.filledImage)

# pixelList - array of indices of contour region
self.pixelList = np.transpose(np.nonzero(self.filledImage))

# convex image :- binary image with convex hull region white and others black
self.convexImage = np.zeros(self.img.shape[0:2],np.uint8)
cv2.drawContours(self.convexImage,[self.convex_hull],0,255,-1)

### PIXEL PARAMETERS

# mean value, minvalue, maxvalue

### EXTREME POINTS ###

# Finds the leftmost, rightmost, topmost and bottommost points
self.leftmost = tuple(self.cnt[self.cnt[:,:,0].argmin()][0])
self.rightmost = tuple(self.cnt[self.cnt[:,:,0].argmax()][0])
self.topmost = tuple(self.cnt[self.cnt[:,:,1].argmin()][0])
self.bottommost = tuple(self.cnt[self.cnt[:,:,1].argmax()][0])
self.extreme = (self.leftmost,self.rightmost,self.topmost,self.bottommost)

### DISTANCE CALCULATION

def distance_image(self,point=None):

'''find the distance between a point and adjacent point on contour specified. Point should be a tuple or list (x,y)
If no point is given, distance to all point is calculated and distance image is returned'''
if type(point) == tuple:
if len(point)==2:
self.dist = cv2.pointPolygonTest(self.cnt,point,True)
return self.dist
else:
dst = np.empty(self.img.shape)
for i in xrange(self.img.shape[0]):
for j in xrange(self.img.shape[1]):
dst.itemset(i,j,cv2.pointPolygonTest(self.cnt,(j,i),True))

dst = dst+127
dst = np.uint8(np.clip(dst,0,255))

# plotting using palette method in numpy
palette = []
for i in xrange(256):
if i<127:
palette.append([2*i,0,0])
elif i==127:
palette.append([255,255,255])
elif i>127:
l = i-128
palette.append([0,0,255-2*l])
palette = np.array(palette,np.uint8)
self.h2 = palette[dst]
return self.h2

#### DEMO ######
if __name__=='__main__':

import sys
if len(sys.argv)>1:
image = sys.argv[1]
else:
image = 'new.bmp'
print "Usage : python contourfeatures.py <image_file>"

imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
k = 1000
for cnt in contours:

# first shows the original image
im2 = im.copy()
c = Contour(imgray,cnt)
print c.leftmost,c.rightmost
cv2.putText(im2,'original image',(20,20), cv2.FONT_HERSHEY_PLAIN, 1.0,(0,255,0))
cv2.imshow('image',im2)
if cv2.waitKey(k)==27:
break

im2 = im.copy()

# Now shows original contours, approximated contours, convex hull
cv2.drawContours(im2,[cnt],0,(0,255,0),4)
string1 = 'green : original contour'
cv2.putText(im2,string1,(20,20), cv2.FONT_HERSHEY_PLAIN, 1.0,(0,255,0))
cv2.imshow('image',im2)
if cv2.waitKey(k)==27:
break

approx = c.approx
cv2.drawContours(im2,[approx],0,(255,0,0),2)
string2 = 'blue : approximated contours'
cv2.putText(im2,string2,(20,40), cv2.FONT_HERSHEY_PLAIN, 1.0,(0,255,0))
cv2.imshow('image',im2)
if cv2.waitKey(k)==27:
break

hull = c.convex_hull
cv2.drawContours(im2,[hull],0,(0,0,255),2)
string3 = 'red : convex hull'
cv2.putText(im2,string3,(20,60), cv2.FONT_HERSHEY_PLAIN, 1.0,(0,255,0))
cv2.imshow('image',im2)
if cv2.waitKey(k)==27:
break

im2 = im.copy()

# Now mark centroid and bounding box on image
(cx,cy) = c.centroid
cv2.circle(im2,(int(cx),int(cy)),5,(0,255,0),-1)
cv2.putText(im2,'green : centroid',(20,20), cv2.FONT_HERSHEY_PLAIN, 1.0,(0,255,0))

(x,y,w,h) = c.bounding_box
cv2.rectangle(im2,(x,y),(x+w,y+h),(0,0,255))
cv2.putText(im2,'red : bounding rectangle',(20,40), cv2.FONT_HERSHEY_PLAIN, 1.0,(0,255,0))

(center , axis, angle) = c.ellipse
cx,cy = int(center[0]),int(center[1])
ax1,ax2 = int(axis[0]),int(axis[1])
orientation = int(angle)
cv2.ellipse(im2,(cx,cy),(ax1,ax2),orientation,0,360,(255,255,255),3)
cv2.putText(im2,'white : fitting ellipse',(20,60), cv2.FONT_HERSHEY_PLAIN, 1.0,(255,255,255))

cv2.circle(im2,c.leftmost,5,(0,255,0),-1)
cv2.circle(im2,c.rightmost,5,(0,255,0))
cv2.circle(im2,c.topmost,5,(0,0,255),-1)
cv2.circle(im2,c.bottommost,5,(0,0,255))
cv2.imshow('image',im2)
if cv2.waitKey(k)==27:
break

# Now shows the filled image, convex image, and distance image
filledimage = c.filledImage
cv2.putText(filledimage,'filledImage',(20,20), cv2.FONT_HERSHEY_PLAIN, 1.0,255)
cv2.imshow('image',filledimage)
if cv2.waitKey(k)==27:
break

conveximage = c.convexImage
cv2.putText(conveximage,'convexImage',(20,20), cv2.FONT_HERSHEY_PLAIN, 1.0,255)
cv2.imshow('image',conveximage)
if cv2.waitKey(k)==27:
break

distance_image = c.distance_image()
cv2.imshow('image',distance_image)
cv2.putText(distance_image,'distance_image',(20,20), cv2.FONT_HERSHEY_PLAIN, 1.0,(255,255,255))
if cv2.waitKey(k)==27:
break

cv2.destroyAllWindows()

## Welcome to OpenCV-Python !!!

Welcome to OpenCV-Python !!!
This site provides some tutorials and examples on OpenCV-Python for absolute beginners.

Why this blog?

I started learning OpenCV a few months back. Before that, I used MATLAB for all my image processing purposes. The experience of shifting from MATLAB to OpenCV was amazing. Since i am a Python fan, I decided to use Python-bindings of OpenCV.

But as a beginner, I found a main problem in front of me. There are plenty of OpenCV tutorials available online for beginners, but most of them uses C++ for example codes. I couldn't find a single tutorial in Python for OpenCV. I could find a lot of OpenCV code in Python scattered online, but none of them was good for a beginner to start with. The best one I could find was none other than OpenCV-Python documentation. But it only lists the functions, not the examples using them.

Finally, I decided to start with C++ tutorials itself. I started to convert those codes from C++ to Python with the help of OpenCV-Python documentation. I decided to start a site or blog which shows the route i travelled to learn OpenCV so that it could be really helpful to the beginners. And here is the result.

Remember, I am also a beginner in OpenCV and I am still learning its basics. Here, what I am doing is, to give you only the outline ideas for a beginner to start with. For in-depth understanding, surely, I am not the right person to explain. But I know some good places where you can find them and I will share it with you as far as possible.

Some basic assumptions...

#### Here, I have made some assumptions...

1. You already know Python very well.
Remember, this site only provides tutorial on OpenCV only, not on Python. So make sure, you have studied Python before beginning this site.
Also, if you are good in C++, I would recommend you to use OpenCV in C++ itself. OpenCV can be used in C also.

2. You are using Python 2.7, OpenCV 2.4 and its python-bindings.

I would recommend you to use Linux. It may be a little difficult at the beginning. But as time passes, you will enjoy it. You will feel the freedom of open-source.

Feel free to talk for a better output...

You can contact me at: abidrahman2@gmail.com

Hope you will enjoy here...

Regards,
Abid K.

## Report "OpenCV-Python"

Are you sure you want to report this post for ?

Cancel
×