-
GrabCut 算法提取前景
-
算法步骤
- 1. 用户输入一个矩形。矩形外的所有区域肯定都是背景矩形框内的东西是未知的。同样
用户确定前景和背景的任何操作都不会被程序改变
- 2. 计算机会对我们的输入图像做一个初始化标记。它会标记前景和背景像素
- 3. 使用一个高斯混合模型(GMM)对前景和背景建模
- 4. 根据我们的输入, GMM 会学习并创建新的像素分布。对那些分类未知
的像素(可能是前景也可能是背景),可以根据它们与已知分类(如背景)
的像素的关系来进行分类(就像是在做聚类操作)
- 5. 这样就会根据像素的分布创建一副图。图中的节点就是像素点。除了像
素点做节点之外还有两个节点: Source_node 和 Sink_node。所有的
前景像素都和 Source_node 相连。所有的背景像素都和 Sink_node 相
连。
- 6. 将像素连接到 Source_node/end_node 的(边)的权重由它们属于同
一类(同是前景或同是背景)的概率来决定。两个像素之间的权重由边的
信息或者两个像素的相似性来决定。如果两个像素的颜色有很大的不同,
那么它们之间的边的权重就会很小
- 7. 使用 mincut 算法对上面得到的图进行分割。它会根据最低成本方程将图
分为 Source_node 和 Sink_node。成本方程就是被剪掉的所有边的权
重之和。在裁剪之后,所有连接到 Source_node 的像素被认为是前景,
所有连接到 Sink_node 的像素被认为是背景
- 8. 继续这个过程直到分类收敛。
-
算法效果
- 用户需要用一个矩形将前景区域框住
- 然后算法进行迭代式分割直达达到最好结果
- 有时分割的结果不够理想,比如把前景当成了背景,或者把背景
当成了前景。在这种情况下,就需要用户来进行修改
-
opencv调用
-
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
- img - 输入图像
- mask-掩模图像,用来确定那些区域是背景,前景,可能是前景/背景等。可以设置为:cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,或者直接输入 0,1,2,3 也行
- rect - 包含前景的矩形,格式为 (x,y,w,h)
- bdgModel, fgdModel - 算法内部使用的数组. 你只需要创建两个大小为 (1,65),数据类型为 np.float64 的数组
- iterCount - 算法的迭代次数
- mode 可以设置为 cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK,也可以联合使用。这是用来确定我们进行修改的方式,矩形模式或者掩模模式
-
hough直线变换
-
算法步骤
- 每一条直线都可以用 (ρ; θ) 表示
- 首先创建一个 2D 数组(累加器),初始化累加器,所有的值都为 0。行表示 ρ,列表示 θ。
- 想象一下我们有一个大小为 100x100 的直线位于图像的中央。
取直线上的第一个点,我们知道此处的(x, y)值
- 把 x 和 y 带入上边的方程组,然后遍历 θ 的取值(0,1,..180)
- 分别求出与其对应的 ρ 的值,这样我们就得到一系列(ρ; θ)的数值对,
如果这个数值对在累加器中也存在相应的位置,就在这个位置上加 1
-
lines = cv2.HoughLines(edges,1,np.pi/180,200)
- edges = cv2.Canny(gray,50,150,apertureSize = 3)
-
cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
- minLineLength - 线的最短长度。比这个短的线都会被忽略
- MaxLineGap - 两条线段之间的最大间隔,如果小于此值,
这两条直线就被看成是一条直线
- 从一幅图像中随机选取点进行计算
- cv25_houghlines.py
-
分水岭算法图像分割
-
算法
- 任何一副灰度图像都可以被看成拓扑平面,灰度值高的区域
可以被看成是山峰,灰度值低的区域可以被看成是山谷
- 向每一个山谷中灌不同颜色的水。随着水的位的升高,不同山谷的水就会相遇汇合
- 为了防止不同山谷的水汇合,我们需要在水汇合的地方构建起堤坝。不停的灌水,不停的构建堤坝直到所有的山峰都被水淹没。我们构建好的堤坝就是对图像的分割
- cv26_watershed.py
-
图像变换
-
傅里叶变换
-
图像的边界点和噪声是图像的高频分量(变化非常快),其他的为低频分量
-
可以对图像做高通滤波和重建图像
- 使用一个nxn的矩形窗口对图像掩膜操作,去除低频分量
- 再使用np.fft.ifftshift() 进行逆平移操作,让直流分量又回到左上角
- 最后使用函数 np.ifft2() 进行 FFT 逆变换
-
DFT性能优化
- 当数组的大小是 2 的指数时 DFT 效率最高
- cv2.getOptimalDFTSize()。
它可以同时被 cv2.dft() 和 np.fft.fft2() 使用
- cv23_fft.py
-
几何变换
-
拓展缩放
-
resize(src, dst, interpolation=CV_INTER_LINEAR)
- 尺寸:用户指定
-
插值方法
- cv2.INTER_AREA (缩放时)(快)
- cv2.INTER_CUBIC(拓展时)(慢)
- cv2.INTER_LINEAR(拓展时)(拓展和收缩时的默认)
-
平移
-
cv2.warpAffine(img,M,(cols,rows))
- M= np.float32([[1,0,100],[0,1,50]])(横向100,纵向50)
- 将对象换一个位置,向某个方向移动一定距离
-
旋转
-
cv2.warpAffine(img,M,(2*cols,2*rows))
-
M=cv2.getRotationMatrix2D((cols/2,rows/2),45,0.6)
- 第一个参数(cols/2,rows/2)为旋转中心
- 第二个参数 45 为旋转角度
- 第三个参数为旋转之后的缩放因子
-
仿射变换
-
dst=cv2.warpAffine(img,M,(cols,rows))
-
M=cv2.getAffineTransform(pts1,pts2)
- pts1=np.float32([[50,50],[200,50],[50,200]])
- pts2=np.float32([[10,100],[200,50],[100,250]])
- 为了创建这个矩阵我们需要从原图像中找到
三个点以及他们在输出图像中的位置
- 原图中所有的平行线在结果图像中同样平行
-
透视变换
-
cv2.warpPerspective(img,M,(300,300))
-
M=cv2.getPerspectiveTransform(pts1,pts2)
- pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
- pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
- 需要在输入图像上找 4 个点,以及他们在输出。图
像上对应的位置。这四个点中的任意三个都不能共线
- 需要一个 3x3 变换矩阵。在变换前后直线还是直线
- cv14_image_transform.py
-
图像平滑
-
2D卷积
-
cv2.filter2D(img,-1,kernel)
- kernel = np.ones((5,5),np.float32)/25
-
图像模糊
-
平均模糊
- cv2.blur(img,(5,5)) 和或cv2.boxFilter()
- 用卷积框覆盖区域所有像素的平均值来代替中心元素
-
高斯模糊
- cv2.GaussianBlur(img,(5,5),0)
- 把卷积核换成高斯核(简单来说,方框不变,将原来每个方框的值是相等的,
现在里面的值是符合高斯分布的,方框中心的值最大,其余方框根据距离
中心元素的距离递减
-
中值模糊
- cv2.medianBlur(img,5)
- 用与卷积框对应像素的中值来替代中心像素的值
- 这个滤波器经常用来去除椒盐噪声
-
双边滤波
-
cv2.bilateralFilter(img,9,75,75)
- 邻域直径,两个 75 分别是空间高斯函数标准差,灰度值相似性高斯函数标准差
- 在保持边界清晰的情况下有效的去除噪音
- cv16_image_smooth.py
-
形态学操作
-
腐蚀
-
cv2.erode(img,kernel,iterations = 1)
- kernel = np.ones((5,5),np.uint8)
-
把前景物体的边界腐蚀掉(但是前景仍然是白色)
- 所以前景物体会变小,整幅图像的白色区域会减少
- 对于去除白噪声很有用,也可以用来断开两个连在一块的物体
-
-
膨胀
-
cv2.dilate(img,kernel,iterations = 1)
- kernel = np.ones((5,5),np.uint8)
-
这个操作会增加图像中的白色区域(前景)
- 一般在去噪声时先用腐蚀再用膨胀
-
开运算
- cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
-
先进性腐蚀再进行膨胀就叫做开运算
- 它被用来去除噪声
-
闭运算
- cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
-
先膨胀再腐蚀
- 它经常被用来填充前景物体中的小洞,或者前景物体上的小黑点
-
形态学梯度
- cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
-
图像膨胀与腐蚀的差别
- 结果看上去就像前景物体的轮廓
-
礼帽操作
- cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
- 原始图像与进行开运算之后得到的图像的差
-
黑帽
- cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
- 进行闭运算之后得到的图像与原始图像的差
-
图像梯度
-
Sobel 算子
- Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好
-
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
- 参数 1,0 为只在 x 方向求一阶导数,最大可以求 2 阶导数
-
cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
- 参数 0,1 为只在 y 方向求一阶导数,最大可以求 2 阶导数。
-
Scharr 算子
- Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化
-
Laplacian 算子
-
cv2.Laplacian(img,cv2.CV_64F)
- cv2.CV_64F 输出图像的深度(数据类型),可以使用-1, 与原图像保持一致 np.uint8
-
canny边缘检测
-
原理
-
1.图像去燥
- 边缘检测很容易受到噪声影响,所以第一步
是使用 5x5 的高斯滤波器去除噪声
-
2. 计算梯度
- 对平滑后的图像使用 Sobel 算子计算水平方向和竖
直方向的一阶导数(图像梯度)(Gx 和 Gy)
-
3. 非极大值抑制
- 获得梯度的方向和大小之后,应该对整幅图
像做一个扫描,去除那些非边界上的点
-
4. 滞后阈值
- 确定那些边界才是真正的边界。这时我们需要设置两个阈值:minVal 和 maxVal。
- 当图像的灰度梯度高于 maxVal 时被认为是真的边界,那些低于 minVal 的边界会被抛弃
-
参数
-
cv2.Canny(img,100,200,kernel)
- 1.图像
- 2. minVal
- 3. maxVal
- 4. 计算图像梯度的 Sobel
卷积核的大小,默认值为 3
- cv18_canny.py
-
图像金字塔
- 创建创建一组图像,这些图像是具有不同分辨率的原始图像
-
高斯金字塔和拉普拉斯金字塔
-
高斯金字塔
- 高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶部图像
中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值
-
函数
- cv2.pyrDown(higher_reso)
- 从一个高分辨率大尺寸的图像向上构建一个金子塔(尺寸变小,分辨率降低)
- cv2.pyrUp(lower_reso)
- 从一个低分辨率小尺寸的图像向下构建一个金子塔(尺寸变大,但分辨率不会增加)
-
拉普拉斯金字塔
- 拉普拉金字塔的图像看起来就像边界图,其中很多像素都是 0。他们经常被用在图像压缩中
-
图像融合
- 1. 读入两幅图像
- 2. 构建两幅图像的图像金字塔
- 3. 根据高斯金字塔构建拉普拉斯金字塔
- 4. 在拉普拉斯的每一层进行图像融合
- 5. 根据融合之后的图像金字塔重构原始图像
- cv20_pyrmaid.py
-
图像轮廓
-
轮廓
- 将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度
-
注意
- 1. 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测
- 2. 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图
像的话,你应该将原始图像存储到其他变量中
- 3. 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体。你应该记住,
要找的物体应该是白色而背景应该是黑色
-
函数
-
cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
-
参数
- 1.原始图像
- 2. 轮廓检索模式
- 3. 轮廓近似方法
-
返回值
- 1. 原始图像
- 2 轮廓
- 3. 轮廓的层析结构。每个轮廓是Numpy数组,包含对象边界点坐标
-
轮廓的特征
-
矩
- cv2.moments()
- 计算图像的质心
-
面积
- cv2.contourArea(cnt)
-
周长
- cv2.arcLength(cnt,True)
-
轮廓近似
- 将轮廓形状近似到另外一种由更少点组成的轮廓形状,
新轮廓的点的数目由我们设定的准确度来决定
-
approx = cv2.approxPolyDP(cnt,epsilon,True)
- epsilon = 0.1*cv2.arcLength(cnt,True)
- 是从原始轮廓到近似轮廓的最大距离
-
凸包
-
cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
- points 我们要传入的轮廓
- hull 输出,通常不需要
- clockwise 方向标志。如果设置为 True,输出的
凸包是顺时针方向的。否则为逆时针方向
- returnPoints: 返回凸包上点的坐标
- 用来检测一个曲线是否具有凸性缺陷,并能纠正缺陷
-
边界矩形
- x,y,w,h = cv2.boundingRect(cnt)
-
最小外接圆
- cv2.minEnclosingCircle(cnt)
- 找到一个对象的外切圆,它是所有能够包括对象的圆中面积最小的一个
-
椭圆拟合
-
cv2.ellipse(im,ellipse,(0,255,0),2)
- ellipse = cv2.fitEllipse(cnt)
- 旋转边界矩形的内切圆
-
直线拟合
- cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
- 根据一组点拟合出一条直线,同样我们也
可以为图像中的白色点拟合出一条直线
-
轮廓:更多的函数
-
凸缺陷
-
cv2.convexityDefects(cnt,hull)
- hull = cv2.convexHull(cnt,returnPoints = False)
- 返回一个数组,其中每一行包含的值是 [起点,终点,
最远的点,到最远点的近似距离]
-
多点测试
- cv2.pointPolygonTest(cnt,(50,50),True)
- 求解图像中的一个点到一个对象轮廓的最短距离。如果点在轮廓的外部,
- 返回值为负。如果在轮廓上,返回值为 0。如果在轮廓内部,返回值为正
-
形状匹配
- cv2.matchShapes(cnt1,cnt2,1,0.0)
- 比较两个形状或轮廓的相似度。如果返回值越小,匹配越好
-
轮廓的层次结构
- 一个形状在另外一个形状的内部。这种情况下我们称外部的形状为父,内部的形状为子
- 每一个轮廓都包含自己的信息:谁是父,谁是子等。
-
OpenCV 使用一个含有四个元素的数组表示。 [Next, Previous,First_Child, Parent]。
- Next 表示同一级组织结构中的下一个轮廓
- Previous 表示同一级结构中的前一个轮廓
- First_Child 表示它的第一个子轮廓
- Parent 表示它的父轮廓
-
轮廓检索模式
-
cv2.RETR_LIST
- 提取所有的轮廓,而不去创建任何父子关系
-
cv2.RETR_TREE
- 返回所有轮廓,并且创建一个完整的组织结构列表。
它甚至会告诉你谁是爷爷,爸爸,儿子,孙子等
-
cv2.RETR_CCOMP
- 返回所有的轮廓并将轮廓分为两级组织结构。
-
cv2.RETR_EXTERNAL
- 只会返回最外边的的轮廓,所有的子轮廓都会被忽略掉
-
直方图
- 通过直方图我们可以对图像的对比度,亮度,灰度分布等有一个直观的认识
-
统计直方图
-
cv2:calcHist(images; channels; mask; histSize; ranges[; hist[; accumulate]])
- channels: 同样需要用中括号括起来,如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0], [1], [2]
- Mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如
果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像
- histSize:BIN 的数目。也应该用中括号括起来
- ranges: 像素值范围,通常为 [0, 256]
-
直方图均衡化
- 高质量的图像应该像素分布范围广,直方图可以对低质量图做横向拉伸
- cv2.equalizeHist(img)
-
CLAHE 有限对比适应性直方图均衡化
- 使用自适应的直方图均衡化。这种情况下,整幅图像会
被分成很多小块然后再对每一个小块分别进行直方图均衡化
- clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
-
2D直方图
- 要绘制颜色直方图的话,我们首先需要将图像的颜色空间从 BGR 转换到 HSV
-
函数的参数要做修改
- channels=[0,1]:同时处理H和S通道
- bins=[180,256]:H通道为180,S通道为256
- range=[0,180,0,256]分别对应H和S
-
直方图反向投影
- 可以用来做图像分割,或者在图像中找寻我们感兴趣的部分
- 它会输出与输入图像(待搜索)同样大小的图像,其中的每一个像素值
代表了输入图像上对应点属于目标对象的概率
- cv22_histgragh.py
-
模板匹配
- 在一副大图中搜寻查找模版图像位置的方法
-
cv2.matchTemplate(img,tempt,method)
- 如果输入图像的大小是(WxH),模板的大小是(wxh),
输出的结果的大小就是(W-w+1, H-h+1)
- img:需要匹配的图像
- tempt:需要匹配的模板
-
method:匹配方法
- cv2.TM_CCOEFF
- cv2.TM_CCOEFF_NORMED
- cv2.TM_CCORR
- cv2.TM_CCORR_NORMED
- cv2.TM_SQDIFF
- cv2.TM_SQDIFF_NORMED
- cv24_templatematch.py
- hough圆变换