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