图像直方图:查找、绘制、分析

  • Post author:
  • Post category:其他


使用OpenCV和Matplotlib函数绘制直方图 :cv.calcHist(),np.histogram()

直方图可以总体了解图像的强度分布。通过查看图像的直方图,您可以直观地了解该图像的对比度,亮度,强度分布等。直方图的左侧区域显示图像中较暗像素的数量,而右侧区域则显示明亮像素的数量。




一、寻找直方图

BINS:上面的直方图显示每个像素值的像素数,即从0到255。如果找介于0到15之间的像素数,然后找到16到31之间,…,240到255之间的像素数。只需要16个值即可表示直方图。因此,您要做的就是将整个直方图分成16个子部分,每个子部分的值就是其中所有像素数的总和。每个子部分都称为“ BIN”。在第一种情况下,bin的数量为256个(每个像素一个),而在第二种情况下,bin的数量仅为16个。BINS由OpenCV文档中的

histSize

术语表示。

DIMS:这是我们为其收集数据的参数的数量。在这种情况下,我们仅收集关于强度值的一件事的数据。所以这里是1。

RANGE:这是您要测量的强度值的范围。通常,它是[0,256],即所有强度值。

查找直方图的函数及其参数:

cv.calcHist(images,channels,mask,histSize,ranges[,hist [,accumulate]])

images:它是uint8或float32类型的源图像。它应该放在方括号中,即“ [img]”。channels:也以方括号给出。它是我们计算直方图的通道的索引。例如,如果输入为灰度图像,则其值为[0]。对于彩色图像,您可以传递[0],[1]或[2]分别计算蓝色,绿色或红色通道的直方图。

mask:图像掩码。为了找到完整图像的直方图,将其指定为“无”。但是,如果要查找图像特定区域的直方图,则必须为此创建一个掩码图像并将其作为掩码。

histSize:这表示BIN计数。需要放在方括号中。对于全尺寸,我们通过[256]。ranges:这是我们的RANGE。通常为[0,256]。

如:img=cv.imread(‘home.jpg’,0)

hist=cv.calcHist([img],[0],None,[256],[0,256])

还有hist,bins=np.histogram(img.ravel(),256,[0,256])也用来求直方图,对于一维直方图,hist = np.bincount(img.ravel(),minlength = 256)速度更快。

matplotlib.pyplot.hist()它直接找到直方图并将其绘制。无需使用

calcHist

()或np.histogram()函数来查找直方图。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('E:\\python opencv\\demo2\\a.jpg', 0)
cv.imshow('img', img)
plt.hist(img.ravel(), 256, [0, 256])
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

对于BGR图片:

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('E:\\python opencv\\demo2\\a.jpg')
cv.imshow('img', img)

color = ('b', 'g', 'r')
for i, col in enumerate(color):
    histr = cv.calcHist([img], [i], None, [256], [0, 256])
    plt.plot(histr, color= col)
    plt.xlim([0, 256])

plt.show()

cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述


掩码的应用

