[OpenCV-Python] OpenCV 中计算摄影学 部分 IX 对象检测 部分 X

部分 IX
计算摄影学

49 图像去噪
目标
  ? 学习使用非局部平均值去噪算法去除图像中的噪音
  ? 学习函数 cv2.fastNlMeansDenoising(),cv2.fastNlMeansDenoisingColored()等
原理
  在前面的章节中我们已经学习了很多图像平滑技术,比如高斯平滑,中值平滑等,当噪声比较小时这些技术的效果都是很好的。在这些技术中我们选取像素周围一个小的邻域然后用高斯平均值或者中值平均值取代中心像素。简单来说,像素级别的噪声去除是限制在局部邻域的。
噪声有一个性质。我们认为噪声是平均值为一的随机变量。考虑一个带噪声的像素点,p = p 0 + n,其中 p 0 为像素的真实值,n 为这个像素的噪声。我们可以从不同图片中选取大量的相同像素(N)然后计算平均值。理想情况下我们会得到 p = p 0 。因为噪声的平均值为 0。
通过简单的设置我们就可以去除这些噪声。将一个静态摄像头固定在一个位置连续拍摄几秒钟。这样我们就会得到足够多的图像帧,或者同一场景的大量图像。写一段代码求解这些帧的平均值(这对你来说应该是小菜一碟)。将最终结果与第一帧图像对比一下。你会发现噪声减小了。不幸的是这种简单的方法对于摄像头和运动场景并不总是适用。大多数情况下我们只有一张导游带有噪音的图像。
想法很简单,我们需要一组相似的图片,通过取平均值的方法可以去除噪音。考虑图像中一个小的窗口(5x5),有很大可能图像中的其他区域也存在一个相似的窗口。有时这个相似窗口就在邻域周围。如果我们找到这些相似的窗口并取他们的平均值会怎样呢?对于特定的窗口这样做挺好的。如下图所示。

    

上图中的蓝色窗口看起来是相似的。绿色窗口看起来也是相似的。所以我们可以选取包含目标像素的一个小窗口,然后在图像中搜索相似的窗口,最后求取所有窗口的平均值,并用这个值取代目标像素的值。这种方法就是非局部平均值去噪。与我们以前学习的平滑技术相比这种算法要消耗更多的时间,但是结果很好。你可以在更多资源中找到更多的细节和在线演示。
对于彩色图像,要先转换到 CIELAB 颜色空间,然后对 L 和 AB 成分分别去噪。

49.1 OpenCV 中的图像去噪
 OpenCV 提供了这种技术的四个变本。
  1. cv2.fastNlMeansDenoising() 使用对象为灰度图。
  2. cv2.fastNlMeansDenoisingColored() 使用对象为彩色图。
  3. cv2.fastNlMeansDenoisingMulti() 适用于短时间的图像序列(灰度图像)
  4. cv2.fastNlMeansDenoisingColoredMulti() 适用于短时间的图像序列(彩色图像)
 共同参数有:
  ? h : 决定过滤器强度。h 值高可以很好的去除噪声,但也会把图像的细节抹去。(取 10 的效果不错)
  ? hForColorComponents : 与 h 相同,但使用与彩色图像。(与 h 相同)
  ? templateWindowSize : 奇数。(推荐值为 7)
  ? searchWindowSize : 奇数。(推荐值为 21)
请查看跟多资源获取这些参数的细节。
这里我们会演示 2 和 3,其余就留给你了。

49.1.1 cv2.fastNlMeansDenoisingColored()
  和上面提到的一样,它可以被用来去除彩色图像的噪声。(假设是高斯噪声)。下面是示例。

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

img = cv2.imread(‘die.png‘)

dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21)

plt.subplot(121),plt.imshow(img)
plt.subplot(122),plt.imshow(dst)
plt.show()

下面是结果的放大图,我们的输入图像中含有方差为 25 的噪声,下面是结果。

    

49.1.2 cv2.fastNlMeansDenoisingMulti()
  现在我们要对一段视频使用这个方法。第一个参数是一个噪声帧的列表。第二个参数 imgtoDenoiseIndex 设定那些帧需要去噪,我们可以传入一个帧的索引。第三个参数 temporaWindowSize 可以设置用于去噪的相邻帧的数目,它应该是一个奇数。在这种情况下 temporaWindowSize 帧的图像会被用于去噪,中间的帧就是要去噪的帧。例如,我们传入 5 帧图像,imgToDenoiseIndex = 2 和 temporalWindowSize = 3。那么第一帧,第二帧,第三帧图像将被用于第二帧图像的去噪。让我们来看一个例子。

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

cap = cv2.VideoCapture(‘vtest.avi‘)

