Adds histogram support to 3 channels images

compute_histogram support is available.
hist2table support is available
hist2image still to be performed. 

Function for 3c to 1c to be added quickly!

Reported-by: Julien Lengrand-Lambert <julien@lengrand.fr>
Signed-off-by: Julien Lengrand-Lambert <julien@lengrand.fr>
This commit is contained in:
Julien Lengrand-Lambert
2011-12-16 17:49:19 +01:00
parent 1892bd6945
commit 335108ecf6
3 changed files with 65 additions and 37 deletions

View File

@@ -23,12 +23,10 @@ import cv
import tippy.statistics as st
import tippy.display_operations as do
hist = st.Histogram()
img_name = "tippy/data/gnu.jpg"
img = cv.LoadImage(img_name, cv.CV_LOAD_IMAGE_GRAYSCALE)
hist.compute_histogram(img)
img = cv.LoadImage(img_name, cv.CV_LOAD_IMAGE_COLOR)
hist = st.Histogram(img)
hist_img = hist.hist2image()
do.display_single_image(hist_img, "Gray-Level histogram of the gnu image")
do.display_single_image(hist_img[0], "Gray-Level histogram of the gnu image")

View File

@@ -18,12 +18,13 @@ class Histogram():
NOTE : Supports only 1 channel / 8 bits images for now.
More should be added soon.
"""
def __init__(self):
def __init__(self, img, bin_fact=cv.IPL_DEPTH_8U, min_range=0):
self.cvhist = None
self.min_range = 0
self.depth = cv.IPL_DEPTH_8U
self.nb_bins = 0
self.channels = 0
self.compute_histogram(img, bin_fact, min_range)
def compute_histogram(self, img, bin_fact=cv.IPL_DEPTH_8U, min_range=0):
"""
@@ -40,7 +41,7 @@ class Histogram():
"""
# TESTS
try:
cv.GetSize(img)
dims = cv.GetSize(img)
except TypeError:
raise TypeError("(%s) img : IplImage expected!"
% (sys._getframe().f_code.co_name))
@@ -49,10 +50,9 @@ class Histogram():
if not(img.depth == cv.IPL_DEPTH_8U):
raise TypeError("(%s) 8U image expected!"
% (sys._getframe().f_code.co_name))
elif not(img.nChannels is 1):
raise TypeError("(%s) 1C image expected!"
% (sys._getframe().f_code.co_name))
if img.nChannels not in [1, 3]:
raise ValueError("(%s) 1 or 3 channels image expected!"
% (sys._getframe().f_code.co_name))
# bin_fact test
if (bin_fact <= 0 or ((bin_fact % 2) != 0)):
raise ValueError("(%s) Positive odd integer expected!"
@@ -71,15 +71,41 @@ class Histogram():
self.depth = int(img.depth)
max_range = pow(2, self.depth)
self.ranges = [min_range, max_range]
img_list = []
# preparing images depending on nChannels
if self.channels == 1:
img_list = [img]
elif self.channels == 3:
# TODO: change this into function
img_1 = cv.CreateImage(dims, cv.IPL_DEPTH_8U, 1)
img_2 = cv.CreateImage(dims, cv.IPL_DEPTH_8U, 1)
img_3 = cv.CreateImage(dims, cv.IPL_DEPTH_8U, 1)
cv.Split(img, img_1, img_2, img_3, None)
img_list = [img_1, img_2, img_3]
self.cvhist = self._compute_1ch_histogram(img_list)
def _compute_1ch_histogram(self, img_list):
"""
DESIGNED FOR INTERNAL USE ONLY
CAREFUL, NO VERIFICATIONS PERFORMED
"""
dims = [self.nb_bins]
all_ranges = [self.ranges]
self.cvhist = cv.CreateHist( dims,
cv.CV_HIST_ARRAY,
all_ranges,
uniform=1)
cv.CalcHist([img], self.cvhist)
hist_list = []
for img in img_list:
hist = cv.CreateHist( dims,
cv.CV_HIST_ARRAY,
all_ranges,
uniform=1)
cv.CalcHist([img], hist)
hist_list.append(hist)
return hist_list
def hist2table(self):
"""
@@ -94,9 +120,11 @@ class Histogram():
% (sys._getframe().f_code.co_name))
histable = []
for jj in range(self.nb_bins):
histable.append(self.cvhist.bins[jj])
for ii in range(self.channels):
hist_list = []
for jj in range(self.nb_bins):
hist_list.append(self.cvhist[ii].bins[jj])
histable.append(hist_list)
return histable
def hist2image(self, scale_x=3, scale_y=3, y_range=64):

View File

@@ -17,7 +17,8 @@ class Test(unittest.TestCase):
This method is called before each test
"""
self.img_1c = cv.LoadImage("data/tippy.jpg", cv.CV_LOAD_IMAGE_GRAYSCALE) # 1 channel image
self.img_3c = cv.LoadImage("data/tippy.jpg", cv.CV_LOAD_IMAGE_COLOR) # 3 channel image
self.img_3c = cv.LoadImage("data/tippy.jpg", cv.CV_LOAD_IMAGE_COLOR) # 3 channel image
self.img_2c = cv.CreateImage((10, 10), cv.IPL_DEPTH_8U, 2) # fake 2 channels image
self.img_16s = cv.CreateImage((15, 15), cv.IPL_DEPTH_16S, 1) # Non 8 bits image
self.val = 10 # non Image
@@ -33,34 +34,35 @@ class Test(unittest.TestCase):
#---
## TESTS
def test_compute_histogram(self):
hist = st.Histogram()
# testing input image
self.assertRaises(TypeError, lambda:hist.compute_histogram(self.val) )
self.assertRaises(TypeError, lambda:hist.compute_histogram(self.img_3c))
self.assertRaises(TypeError, lambda:st.Histogram(self.val) )
self.assertRaises(TypeError, lambda:st.Histogram(self.img_16s) )
self.assertRaises(ValueError, lambda:st.Histogram(self.img_2c) )
# testing bin_fact
self.assertRaises(ValueError,
lambda: hist.compute_histogram(self.img_1c, self.neg_val))
lambda: st.Histogram(self.img_1c, self.neg_val))
self.assertRaises(TypeError,
lambda: hist.compute_histogram(self.img_1c, self.string))
lambda: st.Histogram(self.img_1c, self.string))
# testing min_range. It can be either negative or even.
self.assertRaises(TypeError,
lambda: hist.compute_histogram(self.img_1c, self.val, self.string))
lambda: st.Histogram(self.img_1c, self.val, self.string))
# testing output
hist_1c = st.Histogram(self.img_1c)
self.assertEquals(self.img_1c.nChannels, hist_1c.channels)
hist_3c = st.Histogram(self.img_3c)
self.assertEquals(self.img_3c.nChannels, hist_3c.channels)
def test_hist2table(self):
hist = st.Histogram()
# testing input histogram
self.assertRaises(TypeError, lambda: hist.hist2table(self.val))
# testing output size
hist.compute_histogram(self.img_1c)
hist = st.Histogram(self.img_3c)
histable = hist.hist2table()
self.assertEqual(256, len(histable))
self.assertEqual(3, len(histable))
self.assertEqual(256, len(histable[0]))
def test_hist2image(self):
hist = st.Histogram()
# testing input histogram
self.assertRaises(TypeError, lambda: hist.hist2image(self.val))
def test_hist2image(self):
hist = st.Histogram(self.img_1c)
# testing scale inputs
self.assertRaises(TypeError,
lambda: hist.hist2image(hist, self.string))