:查找需要的区域,需创建一个掩码图像,在你要找到直方图为白色,否则黑色。然后把这个作为掩码传递。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('E:\\python opencv\\demo2\\a.jpg', 0)
#创建掩码
mask = np.zeros(img.shape[0:2], np.uint8)
mask[0:250, 150:350] = 255
mask_img = cv.bitwise_and(img, img, mask=mask)
# 计算掩码区域和非掩码区域的直方图
# 检查作为掩码的第三个参数
hist_full = cv.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv.calcHist([img], [0], mask, [256], [0, 256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(mask_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

均衡

调节亮度

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('E:\\python opencv\\demo2\\wiki.png', 0)
cv.imshow('img', img)

hist, bins = np.histogram(img.flatten(), 256, [0, 256])
cdf = hist.cumsum()
cdf_normalized = cdf*float(hist.max())/cdf.max()
plt.subplot(2, 1, 1), plt.plot(cdf_normalized, color='b')
plt.hist(img.flatten(), 256, [0, 256], color='r')
plt.xlim([0, 256])
plt.legend(('cdf', 'histogram'), loc='upper left')

#均衡
cdf_m = np.ma.masked_equal(cdf, 0)
cdf_m = (cdf_m-cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m, 0).astype('uint8')
img2 = cdf[img]
cv.imshow('img2', img2)
hist1, bins1 = np.histogram(img2.flatten(), 256, [0, 256])
cdf1 = hist1.cumsum()
cdf_normalized1 = cdf1*float(hist1.max())/cdf1.max()
plt.subplot(2, 1, 2), plt.plot(cdf_normalized1, color='b')
plt.hist(img2.flatten(), 256, [0, 256], color='r')
plt.xlim([0, 256])
plt.legend(('cdf', 'histogram'), loc='upper left')


plt.show()
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述
或者用cv.equalizeHist() 函数直接均衡

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('E:\\python opencv\\demo2\\wiki.png', 0)
cv.imshow('img', img)

res = cv.equalizeHist(img)
#res = np.hstack((img, equ))
cv.imshow('res', res)

cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

自适应直方图均衡


有时候直接全部均衡会使图片失去一些信息,在这种情况下,图像被分成称为“tiles”的小块(在OpenCV中,tileSize默认为8×8)。然后,像往常一样对这些块中的每一个进行直方图均衡。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('E:\\python opencv\\demo2\\wiki1.jpg', 0)
cv.imshow('img', img)

res = cv.equalizeHist(img)
#res = np.hstack((img, equ))
cv.imshow('res', res)

#自适应均衡
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(img)
cv.imshow('cl1', cl1)

cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述




二、二维直方图

一维直方图,之所以称为一维,是因为我们仅考虑一个特征,即像素的灰度强度值。但是在二维直方图中,您要考虑两个特征。通常,它用于查找颜色直方图,其中两个特征是每个像素的色相和饱和度值。

二维直方图使用相同的函数

cv.calcHist

()进行计算。对于颜色直方图,我们需要将图像从BGR转换为HSV。(请记住,对于一维直方图,我们从BGR转换为灰度)。

对于二维直方图,其参数将进行如下修改:

channel = [0,1],因为我们需要同时处理H和S平面。

bins = [180,256]对于H平面为180,对于S平面为256。

range = [0,180,0,256]色相值介于0和180之间,饱和度介于0和256之间。

也可以用

hist,xbins,ybins=np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])

来完成找直方图

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('E:\\python opencv\\demo2\\wiki2.jpg')
cv.imshow('img', img)

hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

plt.imshow(hist, interpolation='nearest')
plt.show()

cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述



三、直方图反投影

它用于图像分割或在图像中查找感兴趣的对象。简而言之,它创建的图像大小与输入图像相同(但只有一个通道),其中每个像素对应于该像素属于我们物体的概率。

OpenCV提供了一个内建的函数

cv.calcBackProject

()。它的参数几乎与

cv.calchist

()函数相同。它的一个参数是直方图,也就是物体的直方图,我们必须找到它。另外,在传递给backproject函数之前,应该对对象直方图进行归一化。它返回概率图像。然后我们用圆盘内核对图像进行卷积并应用阈值。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
#感兴趣的部分
roi= cv.imread('E:\\python opencv\\demo2\\wiki6.jpg')
hsv = cv.cvtColor(roi, cv.COLOR_BGR2HSV)
#整张图
target = cv.imread('E:\\python opencv\\demo2\\wiki4.jpg')
hsvt = cv.cvtColor(target, cv.COLOR_BGR2HSV)

#计算对象的直方图
roihist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
#直方图归一化
cv.normalize(roihist, roihist, 0, 255, cv.NORM_MINMAX)
dst = cv.calcBackProject([hsvt], [0, 1], roihist, [0, 180, 0, 256], 1)
#用圆盘进行卷积
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
cv.filter2D(dst, -1, disc, dst)
# 应用阈值作与操作
ret, thresh = cv.threshold(dst, 50, 255, 0)
thresh = cv.merge((thresh, thresh, thresh))
res = cv.bitwise_and(target, thresh)
res = np.vstack((target, thresh, res))
cv.imshow('res', res)

cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述



版权声明:本文为X1996_原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。