您的位置:首页 > 运维架构

OpenCV中的图像处理 [3]-OpenCV中的直方图

2017-10-23 11:29 453 查看
参考:

1、http://docs.opencv.org/3.3.0/  官方文档api

2、http://docs.opencv.org/3.3.0/d6/d00/tutorial_py_root.html 官方英文教程

3、https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html

4、https://github.com/makelove/OpenCV-Python-Tutorial# 进阶教程

5、https://docs.opencv.org/3.3.0/index.html 
官方英文教程

6、https://github.com/abidrahmank/OpenCV2-Python-Tutorials

7、https://www.learnopencv.com/

8、http://answers.opencv.org/questions/ OpenCV论坛

9、https://github.com/opencv/opencv  
官方github

10、https://github.com/abidrahmank/OpenCV2-Python-Tutorials

注:安装的版本
opencv_python-3.3.0-cp36-cp36m-win_amd64.whl

参考:https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html

直方图 - 1:查找,绘制,分析 !!!


目标

Learn to
Find histograms, using both OpenCV and Numpy functions
Plot histograms, using OpenCV and Matplotlib functions
You will see these functions : cv2.calcHist()np.histogram() etc.


理论

1. OpenCV中的直方图计算

所以现在我们使用cv2.calcHist() 函数来查找直方图。 让我们熟悉函数及其参数:

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

图像:它是uint8或float32类型的源图像。 应该在方括号中给出,即“

Additional Resources

Cambridge in Color website

直方图 - 2:直方图均衡


目标

In this section,

We will learn the concepts of histogram equalization and use it to improve the contrast of our images.


理论

考虑图像像素值仅限于特定值范围。 例如,较亮的图像将所有像素都限制在高值。 但是,一个好的图像将会有来自图像所有区域的像素。 所以你需要将这个直方图拉伸到两端(如下图所示,从维基百科),这就是直方图均衡所做的(简单的话)。 这通常会改善图像的对比度



import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('dave.jpg',0)

# x=np.max(img.ravel()-img.flatten())

hist,bins = np.histogram(img.flatten(),256,[0,256])

cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()

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')
plt.show()




您可以看到直方图位于较亮的区域。 我们需要全谱。 为此,我们需要一个转换函数,将更亮区域中的输入像素映射到全区域的输出像素。 那就是直方图均衡。

现在我们找到最小直方图值(不包括0),并应用维基页面中给出的直方图均衡方程。 但是我在这里使用了来自Numpy的掩码数组概念数组。 对于屏蔽阵列,所有操作都在非屏蔽元素上执行。 您可以从掩码数组的Numpy文档中阅读更多信息。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('dave.jpg',0)

hist,bins = np.histogram(img.flatten(),256,[0,256])

cdf = hist.cumsum()

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

OpenCV中的直方图均衡

OpenCV具有执行此功能的功能,cv2.equalizeHist()。 它的输入只是灰度图像,输出是我们的直方图均衡图像。

下面是一个简单的代码片段,显示了我们使用的相同图像的用法:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('dave.jpg',0)

