理论

这是由**Michael J. Swain**和**Dana H. Ballard**在他们的论文《通过颜色直方图索引》中提出的。

用简单的话说是什么意思?它用于图像分割或在图像中查找感兴趣的对象。简而言之,它创建的图像大小与输入图像相同(但只有一个通道),其中每个像素对应于该像素属于我们物体的概率。用更简单的话来说,与其余部分相比,输出图像将在可能有对象的区域具有更多的白色值。好吧,这是一个直观的解释。(我无法使其更简单)。直方图反投影与camshift算法等配合使用。

我们该怎么做呢?我们创建一个图像的直方图,其中包含我们感兴趣的对象(在我们的示例中是背景,离开球员等)。对象应尽可能填充图像以获得更好的效果。而且颜色直方图比灰度直方图更可取,因为对象的颜色对比灰度强度是定义对象的好方法。然后,我们将该直方图“反投影”到需要找到对象的测试图像上,换句话说,我们计算出属于背景的每个像素的概率并将其显示出来。在适当的阈值下产生的输出使我们仅获得背景。

Numpy中的算法

  1. 首先,我们需要计算我们要查找的对象(使其为“ M”)和要搜索的图像(使其为“ I”)的颜色直方图。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
#roi是我们需要找到的对象或对象区域
roi = cv.imread('rose_red.png')
hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
#目标是我们搜索的图像
target = cv.imread('rose.png')
hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV)
# 使用calcHist查找直方图。也可以使用np.histogram2d完成
M = cv.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
I = cv.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] )
  1. 求出比值R=MIR=MI。然后反向投影R,即使用R作为调色板,并以每个像素作为其对应的目标概率创建一个新图像。即B(x,y) = R[h(x,y),s(x,y)] 其中h是色调,s是像素在(x,y)的饱和度。之后,应用条件B(x,y)=min[B(x,y),1]B(x,y)=min[B(x,y),1]。
h,s,v = cv.split(hsvt)
B = R[h.ravel(),s.ravel()]
B = np.minimum(B,1)
B = B.reshape(hsvt.shape[:2])
  1. 现在对圆盘应用卷积,B=D∗BB=D∗B,其中D是圆盘内核。
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
'''getStructuringElement()函数可用于构造一个特定大小和形状的结构元素,用于图像形态学处理
retval=cv.getStructuringElement(shape, ksize[, anchor] )
shape:cv.MORPH_RECT 方形 cv.MORPH_CROSS 交错形状 cv.MORPH_ELLIPSE椭圆
anchor :图像内锚点位置,默认(-1,-1)'''
cv.filter2D(B,-1,disc,B)
B = np.uint8(B)
cv.normalize(B,B,0,255,cv.NORM_MINMAX)
  1. 现在最大强度的位置给了我们物体的位置。如果我们期望图像中有一个区域,则对合适的值进行阈值处理将获得不错的结果。
  2. ret,thresh = cv.threshold(B,50,255,0)
    

    就是这样!!

    OpenCV的反投影

    OpenCV提供了一个内建的函数**cv.calcBackProject**()。它的参数几乎与**cv.calchist**()函数相同。它的一个参数是直方图,也就是物体的直方图,我们必须找到它。另外,在传递给backproject函数之前,应该对对象直方图进行归一化。它返回概率图像。然后我们用圆盘内核对图像进行卷积并应用阈值。下面是我的代码和结果:import numpy as np import cv2 as cv roi = cv.imread('rose_red.png') hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV) target = cv.imread('rose.png') 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.imwrite('res.jpg',res)

  3. import numpy as np
    import cv2 as cv
    roi = cv.imread('rose_red.png')
    hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
    target = cv.imread('rose.png')
    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))
    '''np.vstack()
    按垂直方向(行顺序)堆叠数组构成一个新的数组
    堆叠的数组需要具有相同的维度
    np.hstack()
    按水平方向(列顺序)堆叠数组构成一个新的数组
    堆叠的数组需要具有相同的维度'''
    cv.imwrite('res.jpg',res)

    cv.normalize:函数作用
    归一化数据。该函数分为范围归一化与数据值归一化。(Normalizes the norm or value range of an array.)

    参数说明
    src               输入数组;
    dst               输出数组,数组的大小和原数组一致;
    alpha           1,用来规范值,2.规范范围,并且是下限;
    beta             只用来规范范围并且是上限;
    norm_type   归一化选择的数学公式类型;
    dtype           当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游dtype决定;
    mark            掩码。选择感兴趣区域,选定后只能对该区域进行操作。

    归一化选择的数学公式类型介绍(norm_type)
    设数组中原有{A1,A2,A3...An}
    NORM_L1:

    NORM_INF:

    NORM_L2:

    NORM_MINMAX:(AK不属于{max(Ai)},min(Ai),当AK等于max(Ai)时p=1,等于min(Ai)时p=0)

    5.举例说明:
    src={10,23,71}

    NORM_L1运算后得到    dst={0.096,0.221,0.683}

    NORM_INF运算后得到  dst={0.141,0.324,1}

    NORM_L2运算后得到   dst={0.133,0.307,0.947}

    NORM_MINMAX运算得到 dst={0,0.377,1}

    6.范围归一化与值归一化的区别
    区别一:范围归一化使用的是如下式子,设范围为【0,255】

    即把src缩放到【0,255】这个范围内,并不使用上面的4个公式去解。

    以下是我处理过的一个示例。我将蓝色矩形内的区域用作示例对象,我想提取整个地面。

