17

I was just trying to draw histogram using new OpenCV Python interface ( cv2 ).

Below is the code i tried:

import cv2
import numpy as np
import time

img = cv2.imread('zzz.jpg')
h = np.zeros((300,256,3))
b,g,r = cv2.split(img)
bins = np.arange(256).reshape(256,1)
color = [ (255,0,0),(0,255,0),(0,0,255) ]

for item,col in zip([b,g,r],color):
    hist_item = cv2.calcHist([item],[0],None,[256],[0,255])
    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)

And it works fine. Below is the resulting histogram i obtained.

enter image description here


Then i modified the code a little bit.

ie changed the sixth line in code b,g,r = cv2.split(img) to b,g,r = img[:,:,0], img[:,:,1], img[:,:,2] (because it works a little faster than cv2.split).

Now the output is something different. Below is the output.

enter image description here


I checked the values of b,g,r from both the codes. They are same.

Difference lies in the output of cv2.calcHist. Result of hist_item is different in both the cases.

Question:

How does it happen? Why the result of cv2.calcHist is different when inputs are same?

EDIT

I tried a different code. Now, a numpy version of my first code.

import cv2
import numpy as np

img = cv2.imread('zzz.jpg')
h = np.zeros((300,256,3))
b,g,r = img[:,:,0],img[:,:,1],img[:,:,2]
bins = np.arange(257)
bin = bins[0:-1]
color = [ (255,0,0),(0,255,0),(0,0,255) ]

for item,col in zip([b,g,r],color):
    N,bins = np.histogram(item,bins)
    v=N.max()
    N = np.int32(np.around((N*255)/v))
    N=N.reshape(256,1)
    pts = np.column_stack((bin,N))
    cv2.polylines(h,[pts],False,col,2)

h=np.flipud(h)

cv2.imshow('img',h)
cv2.waitKey(0)

And the output is same as first one.

enter image description here

You can get my original image here: zzz.jpg

Thank you.

1 Answer 1

15

You should copy the array:

b,g,r = img[:,:,0].copy(), img[:,:,1].copy(), img[:,:,2].copy()

But, since calcHist() can accept channels parameter, you need not to split your img to three array.

import cv2
import numpy as np

img = 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,255])
    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)
Sign up to request clarification or add additional context in comments.

7 Comments

What is the need for copy? And what is meant by calcHist() accept channel parameter? What does it actually denote?
you can call cv2.calcHist([img],[CH],None,[256],[0,255]) to calculate the histogram of channel CH of img, that is img[:, :, CH]. You need to copy the array because data in img[:, :, 0] is not continuous.
you mean c_contiguous? What is its significance?
numpy is more efficent at manipulating arrays and is used in cv2. the python split operator doesn't keep all the data together. the copy operator collects them neatly.
but is it me or the image size is not 300 * 256?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.