# create a list of first 5 frames
img = [cap.read()[1] for i in xrange(5)]

# convert all to grayscale
gray = [cv2.cvtColor(i, cv2.COLOR_BGR2GRAY) for i in img]

# convert all to float64
gray = [np.float64(i) for i in gray]

# create a noise of variance 25
noise = np.random.randn(*gray[1].shape)*10

# Add this noise to images
noisy = [i+noise for i in gray]

# Convert back to uint8
noisy = [np.uint8(np.clip(i,0,255)) for i in noisy]

# Denoise 3rd frame considering all the 5 frames
dst = cv2.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35)

plt.subplot(131),plt.imshow(gray[2],‘gray‘)
plt.subplot(132),plt.imshow(noisy[2],‘gray‘)
plt.subplot(133),plt.imshow(dst,‘gray‘)
plt.show()

下图是我得到结果的放大版本。

计算消耗了相当可观的时间。第一张图是原始图像,第二个是带噪音个图
像,第三个是去噪音之后的图像。

    

50 图像修补
目标
  ? 使用修补技术去除老照片中小的噪音和划痕
  ? 使用 OpenCV 中与修补技术相关的函数

50.1 基础
  在我们每个人的家中可能都会几张退化的老照片,有时候上面不小心在上面弄上了点污渍或者是画了几笔。你有没有想过要修复这些照片呢?我们可以使用笔刷工具轻易在上面涂抹两下,但这没用,你只是用白色笔画取代了黑色笔画。此时我们就要求助于图像修补技术了。这种技术的基本想法很简单:使用坏点周围的像素取代坏点,这样它看起来和周围像素就比较像了。如下图所示(照片来自维基百科):

    
为了实现这个目的,科学家们已经提出了好几种算法,OpenCV 提供了其中的两种。这两种算法都可以通过使用函数 cv2.inpaint() 来实施。
第一个算法是根据 Alexandru_Telea 在 2004 发表的文章实现的。它是基于快速行进算法的。以图像中一个要修补的区域为例。算法从这个区域的边界开始向区域内部慢慢前进,首先填充区域边界像素。它要选取待修补像素周围的一个小的邻域,使用这个邻域内的归一化加权和更新待修复的像素值。权重的选择是非常重要的。对于靠近带修复点的像素点,靠近正常边界像素点和在轮廓上的像素点给予更高的权重。当一个像素被修复之后,使用快速行进算法(FMM)移动到下一个最近的像素。FMM 保证了靠近已知(没有退化的)像素点的坏点先被修复,这与手工启发式操作比较类似。可以通过设置标签参数为 cv2.INPAINT_TELEA 来使用此算法。
第二个算法是根据 Bertalmio,Marcelo,Andrea_L.Bertozzi, 和 Guillermo_Sapiro在 2001 年发表的文章实现的。这个算法是基于流体动力学并使用了偏微分方程。基本原理是启发式的。它首先沿着正常区域的边界向退化区域的前进(因为边界是连续的,所以退化区域非边界与正常区域的边界应该也是连续的)。它通过匹配待修复区域中的梯度向量来延伸等光强线(isophotes,由灰度值相等的点练成的线)。为了实现这个目的,作者是用来流体动力学中的一些方法。

完成这一步之后,通过填充颜色来使这个区域内的灰度值变化最小。可以通过设置标签参数为 cv2.INPAINT_NS 来使用此算法。

50.2 代码
  我们要创建一个与输入图像大小相等的掩模图像,将待修复区域的像素设置为 255(其他地方为 0)。所有的操作都很简单。我要修复的图像中有几个黑色笔画。我是使用画笔工具添加的。

import numpy as np
import cv2

img = cv2.imread(‘messi_2.jpg‘)
mask = cv2.imread(‘mask2.png‘,0)

dst = cv2.inpaint(img,mask,3,cv2.INPAINT_TELEA)