傅里叶变换

目标

在本节中,我们将学习 - 使用OpenCV查找图像的傅立叶变换 - 利用Numpy中可用的FFT函数 - 傅立叶变换的某些应用程序 - 我们将看到以下函数:cv.dft(),cv.idft()等

理论

傅立叶变换用于分析各种滤波器的频率特性。对于图像,使用**2D离散傅里叶变换**(DFT)查找频域。一种称为**快速傅立叶变换**(FFT)的快速算法用于DFT的计算。关于这些的详细信息可以在任何图像处理或信号处理教科书中找到。请参阅其他资源部分。

对于正弦信号x(t)=Asin(2πft)x(t)=Asin⁡(2πft),我们可以说ff是信号的频率,如果采用其频域,则可以看到ff的尖峰。如果对信号进行采样以形成离散信号,我们将获得相同的频域,但是在[−π,π][−π,π]或[0,2π][0,2π]范围内(对于N点DFT为[0,N][0,N])是周期性的。您可以将图像视为在两个方向上采样的信号。因此,在X和Y方向都进行傅立叶变换,可以得到图像的频率表示。

更直观地说,对于正弦信号,如果幅度在短时间内变化如此之快,则可以说它是高频信号。如果变化缓慢,则为低频信号。您可以将相同的想法扩展到图像。图像中的振幅在哪里急剧变化?在边缘点或噪声。因此,可以说边缘和噪声是图像中的高频内容。如果幅度没有太大变化,则它是低频分量。(一些链接已添加到“其他资源”,其中通过示例直观地说明了频率变换)。

现在,我们将看到如何找到傅立叶变换。

Numpy中的傅里叶变换

首先,我们将看到如何使用Numpy查找傅立叶变换。Numpy具有FFT软件包来执行此操作。np.fft.fft2()为我们提供了频率转换,它将是一个复杂的数组。它的第一个参数是输入图像,即灰度图像。第二个参数是可选的,它决定输出数组的大小。如果它大于输入图像的大小,则在计算FFT之前用零填充输入图像。如果小于输入图像,将裁切输入图像。如果未传递任何参数,则输出数组的大小将与输入的大小相同。

现在,一旦获得结果,零频率分量(DC分量)将位于左上角。如果要使其居中,则需要在两个方向上将结果都移动N2N2。只需通过函数**np.fft.fftshift**()即可完成。(它更容易分析)。找到频率变换后,就可以找到幅度谱。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
f = np.fft.fft2(img)
'''一旦获得结果,零频率分量(DC分量)将位于左上角。如果要使其居中,则需要在两个方向上将结果都移动N2N2。只需通过函数**np.fft.fftshift**()即可完成'''
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