equ = cv2.equalizeHist(img) # 直方图均衡后的图像
'''
# 等价于
hist,bins = np.histogram(img.flatten(),256,[0,256])
cdf = hist.cumsum()
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')
equ = cdf

在直方图均衡后,背景对比度是改善的。 但是在两个图像中比较雕像的脸。 由于超亮度,我们失去了大部分信息。 这是因为它的直方图并不局限于特定区域,就像我们以前的情况一样(尝试绘制输入图像的直方图,你会得到更多的直觉)。

因此,为了解决这个问题,使用自适应直方图均衡。 在这种情况下,图像被划分为称为“瓦片”的小块(默认情况下,TileSize是OpenCV中的8x8)。 然后这些块中的每一个像平常一样直方图均衡。 所以在一个很小的区域,直方图将局限于一个小区域(除非有噪音)。
如果有噪音,那将会被放大。 为了避免这种情况,应用对比度限制。 如果任何直方图bin高于指定的对比度限制(OpenCV中默认为40),则在应用直方图均衡之前,这些像素将被裁剪并均匀分布到其他bin。 均衡后,为了去除瓦片边框中的伪像,应用双线性插值。

以下代码片段显示了如何在OpenCV中应用CLAHE:

import numpy as np
import cv2

img = cv2.imread('tsukuba_l.png',0)

# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)

cv2.imwrite('clahe_2.jpg',cl1)


Additional Resources

Wikipedia page on Histogram
Equalization
Masked Arrays in Numpy

Also check these SOF questions regarding contrast adjustment:

How
can I adjust contrast in OpenCV in C?
How
do I equalize contrast & brightness of images using opencv?

直方图 - 3:2D直方图


目标

In this chapter, we will learn to find and plot 2D histograms. It will be helpful in coming chapters.


介绍

在第一篇文章中,我们计算并绘制了一维直方图。 它被称为一维,因为我们仅考虑了一个特征,即像素的灰度强度值。 但是在二维直方图中,您可以考虑两个特征。 通常它用于查找颜色直方图,其中两个特征是每个像素的色相和饱和度值。

官方示例中有一个python样本已经用于查找颜色直方图。 我们将尝试了解如何创建这样的颜色直方图,并且它将有助于理解进一步的主题,如直方图反投影。

OpenCV中的2D直方图

它是相当简单和计算使用相同的函数,cv2.calcHist()。 对于颜色直方图,我们需要将图像从BGR转换为HSV。 (记住,对于1D直方图,我们从BGR转换为灰度)。 对于2D直方图,其参数将被修改如下:

channels = [0,1] because we need to process both H and S plane.
bins = [180,256] 180 for H plane and 256 for S plane.
range = [0,180,0,256] Hue value lies between 0 and 180 & Saturation lies between 0 and 256.
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('messi5.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

plt.plot(hist);plt.show()



二维直方图在Numpy

Numpy还提供了一个特定的功能:np.histogram2d()。 (记住,对于1D直方图,我们使用np.histogram())。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

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


第一个参数是H平面,第二个是S平面,第三个是四和四的数量是它们的范围。

现在我们可以检查如何绘制这个颜色直方图。

绘制2D直方图


方法 - 1:使用cv2.imshow()

我们得到的结果是尺寸为180x256的二维数组。 所以我们可以像正常使用cv2.imshow()函数一样显示它们。 这将是一个灰度图像,除非你知道不同颜色的色相值,否则它不会给出很多的颜色。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
h,s,v=cv2.split(hsv)
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
cv2.imshow('his',hist)
cv2.waitKey(0)
cv2.destroyAllWindows()


方法 - 2:使用Matplotlib

我们可以使用matplotlib.pyplot.imshow()函数来绘制具有不同颜色图的2D直方图。 它使我们更好地了解不同的像素密度。 但是,这也不是让我们了解第一眼看什么颜色,除非你知道不同颜色的色相值。 仍然我喜欢这种方法。 这是简单和更好。

使用此功能时,请记住,插补标志应该是nearest以获得更好的结果。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('home.jpg')
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )

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


下面是输入图像及其颜色直方图。 X轴显示S值,Y轴显示Hue值。



在直方图中,您可以看到H = 100和S = 200附近的一些高值。它对应于天空的蓝色。 类似地,在H = 25和S = 100附近可以看到另一个峰值。它对应于宫殿的黄色。 您可以使用任何图像编辑工具(如GIMP)进行验证。

方法3:OpenCV样本样式 !!

OpenCV-Python2样本中有一个颜色直方图的示例代码。 如果你运行代码,你可以看到直方图显示相应的颜色。 或者只是输出一个颜色编码的直方图。 它的结果是非常好的(虽然你需要添加额外的一些行)。

在该代码中,作者在HSV中创建了一个颜色映射。 然后将其转换为BGR。 所得到的直方图图像与该颜色图相乘。 他还使用一些预处理步骤来删除小的孤立像素,导致良好的直方图。

直方图 - 4:直方图反投影


目标

In this chapter, we will learn about histogram backprojection.


理论

Numpy中的算法

1、首先,我们需要计算我们需要找到的对象(让它成为'M')和我们要搜索的图像(让它是'I')的颜色直方图。

import cv2
import numpy as np
from matplotlib import pyplot as plt

#roi is the object or region of object we need to find
roi = cv2.imread('rose_red.png')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)

#target is the image we search in
target = cv2.imread('rose.png')
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)

# Find the histograms using calcHist. Can be done with np.histogram2d also
M = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
I = cv2.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] )


2、找到比率 


然后是backproject R,即使用R作为调色板,并创建一个新的图像与每个像素作为其相应的目标概率。 即B(x,y) = R[h(x,y),s(x,y)]其中h是色调,s是像素在(x,y)时的饱和度。
之后应用条件 

.

h,s,v = cv2.split(hsvt)
B = R[h.ravel(),s.ravel()]
B = np.minimum(B,1)
B = B.reshape(hsvt.shape[:2])


3.现在用圆盘卷积

,其中D是光盘内核。

disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.filter2D(B,-1,disc,B)
B = np.uint8(B)
cv2.normalize(B,B,0,255,cv2.NORM_MINMAX)


4、现在最大强度的位置给我们物体的位置。 如果我们期待图像中的一个区域,则为适当的值进行阈值提供了不错的结果。

ret,thresh = cv2.threshold(B,50,255,0)


OpenCV中的反投影

OpenCV提供内置函数cv2.calcBackProject()。 它的参数与cv2.calcHist()函数几乎相同。 其参数之一是直方图,它是对象的直方图,我们必须找到它。 此外,在传递给backproject函数之前,对象直方图应该被归一化。 它返回概率图像。 然后我们使用光盘内核卷积图像并应用阈值。 下面是我的代码和输出:

import cv2
import numpy as np

'''
roi = cv2.imread('rose_red.png')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)

target = cv2.imread('rose.png')
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
'''

roi=cv2.imread('messi5.jpg')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
target=roi[300:340,10:100,:]
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)

# calculating object histogram
roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )

# normalize histogram and apply backprojection
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX) # 目标对象归一化
dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)

# Now convolute with circular disc
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
cv2.filter2D(dst,-1,disc,dst)

# threshold and binary AND
ret,thresh = cv2.threshold(dst,50,255,0)
thresh = cv2.merge((thresh,thresh,thresh))
res = cv2.bitwise_and(target,thresh)

res = np.vstack((target,thresh,res))
# cv2.imwrite('res.jpg',res)
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