cv2.imshow(‘dst‘,dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果如下。第一幅图是退化的输入图像,第二幅是掩模图像。第三幅是使用第一个算法的结果,最后一副是使用第二个算法的结果。

    

部分 X
对象检测

51 使用 Haar 分类器进行面部检测
目标
  ? 以 Haar 特征分类器为基础的面部检测技术
  ? 将面部检测扩展到眼部检测等。

51.1 基础
  以 Haar 特征分类器为基础的对象检测技术是一种非常有效的对象检测技术(2001 年 Paul_Viola 和 Michael_Jones 提出)。它是基于机器学习的,通过使用大量的正负样本图像训练得到一个 cascade_function,最后再用它来做对象检测。
现在我们来学习面部检测。开始时,算法需要大量的正样本图像(面部图像)和负样本图像(不含面部的图像)来训练分类器。我们需要从其中提取特征。下图中的 Haar 特征会被使用。它们就像我们的卷积核。每一个特征是一个值,这个值等于黑色矩形中的像素值之后减去白色矩形中的像素值之和。使用所有可能的核来计算足够多的特征。(想象一下这需要多少计算量?仅仅是一个 24x24 的窗口就有 160000 个特征)。对于每一个特征的计算我们好需要计算白色和黑色矩形内的像素和。为了解决这个问题,作者引入了积分图像,这可以大大的简化求和运算,对于任何一个区域的像素和只需要对积分图像上的四个像素操作即可。非常漂亮,它可以使运算速度飞快!
但是在我们计算得到的所有的这些特征中,大多数是不相关的。如下图所示。

    

上边一行显示了两个好的特征,第一个特征看上去是对眼部周围区域的描述,因为眼睛总是比鼻子黑一些。第二个特征是描述的是眼睛比鼻梁要黑一些。但是如果把这两个窗口放到脸颊的话,就一点都不相关。那么我们怎样从超过160000+ 个特征中选出最好的特征呢?使用 Adaboost。
为了达到这个目的,我们将每一个特征应用于所有的训练图像。对于每一个特征,我们要找到它能够区分出正样本和负样本的最佳阈值。但是很明显,这会产生错误或者错误分类。我们要选取错误率最低的特征,这说明它们是检测面部和非面部图像最好的特征。(这个过程其实不像我们说的这么简单。在开始时每一张图像都具有相同的权重,每一次分类之后,被错分的图像的权重会增大。同样的过程会被再做一遍。然后我们又得到新的错误率和新的权重。重复执行这个过程知道到达要求的准确率或者错误率或者要求数目的特征找到)。
最终的分类器是这些弱分类器的加权和。之所以成为弱分类器是应为只是用这些分类器不足以对图像进行分类,但是与其他的分类器联合起来就是一个很强的分类器了。文章中说 200 个特征就能够提供 95% 的准确度了。他们最后使用 6000 个特征。(从 160000 减到 6000,效果显著呀!)。

    
现在你有一幅图像,对每一个 24x24 的窗口使用这 6000 个特征来做检查,看它是不是面部。这是不是很低效很耗时呢?的确如此,但作者有更好的解决方法。
在一副图像中大多数区域是非面部区域。所以最好有一个简单的方法来证明这个窗口不是面部区域,如果不是就直接抛弃,不用对它再做处理。而不是集中在研究这个区域是不是面部。按照这种方法我们可以在可能是面部的区域多花点时间。
为了达到这个目的作者提出了级联分类器的概念。不是在一开始就对窗口进行这 6000 个特征测试,将这些特征分成不同组。在不同的分类阶段逐个使用。(通常前面很少的几个阶段使用较少的特征检测)。如果一个窗口第一阶段的检测都过不了就可以直接放弃后面的测试了,如果它通过了就进入第二阶段的检测。如果一个窗口经过了所有的测试,那么这个窗口就被认为是面部区域。
这个计划是不是很帅!!!
作者将 6000 多个特征分为 38 个阶段,前五个阶段的特征数分别为 1,10,25,25 和 50。(上图中的两个特征其实就是从 Adaboost 获得的最好特征)。
According to authors, on an average, 10 features out of 6000+
are evaluated per sub-window.
上面是我们对 Viola-Jones 面部检测是如何工作的直观解释。读一下原始文献或者更多资源中非参考文献将会对你有更大帮助。

51.2 OpenCV 中的 Haar 级联检测
  OpenCV 自带了训练器和检测器。如果你想自己训练一个分类器来检测汽车,飞机等的话,可以使用 OpenCV 构建。其中的细节在这里:Cascade Classifier Training
现在我们来学习一下如何使用检测器。OpenCV 已经包含了很多已经训练好的分类器,其中包括:面部,眼睛,微笑等。这些 XML 文件保存在/opencv/data/haarcascades/文件夹中。下面我们将使用 OpenCV 创建一个面部和眼部检测器。
首先我们要加载需要的 XML 分类器。然后以灰度格式加载输入图像或者是视频。

import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml‘)
eye_cascade = cv2.CascadeClassifier(‘haarcascade_eye.xml‘)

img = cv2.imread(‘sachin.jpg‘)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

现在我们在图像中检测面部。如果检测到面部,它会返回面部所在的矩形
区域 Rect(x,y,w,h)。一旦我们获得这个位置,我们可以创建一个 ROI 并在
其中进行眼部检测。(谁让眼睛长在脸上呢!!!)

faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
    img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    roi_gray = gray[y:y+h, x:x+w]
    roi_color = img[y:y+h, x:x+w]
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex,ey,ew,eh) in eyes:
        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

cv2.imshow(‘img‘,img)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果如下:

    

原文地址:https://www.cnblogs.com/Undo-self-blog/p/8449502.html

时间: 2024-08-28 05:09:13

[OpenCV-Python] OpenCV 中计算摄影学 部分 IX 对象检测 部分 X的相关文章

.NET + OpenCV & Python + OpenCV 配置

最近需要做一个图像识别的GUI应用,权衡了Opencv+ 1)QT,2)Python GUI,3).NET后选择了.NET... 本文给出C#+Opencv和Python+Opencv的相应参考,节省大家时间. (一)C#.NET + Opencv 1)下载并安装Emgu库(for opencv on .NET env) Download @ http://sourceforge.net/projects/emgucv/ 2)How to use opencv on C#? VS上配置Emgu(

Python序列化中json模块和pickle模块

1.什么是序列化? 将原本的字典.列表等内容转换成一个字符串的过程就叫做序列化. 比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给? 现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来. 但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中. 你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢? 没错序列化的过程就是从dic 变成str(dic)

python OpenCV使用

关于OpenCV简介  OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows.Android和Mac OS操作系统上.它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python.Ruby.MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法.OpenCV用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语言接口. 在计算机视觉项目的开发中,OpenCV作为较大众的开源库,拥有了丰富的常

python+opencv实现机器视觉基础技术(边缘提取,图像滤波,边缘检测算子,投影,车牌字符分割)

目录 一:边缘提取 1.对图像进行阈值分割并反色 2.边缘提取 二:图像滤波 1.读取原图 2.均值滤波 3.中值滤波 4.高斯滤波 5.高斯边缘检测 三:边缘检测算子 1.显示原图 2.对图像进行反色 3.对图像用sobel方法进行边缘检测 4.对图像用robert方法进行边缘检测 四:投影 1.显示原图 2.垂直方向投影 3.水平方向投影 五:车牌字符分割 1.读取原图 2.灰度转换 3.反色 4.阈值分割 5.投影 6.字符识别匹配分割 ??机器视觉是人工智能正在快速发展的一个分支.简单说

python opencv linux下合作操作摄像头

设想: 之前使用C#控制摄像头的,现在厌烦了windows,决定转移到linux下玩耍.感觉能够python语言特有的好入手,正好替代C#,选择了deepin2014.1作为试验品.现在的设想是第一步实现在自己电脑上对视频的采集,第二步实现视频传输.慢慢来吧.百度说python想操作摄像头,VideoCapture是windows特有的,linux要用opencv才行. 下载: 百度下载了最新的opencv,2.4.9版本,正好和deepin2014.1自带的python2.7般配,不冲突.且发

centos6.5下安装OpenCV+Python支持

Python调用opencv的原理是:opencv编译出共享库文件,python把这个共享库文件作为一个模块加载并使用.通俗点就是,编译opencv的时候开启python接口选项,编译好了会产生cv2.so(linux下)或者cv2.pyd(windows下)这个共享库文件,python代码中import这个cv2就可以用了.为了能正确import它,往往需要把cv2.so放在python找包能找到的路径下,或者修改PYTHONPATH环境变量让它包含cv2.so所在路径.此外,python的o

python opencv 人脸识别初识

甲.希望通过python加opencv搭建自己的人脸识别判断库 参照如下网页,配置python opencv开发环境, {博主ma6174} http://www.cnblogs.com/ma6174/archive/2013/03/31/2991315.html ubuntu中已有python-opencv的库,安装方便 sudo apt-get install libopencv-* sudo apt-get install python-opencv sudo apt-get instal

window环境下Python+OpenCV配置

最近开始学习OpenCV来进行计算机视觉实验,选择了Python作为实验语言,工欲善其事,必先利其器.先总结下安装配置. 现在opencv目测只支持Python2.7X版本的,还依赖于numpy和matplotlib两个类库.. (I)前期准备 1.下载安装Python2.7:https://www.python.org/downloads/  选择最新版2.7.13 2.下载pip: https://pypi.python.org/pypi/pip,主要是用来安装numpy和matplotli

OpenCV中CascadeClassifier类实现多尺度检测源码解析

级联分类器检测类CascadeClassifier,在2.4.5版本中使用Adaboost的方法+LBP.HOG.HAAR进行目标检测,加载的是使用traincascade进行训练的分类器 class CV_EXPORTS_W CascadeClassifier { public: CV_WRAP CascadeClassifier(); // 无参数构造函数,new自动调用该函数分配初试内存 CV_WRAP CascadeClassifier( const string& filename )