结果看起来像下面这样:

看,您可以在中心看到更多白色区域,这表明低频内容更多。

因此,您发现了频率变换现在,您可以在频域中进行一些操作,例如高通滤波和重建图像,即找到逆DFT。为此,您只需用尺寸为60x60的矩形窗口遮罩即可消除低频。然后,使用**np.fft.ifftshift**()应用反向移位,以使DC分量再次出现在左上角。然后使用**np.ifft2**()函数找到逆FFT。同样,结果将是一个复数。您可以采用其绝对值。

rows, cols = img.shape
crow,ccol = rows//2 , cols//2
fshift[crow-30:crow+31, ccol-30:ccol+31] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.real(img_back)
plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()

结果看起来像下面这样:

结果表明高通滤波是边缘检测操作。这就是我们在“图像渐变”一章中看到的。这也表明大多数图像数据都存在于频谱的低频区域。无论如何,我们已经看到了如何在Numpy中找到DFT,IDFT等。现在,让我们看看如何在OpenCV中进行操作。 如果您仔细观察结果,尤其是最后一张JET颜色的图像,您会看到一些伪像(我用红色箭头标记的一个实例)。它在那里显示出一些波纹状结构,称为**振铃效应**。这是由我们用于遮罩的矩形窗口引起的。此掩码转换为正弦形状,从而导致此问题。因此,矩形窗口不用于过滤。更好的选择是高斯窗口。

OpenCV中的傅里叶变换

OpenCV为此提供了**cv.dft**()和**cv.idft**()函数。它返回与前一个相同的结果,但是有两个通道。第一个通道是结果的实部,第二个通道是结果的虚部。输入图像首先应转换为np.float32。我们来看看怎么做。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

注意 您还可以使用**cv.cartToPolar**(),它在单个镜头中同时返回幅值和相位

现在我们要做DFT的逆变换。在上一节中,我们创建了一个HPF,这次我们将看到如何删除图像中的高频内容,即我们将LPF应用到图像中。它实际上模糊了图像。为此,我们首先创建一个高值(1)在低频部分,即我们过滤低频内容,0在高频区。

rows, cols = img.shape
crow,ccol = rows/2 , cols/2
# 首先创建一个掩码,中心正方形为1,其余全为零
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# 应用掩码和逆DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv.idft(f_ishift)
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

看看结果:

注意 通常,OpenCV函数**cv.dft**()和**cv.idft**()比Numpy函数更快。但是Numpy函数更容易使用。有关性能问题的更多细节,请参见下面的部分。

DFT的性能优化

对于某些数组尺寸,DFT的计算性能较好。当数组大小为2的幂时,速度最快。对于大小为2、3和5的乘积的数组,也可以非常有效地进行处理。因此,如果您担心代码的性能,可以在找到DFT之前将数组的大小修改为任何最佳大小(通过填充零)。对于OpenCV,您必须手动填充零。但是对于Numpy,您指定FFT计算的新大小,它将自动为您填充零。

那么如何找到最优的大小呢?OpenCV为此提供了一个函数,cv.getOptimalDFTSize()。它同时适用于**cv.dft**()和**np.fft.fft2**()。让我们使用IPython魔术命令timeit来检查它们的性能。

In [16]: img = cv.imread('messi5.jpg',0)
In [17]: rows,cols = img.shape
In [18]: print("{} {}".format(rows,cols))
342 548
In [19]: nrows = cv.getOptimalDFTSize(rows)
In [20]: ncols = cv.getOptimalDFTSize(cols)
In [21]: print("{} {}".format(nrows,ncols))
360 576

参见,将大小(342,548)修改为(360,576)。现在让我们用零填充(对于OpenCV),并找到其DFT计算性能。您可以通过创建一个新的零数组并将数据复制到其中来完成此操作,或者使用**cv.copyMakeBorder**()。

