首页 > 解决方案 > 如何使用合并的 bin 计算直方图?

问题描述

我想问你关于使用 OpenCV 在 Python 中计算直方图的问题。我使用了这段代码:

hist = cv2.calcHist(im, [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])

结果给了我每个颜色通道的直方图,有 8 个 bin,但我想要得到的是:

所以我总共有 512 个垃圾箱。

标签: pythonimageopencvimage-processinghistogram

解决方案


From my point of view, your cv2.calcHist call isn't correct:

hist = cv2.calcHist(im, [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])

The first parameter should be a list of images:

hist = cv2.calcHist([im], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])

Let's see this small example:

import cv2
import numpy as np

# Red blue square of size [4, 4], i.e. eight pixels (255, 0, 0) and eight pixels (0, 0, 255); Attention: BGR ordering!
image = np.zeros((4, 4, 3), dtype=np.uint8)
image[:, 0:2, 2] = 255
image[:, 2:4, 0] = 255

# Calculate histogram with two bins [0 - 127] and [128 - 255] per channel:
# Result should be hist["bin 0", "bin 0", "bin 1"] = 8 (red) and hist["bin 1", "bin 0", "bin 0"] = 8 (blue)

# Original cv2.calcHist call with two  bins [0 - 127] and [128 - 255]
hist = cv2.calcHist(image, [0, 1, 2], None, [2, 2, 2], [0, 256, 0, 256, 0, 256])
print(hist, '\n')       # Not correct

# Correct cv2.calcHist call
hist = cv2.calcHist([image], [0, 1, 2], None, [2, 2, 2], [0, 256, 0, 256, 0, 256])
print(hist, '\n')       # Correct
[[[8. 0.]
  [0. 0.]]

 [[0. 0.]
  [0. 4.]]] 

[[[0. 8.]
  [0. 0.]]

 [[8. 0.]
  [0. 0.]]] 

As you can, your version only has 12 values in total, whereas there are 16 pixels in the image! Also, it's not clear, what "bins" (if at all) are represented.

So, having the proper cv2.calcHist call, your general idea/approach is correct! Maybe, you just need a little hint, "how to read" the resuling hist:

import cv2
import numpy as np

# Colored rectangle of size [32, 16] with one "color" per bin for eight bins per channel,
# i.e. 512 pixels, such that each of the resulting 512 bins has value 1
x = np.linspace(16, 240, 8, dtype=np.uint8)
image = np.reshape(np.moveaxis(np.array(np.meshgrid(x, x, x)), [0, 1, 2, 3], [3, 0, 1, 2]), (32, 16, 3))

# Correct cv2.calcHist call
hist = cv2.calcHist([image], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])

# Lengthy output of each histogram bin
for B in np.arange(hist.shape[0]):
    for G in np.arange(hist.shape[1]):
        for R in np.arange(hist.shape[2]):
            r = 'R=' + str(R*32).zfill(3) + '-' + str((R+1)*32-1).zfill(3)
            g = 'G=' + str(G*32).zfill(3) + '-' + str((G+1)*32-1).zfill(3)
            b = 'B=' + str(B*32).zfill(3) + '-' + str((B+1)*32-1).zfill(3)
            print('(' + r +  ', ' + g + ', ' + b + '): ', int(hist[B, G, R]))
(R=000-031, G=000-031, B=000-031):  1
(R=032-063, G=000-031, B=000-031):  1
(R=064-095, G=000-031, B=000-031):  1
[... 506 more lines ...]
(R=160-191, G=224-255, B=224-255):  1
(R=192-223, G=224-255, B=224-255):  1
(R=224-255, G=224-255, B=224-255):  1

Hope that helps!


推荐阅读