I want to segment images (from magazines) in text and image parts. I have several histograms for several ROIs in my picture. I use opencv with python (cv2).
I want to recognize histograms that look like this
http://matplotlib.sourceforge.net/users/image_tutorial-6.png
as it is a typical shape for a text region. How can I do that?
Edit: Thank you for your help so far.
I compared the histograms I got from my ROIs to a sample histogram I provided:
hist = cv2.calcHist(roi,[0,1], None, [180,256],ranges)
compareValue = cv2.compareHist(hist, samplehist, cv.CV_COMP_CORREL)
print "ROI: {0}, compareValue: {1}".format(i,compareValue)
Assuming ROI 0, 1, 4 and 5 are text regions and ROI is an image region, I get output like this:
What can I do to avoid wrong classification? For some images, the misclassification rate is about 30%, which is way too high.
(I tried also with CV_COMP_CHISQR, CV_COMP_INTERSECT, CV_COMP_BHATTACHARYY and (hist*samplehist).sum() but they also provide wrong compareValues)
(See the EDIT at the end in case i misunderstood the question) :
If you are looking to draw the histograms, I had submitted one python sample to OpenCV, and you can get it from here :
http://code.opencv.org/projects/opencv/repository/entry/trunk/opencv/samples/python2/hist.py
It is used to draw two kinds of histograms. First one applicable to both color and grayscale images as shown here : http://opencvpython.blogspot.in/2012/04/drawing-histogram-in-opencv-python.html
Second one is exclusive for grayscale image which is same as your image in the question.
I will show the second and its modification.
Consider a full image as below :
We need to draw a histogram as you have shown. Check the below code:
import cv2
import numpy as np
img = cv2.imread('messi5.jpg')
mask = cv2.imread('mask.png',0)
ret,mask = cv2.threshold(mask,127,255,0)
def hist_lines(im,mask):
h = np.zeros((300,256,3))
if len(im.shape)!=2:
print "hist_lines applicable only for grayscale images"
#print "so converting image to grayscale for representation"
im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
hist_item = cv2.calcHist([im],[0],mask,[256],[0,255])
cv2.normalize(hist_item,hist_item,0,255,cv2.NORM_MINMAX)
hist=np.int32(np.around(hist_item))
for x,y in enumerate(hist):
cv2.line(h,(x,0),(x,y),(255,255,255))
y = np.flipud(h)
return y
histogram = hist_lines(img,None)
And below is the histogram we got. Remember it is histogram of full image. For that,we have given None
for mask.
Now I want to find the histogram of some part of the image. OpenCV histogram function has got a mask facility for that. For normal histogram, you should set it None
. Otherwise you have to specify the mask.
Mask is a 8-bit image, where white denotes that region should be used for histogram calculations, and black means it should not.
So I used a mask like below ( created using paint, you have to create your own mask for your purposes).
I changed the last line of code as below :
histogram = hist_lines(img,mask)
Now see the difference below :
(Remember, values are normalized, so values shown are not actual pixel count, normalized to 255. Change it as you like.)
EDIT :
I think i misunderstood your question. You need to compare histograms, right ?
If that is what you wanted, you can use cv2.compareHist
function.
There is an official tutorial about this in C++. You can find its corresponding Python code here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With