nimg = np.zeros((nrows,ncols))
nimg[:rows,:cols] = img

或者:

right = ncols - cols
bottom = nrows - rows
bordertype = cv.BORDER_CONSTANT #只是为了避免PDF文件中的行中断
nimg = cv.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)

现在,我们计算Numpy函数的DFT性能比较:

In [22]: %timeit fft1 = np.fft.fft2(img)
10 loops, best of 3: 40.9 ms per loop
In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols])
100 loops, best of 3: 10.4 ms per loop

它显示了4倍的加速。现在,我们将尝试使用OpenCV函数。

In [24]: %timeit dft1= cv.dft(np.float32(img),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 13.5 ms per loop
In [27]: %timeit dft2= cv.dft(np.float32(nimg),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 3.11 ms per loop

它还显示了4倍的加速。您还可以看到OpenCV函数比Numpy函数快3倍左右。也可以对逆FFT进行测试,这留给您练习。

为什么拉普拉斯算子是高通滤波器?

在一个论坛上也有人提出了类似的问题。问题是,为什么拉普拉斯变换是高通滤波器?为什么Sobel是HPF?等。第一个答案是关于傅里叶变换的。对于更大的FFT只需要拉普拉斯变换。分析下面的代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 没有缩放参数的简单均值滤波器
mean_filter = np.ones((3,3))
# 创建高斯滤波器
x = cv.getGaussianKernel(5,10)
gaussian = x*x.T
# 不同的边缘检测滤波器
# x方向上的scharr
scharr = np.array([[-3, 0, 3],[-10,0,10],[-3, 0, 3]])
# x方向上的sobel
sobel_x= np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])
# y方向上的sobel
sobel_y= np.array([[-1,-2,-1],[0, 0, 0],[1, 2, 1]])
# 拉普拉斯变换
laplacian=np.array([[0, 1, 0],[1,-4, 1],[0, 1, 0]])
filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr]
filter_name = ['mean_filter', 'gaussian','laplacian', 'sobel_x', \'sobel_y', 'scharr_x']
fft_filters = [np.fft.fft2(x) for x in filters]
fft_shift = [np.fft.fftshift(y) for y in fft_filters]
mag_spectrum = [np.log(np.abs(z)+1) for z in fft_shift]
for i in xrange(6):plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap = 'gray')plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])
plt.show()

看看结果:

从图像中,您可以看到每种内核阻止的频率区域以及它允许经过的区域。从这些信息中,我们可以说出为什么每个内核都是HPF或LPF

opencv第九天pro相关推荐

  1. Qt5--学习笔记-+openCV2-客户端、服务端回环视频显示

    参考资料:openCV2参考文档 参考博客 修改了博主的代码,并将整个客户端加服务端的代码工程代码上传到CSDN网站上. OpenCV的运用  安装OpenCV其实就是下载好OpenCV的压缩包之后解 ...

  2. QT实现一个图片透视变换的小玩意

    近来有点烦,不想看论文,不想做项目,无聊之余把好久之前想到的用qt做一个图片透视变换的小工具的想法实现了一下...详细如下: 说明:对于有些平时拍的图片可能产生了透视效果,而你想得到正向拍摄的效果,你 ...

  3. opencv读取usb摄像头_2020 款 11寸 iPad Pro 深度摄像头 RGBD 视频流可视化

    上个月,客户帮我租了一台 2020 款 11寸 iPad Pro,为了在 iPad 上实现一个室内三维重建的APP.以我的方式,我需要先离线在主机上实现一个三维重建的程序. 为了给客户节约成本,我找到 ...

  4. 全网最详细 Opencv + OpenNi + 奥比中光(Orbbec) Astra Pro /乐视三合一体感摄像头LeTMC-520 + linux 环境搭建

    本文参考 Using Orbbec Astra 3D cameras C++20学习:基于Ubuntu系统编译gcc10.2.0 linux下编译安装opencv生成opencv.pc 摄像头方案 / ...

  5. 的pro文件添加opencv配置_VS2013+OpenCV3.1.0配置方法

    原文首发于微信公众号:[3D视觉工坊]. 相关文件安装包下载:关注「3D视觉工坊」微信公众号,回复「VS2013+OpenCV3.1.0」,即可获得下载链接. 一 请先安装VS2013 见工具包中的& ...

  6. 【python + opencv + pytorch】车牌提取、分割、识别 pro版

    老规矩,先看最后成果图(如果想要全部工程,文章最后我会把github链接放上) 1.分割车牌 2.分割字符 3.识别字符 最终识别的车牌号码是:浙F99999 整个车牌识别分五步: 1.一个分割车牌的 ...

  7. QT 中使用 OpenCv 的 CascadeClassifier 报错

    问题 在 QT 中调用 OpenCv 的 CascadeClassifier 进行人脸框检测的时候,在构造函数中进行检测器的初始化,随后调用相机读取图片的时候就会报错,报的错误是 Segment Fa ...

  8. 【Qt】ubuntu QtCreator的pro文件中使用pkg-config

    试验环境 ubuntu14.04.5 opencv2.4.13.6 Qt Creator 4.0.3 Qt 5.6 使用方法 在pro文件中,添加opencv头文件路径 INCLUDEPATH += ...

  9. 71 mac boook pro 无 gpu 下caffe 安装

    71 mac boook pro 无 gpu 下caffe 安装 1.首先安装homebrew工具,相当于Mac下的yum或apt ruby -e "$(curl -fsSL https:/ ...

  10. 如何用 OpenCV、Python 和深度学习实现面部识别?

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达本文转自|新机器视觉 Face ID 的兴起带动了一波面部识别技术热 ...

最新文章

  1. R语言ggplot2可视化创建堆叠的柱状图(stacked barplot)并且每个堆叠的柱状图都缩放到总和为100%实战:最后所有的堆叠的柱子都一样高、Y轴以百分比的形式来显示
  2. 无线节能组信标为什么会自动切换? 排查故障的过程真的像谜一样无法解释
  3. 微信小程序 - vant popup弹出层阻止底层页面滑动
  4. boost::hana::iterate用法的测试程序
  5. PngEncoder_CreateInstance Failed writing PNG because unable to find libpng12.so.0
  6. Pycharm如何选择自动打开最近项目
  7. 前端学习(2125):watch实现
  8. linux内核支持的加密算法,Linux Kernel(Android) 加密算法总结(三)-应用程序调用内核加密算法接口...
  9. Linux—shell脚本化工具模板
  10. Golang笔记-面向对象编程-多态/类型断言
  11. 微博拟全球发售1100万股 发售价不超388港元
  12. FreeRTOS的内存管理
  13. 携程Apollo(阿波罗)配置中心在Spring Boot项目快速集成
  14. js中substr,substring,indexOf,lastIndexOf的用法小结
  15. C-从源文件到可执行文件的详细编译链接过程
  16. 数据库备份和事务日志备份
  17. 简单数据策略帮助LinkedIn提高企业服务收入
  18. Neural NILM: Deep Neural Networks Applied to Energy Disaggregation
  19. ResultSet用法集锦
  20. 城八区和通州区限价房申请5月16日开始受理

热门文章

  1. 私有文件服务器,文件服务器与私有云盘
  2. [转贴] To love and to be loved
  3. vscode eslint beautify 格式化 html
  4. 计算机应用基础2207,山东省高等教育自学考试2012年4月份考试专业科目一览表
  5. scrapy IP代理池 scrapyd spiderkeeper docker flask uwsgi nginx
  6. Word中怎样在方框里打钩?方框里打钩的符号的方法
  7. antd4使用form表单
  8. PHP数据加密的几种方式
  9. 5G/NR 5G核心网(5GC)之网络功能和实体
  10. html中重叠盒子之间的距离,div间距设置_div之间距离设置布局