参考:https://github.com/makelove/OpenCV-Python-Tutorial


ch21-轮廓Contours

21.1.2 怎样绘制轮廓.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午7:49
# @Author  : play4fun
# @File    : 21.1.2 怎样绘制轮轮廓.py
# @Software: PyCharm

"""
21.1.2 怎样绘制轮轮廓.py:
函数 cv2.drawContours() 可以 用来绘制 轮廓。它可以根据你提供 的 界点绘制任何形状。
第一个参数是原始图像 
第二个参数是 轮廓 一 个 Python 列表。
第三个参数是 轮廓的索引
在绘制独立 轮廓是很有用 当 设置为 -1 时绘制所有轮廓 。
接下来的参数是 轮廓的颜色和厚度等。
"""

import numpy as np
import cv2

im = cv2.imread('../data/cards.png')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow('imgray', imgray)

ret, thresh = cv2.threshold(imgray, 244, 255, 0)

img, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print('len(contours', len(contours))
contours2=[cnt for cnt in contours if cv2.contourArea(cnt)>200]#过滤太小的contour
print('过滤太小的contour', len(contours2))

# cv2.drawContours(imgray, contours, -1, (0, 0,255), 3)
cv2.drawContours(im, contours, -1, (255, 0, 0), 3)

if len(contours) > 4:
    # To gdraw an individual contour, say 4th contour:
    # 绘制独立 轮廓 如第四个 轮廓
    cv2.drawContours(image=im, contours=contours, contourIdx=3, color=(0, 0, 255), thickness=3)
    # drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

    # But most of the time, below method will be useful:
    # 但是大多数时候 下 的方法更有用
    cnt = contours[4]
    cv2.drawContours(im, [cnt], 0, (0, 255, 0), 3)

# 第一个contour
print('contours[0]:', contours[0])
cv2.drawContours(imgray, contours[0], 0, (0, 0, 255), 3)

'''
 这个参数如果 设置为 cv2.CHAIN_APPROX_NONE 
 所有的边界点 都 会被存储。但是我们真的需要那么多点吗 ?
 例如 当我们找的边界是一条直线时。你需要直线上所有的点来表示直线吗 ?
 不是的 我们只需要1 条直线 的两个端点而已。 
 就是 cv2.CHAIN_APPROX_SIMPLE  做的。它会
将 轮廓上的冗余点 去掉, 压缩 轮廓 ,从而节省内存开支。
'''

cv2.imshow('drawContours', im)
cv2.imshow('drawContours-', imgray)
cv2.waitKey(0)

21.4 轮廓-更多函数.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午8:47
# @Author  : play4fun
# @File    : 21.4 轮廓-更多函数.py
# @Software: PyCharm

"""
21.4 轮廓-更多函数.py:
"""

import cv2
import numpy as np

'''
Point Polygon Test
求 图像中的一个点到一个对  廓的最短 离。如果点在 廓的外    回值为 。如果在 廓上  回值为 0。如果在 廓内   回值为正。
下 我们以点 50 50 为例 

dist = cv2.pointPolygonTest(cnt,(50,50),True)

此函数的第三个参数是 measureDist。如果 置为 True 就会 算最 短 离。如果是 False 只会判断 个点与 廓之 的位置关系  回值为 +1 -1 0 

 注意 如果你不  知 具体 离 建 你将第三个参数 为 False  这样速度会提  2 到 3 倍。
'''

21.4.3-形状匹配.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午9:30
# @Author  : play4fun
# @File    : 21.4.3-形状匹配.py
# @Software: PyCharm

"""
21.4.3-形状匹配.py:
函数 cv2.matchShape() 可以帮我们比 两个形状或 廓的相似度。
如果返回值越小, 匹配越好。它是根据 Hu 矩来计算的。文档中对不同的方法有解释。

"""

import cv2
import numpy as np

img1 = cv2.imread('star.jpg', 0)
img2 = cv2.imread('star2.jpg', 0)

ret, thresh = cv2.threshold(img1, 127, 255, 0)
ret, thresh2 = cv2.threshold(img2, 127, 255, 0)

image,contours, hierarchy = cv2.findContours(thresh, 2, 1)
cnt1 = contours[0]
image,contours, hierarchy = cv2.findContours(thresh2, 2, 1)
cnt2 = contours[0]

ret = cv2.matchShapes(cnt1, cnt2, 1, 0.0)
print(ret)

#Hu 矩是归一化中心矩的线性组合
# 之所以 样做是为了能够获取 代表图像的某个特征的矩函数
# 这些矩函数对某些变化如缩放 旋转,  镜像映射  ( 除了 h1) 具有不变形。

21-findContour.py

# -*- coding: utf-8 -*-

import numpy as np
import cv2

# im = cv2.imread('test.jpg')#
# im = cv2.imread('poker5hearts.jpg')#
# im = cv2.imread('../data/black-white-rect.png')#contour.jpg #
im = cv2.imread('../data/chessboard.jpeg')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

cv2.imshow("imgray", imgray)

#需要注意的是cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图)
# 所以读取的图像要先转成灰度的,再转成二值图
# ret, thresh = cv2.threshold(imgray, 0, 25, 0)
# ret, thresh = cv2.threshold(imgray, 0, 100, 0)
ret, thresh = cv2.threshold(src=imgray, thresh=127, maxval=255, type=cv2.THRESH_BINARY)#src, thresh, maxval, type

cv2.imshow("thresh", thresh)
#轮廓提取模式 Contour_Retrieval_Mode
image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print("contours size: ", len(contours))

img = cv2.drawContours(im, contours, -1, (0,255,0), 3)
# img = cv2.drawContours(im, contours, 3, (255, 0, 0), 3)

cv2.namedWindow("contour.jpg", 0)
cv2.imshow("contour.jpg", img)
cv2.waitKey(0)

21-moments.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-23 下午12:56
图像的矩可以帮助我们计算图像的质心, 面积等。
"""

import cv2
import numpy as np

from pprint import pprint

img = cv2.imread('../data/star.png', 0)
# img = cv2.imread('../data/box.png', 0)

ret, thresh = cv2.threshold(img, 127, 255, 0)
# ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
# contours,hierarchy = cv2.findContours(thresh, 1, 2)
image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

print('contours len:', len(contours))

cnt = contours[0]  # 第一个
M = cv2.moments(cnt)

# print(M)
pprint(M)  # 好看一点

# 根据 这些矩的值 我们可以 计算出对象的重心
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
print('重心:', cx, cy)

#
area = cv2.contourArea(cnt)
print('面积:', area)

# 第二参数可以用来指定对象的形状是闭合的 True   是打开的FALSE 一条曲线 。
perimeter = cv2.arcLength(cnt, True)
print('周长:', perimeter)

'''
将轮廓形状近似到另外一种由更少点组成的 廓形状 新 廓的点的数目 由我们 定的准确度来决定。
使用的Douglas-Peucker算法 
为了帮助理解,假设我们 在一幅图像中查找一个矩形 
但是由于图像的 种种原因,我们不能得到一个完美的矩形 而是一个 坏形状 如下图所示 。 

现在你就可以使用这个函数来近似 个形状  了。
 这个函数的第二个参数叫 epsilon 它是从原始 廓到近似轮廓的最大距离。它是一个准确度参数。  
 选择一个好的 epsilon 对于得到满意结果非常重要
'''
epsilon = 0.1*cv2.arcLength(cnt,True)
print('epsilon:',epsilon)

approx = cv2.approxPolyDP(cnt,epsilon,True)
cv2.drawContours(image,[approx],0,(255,0,0),3)
cv2.imshow('approxPolyDP',image)

cv2.waitKey(0)
cv2.destroyAllWindows()

draw最大的轮廓.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/21 下午4:11
# @Author  : play4fun
# @File    : draw最大的轮廓.py
# @Software: PyCharm

"""
draw最大的轮廓.py:
"""

import cv2
import numpy as np

org = cv2.imread('../data/cards.png')

imgray = cv2.cvtColor(org, cv2.COLOR_BGR2GRAY)
cv2.imshow('imgray', imgray)

# 白色背景
ret, threshold = cv2.threshold(imgray, 244, 255, cv2.THRESH_BINARY_INV)  # 把黑白颜色反转
cv2.imshow('after threshold', threshold)

image, contours, hierarchy = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

areas = list()
for i, cnt in enumerate(contours):
    areas.append((i, cv2.contourArea(cnt)))#面积大小

#
a2 = sorted(areas, key=lambda d: d[1], reverse=True)#按面积大小,从大到小排序

cv2.waitKey(0)#要先按一下键盘
for i, are in a2:
    if are < 150:
        continue
    img22 = org.copy()#逐个contour 显示
    cv2.drawContours(img22, contours, i, (0, 0, 255), 3)
    print(i, are)

    cv2.imshow('drawContours', img22)
    cv2.moveWindow('drawContours', x=img22.shape[1], y=0)  # 右边
    k = cv2.waitKey(500)
    if k == ord('q'):
        break

# 获取最大或某个contour,剪切
idx = a2[1][0]
mask = np.zeros_like(org)  # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, (0, 255, 0), -1)  # Draw filled contour in mask
out = np.zeros_like(org)  # Extract out the object and place into output image
out[mask == 255] = org[mask == 255]
cv2.imwrite('out_contour.jpg', out)

# roi方法
idx = a2[4][0]
x, y, w, h = cv2.boundingRect(contours[idx])
roi = org[y:y + h, x:x + w]
cv2.imwrite('out_contour-roi4.jpg', roi)

cv2.destroyAllWindows()

findContours2.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/5 下午5:33
# @Author  : play4fun
# @File    : findContours2.py
# @Software: PyCharm

"""
findContours2.py:
http://blog.csdn.net/sunny2038/article/details/12889059
"""

import cv2

img = cv2.imread('contour.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

cv2.imshow("thresh", binary)

# contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
image, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print("contours size: ", len(contours))

cv2.drawContours(img, contours, -1, (0, 0, 255), 3)

cv2.imshow("img", img)
cv2.waitKey(0)

minAreaRect-旋转矩形.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/27 12:33
# @Author  : play4fun
# @File    : minAreaRect-旋转矩形.py
# @Software: PyCharm

"""
minAreaRect-旋转矩形.py:
"""

import cv2
import numpy as np

img = cv2.imread('../data/lightning.png')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

image, contours, hierarchy = cv2.findContours(imgray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 100]
print('len(contours)', len(contours))
cnt = contours[0]

#方向是物体定向的角度
(x, y), (MA, ma), angle = cv2.fitEllipse(cnt)
print((x, y), (MA, ma), angle)

rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
img = cv2.drawContours(img, [box], 0, (0, 0, 255), 2)

cv2.imshow('fd', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

轮廓的性质.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午8:38
# @Author  : play4fun
# @File    : 轮廓的性质.py
# @Software: PyCharm

"""
轮廓的性质.py:
"""
import cv2
import numpy as np

# 边界矩形的宽高比
x, y, w, h = cv2.boundingRect(cnt)
aspect_ratio = float(w) / h

# Extent轮廓面积与边界矩形面积的比。
area = cv2.contourArea(cnt)
x, y, w, h = cv2.boundingRect(cnt)
rect_area = w * h
extent = float(area) / rect_area

# Solidity轮廓面积与凸包面积的比。
area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area) / hull_area

# Equivalent Diameter与轮廓面积相等的圆形的直径
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4 * area / np.pi)

# Orientation对象的方向 下 的方法 会返回  长轴和短轴的长度
(x, y), (MA, ma), angle = cv2.fitEllipse(cnt)

# Mask and Pixel Points掩模和像素点
mask = np.zeros(imgray.shape, np.uint8)
cv2.drawContours(mask, [cnt], 0, 255, -1)
pixelpoints = np.transpose(np.nonzero(mask))
# pixelpoints = cv2.findNonZero(mask)
# 第一种方法使用了 Numpy 函数
# 第二种使用 了 OpenCV 函数。
# 结果相同 但还是有点不同。Numpy 给出的坐标是 (row ,colum)
# 而 OpenCV 给出的格式是 (x y )形式的。所以 两个结果基 本是可以互换的。row=x ,colunm=y。

# 最大值和最小值及它们的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray, mask=mask)

# 平均 色及平均灰度 我们也可以使用相同的掩模求一个对 的平均 色或平均灰度
mean_val = cv2.mean(im, mask=mask)

# 极点 一个对象最上面  最下面  最左  最右 的点。
leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])
rightmost = tuple(cnt[cnt[:, :, 0].argmax()][0])
topmost = tuple(cnt[cnt[:, :, 1].argmin()][0])
bottommost = tuple(cnt[cnt[:, :, 1].argmax()][0])

凸包-凸性检测-边界矩形-最小外接圆-拟合.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午8:28
# @Author  : play4fun
# @File    : 凸包-凸性检测-边界矩形-最小外接圆-拟合.py
# @Software: PyCharm

"""
凸包-凸性检测-边界矩形-最小外接圆-拟合.py:
"""
import cv2
import numpy as np

img=cv2.imread('../data/lightning.png',0)

image, contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cnt=contours[0]
'''
函数 cv2.convexHull() 可以用来检测一个曲线是否具有凸性缺  并能纠 正缺 。一般来  凸性曲线总是凸出来的 至少是平的。如果有地方凹 去 了就 叫做凸性缺 
例如下图中的手。红色曲线显示了手的凸包 凸性缺   双箭头标出来了。
'''
# convexHull(points, hull=None, clockwise=None, returnPoints=None)
hull = cv2.convexHull(points, hull, clockwise, returnPoints)

'''
points 我们 传入的 廓
• hull  输出  通常不需要  
• clockwise 方向标志。如果 置为 True  出的凸包是顺时针 方向的。 否则为逆时针 方向。
• returnPoints   值为 True。它会 回凸包上点的坐标。如果 置 为 False 就会 回与凸包点对应的 廓上的点。
'''
hull = cv2.convexHull(cnt)

# 凸性检测
# 函数 cv2.isContourConvex() 可以可以用来检测一个曲线是不是凸的。它只能 回 True 或 False。没什么大不了的。
k = cv2.isContourConvex(cnt)

# 边界矩形
'''
直边界矩形 一个直矩形 就是没有旋转的矩形 。它不会考虑对象是否旋转。 所以边界矩形的 积不是最小的。可以使用函数 cv2.boundingRect() 查 找得到。
 x y 为矩形左上角的坐标 w h 是矩形的宽和 。
'''
x, y, w, h = cv2.boundingRect(cnt)
img = cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

'''
旋转矩形
这里,以最小面积绘制边界矩形,因此也考虑旋转。使用的功能是cv2.minAreaRect()。它返回一个Box2D结构,其中包含以下条件 - (中心(x,y),(宽度,高度),旋转角度)。但是要绘制这个矩形,我们需要矩形的四个角。它是通过函数cv2.boxPoints()
'''
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(0,0,255),2)

# 最小外接圆
# 函数 cv2.minEnclosingCircle() 可以帮我们找到一个对 的外切圆。它是所有能够包括对 的圆中 积最小的一个。
(x, y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
img = cv2.circle(img, center, radius, (0, 255, 0), 2)

# 椭圆拟合
# 使用的函数为 cv2.ellipse()  回值其实就是旋  界矩形的内切圆
ellipse = cv2.fitEllipse(cnt)
#((135.34278869628906, 134.22764587402344),(57.018402099609375, 166.91265869140625),136.8311767578125)
angle=ellipse[2]
im = cv2.ellipse(img, ellipse, (0, 255, 0), 2)

# 直线拟合
# 我们可以根据一组点拟合出一条直线 同样我们也可以为图像中的白色点 拟合出一条直线。
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv2.fitLine(cnt, cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
cv2.line(img, (cols - 1, righty), (0, lefty), (0, 255, 0), 2)

凸缺陷.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午9:25
# @Author  : play4fun
# @File    : 凸缺陷.py
# @Software: PyCharm

"""
凸缺陷.py:
"""

# 凸缺陷
# 前 我们已经学习了 廓的凸包 对 上的任何凹   成为凸缺 。
# OpenCV 中有一个函数 cv.convexityDefect() 可以帮助我们找到凸缺


# hull = cv2.convexHull(cnt, returnPoints=False)
# defects = cv2.convexityDefects(cnt, hull)


# 注意 如果 查找凸缺  在使用函数 cv2.convexHull 找凸包时 参数 returnPoints 一定 是 False
'''
它会 回一个数组 其中每一 包含的值是 [ 点 终点 最 的点 到最  点的 似 离]。我们可以在一张图上显示它。我们将 点和终点用一条绿线  接 在最 点画一个圆圈   住的是 回结果的前三个值是 廓点的索引。 所以我们  到 廓点中去找它们。
'''
import cv2
import numpy as np

img = cv2.imread('star.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(img_gray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, 2, 1)

cnt = contours[0]
hull = cv2.convexHull(cnt, returnPoints=False)
defects = cv2.convexityDefects(cnt, hull)

for i in range(defects.shape[0]):
    s, e, f, d = defects[i, 0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv2.line(img, start, end, [0, 255, 0], 2)
    cv2.circle(img, far, 5, [0, 0, 255], -1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

ch22-直方图

22.1.2-绘制直方图-matplotlib.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:17
"""

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

img = cv2.imread('../data/home.jpg', 0)
# img.ravel() 将图像转成一维数组   没有中括号
plt.hist(img.ravel(), 256, [0, 256])
plt.show()

22.2.2-CLAHE有限对比适应性直方图均衡化.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午10:18
# @Author  : play4fun
# @File    : 22.2.2-CLAHE有限对比适应性直方图均衡化.py
# @Software: PyCharm

"""
22.2.2-CLAHE有限对比适应性直方图均衡化.py:

自 应的直方图均 化。 种情况下  整幅图像会 分成很多小块  些小块 称为 tiles
在 OpenCV 中 tiles 的 大小  是 8x8
然后再对每一个小块分别  直方图均 化  前 类似 。 所以在每一个的区域中 直方图会 中在某一个小的区域中   有噪声干 扰 。

如果有噪声的  噪声会 放大。为了 免 种情况的出现 使用对比度  制。对于每个小块来  如果直方图中的 bin   对比度的上 的  就把 其中的像素点均匀分散到其他 bins 中 然后在  直方图均 化。

最后 为了 去 每一个小块之  人 的 由于算法 成  界 再使用双线性差值 对 小块  缝合。

"""

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)

22.3.4.hsv_hist-绘制2D直方图.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-11-8 下午4:44
绘制2D直方图
"""

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

img = cv2.imread('../data/home.jpg')
# cv2.imshow("src", img)

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()

22.3-2D直方图.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午10:32
# @Author  : play4fun
# @File    : 22.3-2D直方图.py
# @Software: PyCharm

"""
22.3-2D直方图.py:
一维 是因为 我们只考 了图像的一个特征:灰度值。
但是在 2D 直方图中我们就 考虑  两个图像特征。

对于彩色图像的直方图通常情况下我们  考 每个的颜色
 Hue 和 饱和度 Saturation 。
 根据 两个特征绘制 2D 直方图。

 使用函数 cv2.calcHist() 来 算直方图既简单又方便。如果 绘制颜色直方图的话, 我们 先  将图像的颜色空间从 BGR  换到 HSV 计算 2D 直方图
 记住   计算一维直方图  从 BGR  换到 HSV 。
 函数的参数  做如下修改
• channels=[0 1] 因为我们  同时处理 H 和 S 两个  。
• bins=[180 256]H   为 180 S   为 256。
• range=[0 180 0 256]H 的取值范围在 0 到 180 S 的取值范围 在 0 到 256。

"""

import cv2
import numpy as np

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

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

# Numpy 同样提供了绘制 2D 直方图的函数 np.histogram2d()。
# 绘制 1D 直方图时我们使用的是 np.histogram() 。

h, s, v = cv2.split(hsv)

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

pass

22.4-OpenCV中的反向投影.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午11:06
# @Author  : play4fun
# @File    : 22.4-OpenCV中的反向投影.py
# @Software: PyCharm

"""
22.4-OpenCV中的反向投影.py:
OpenCV 提供的函数 cv2.calcBackProject() 可以用来做直方图反向 投影。
它的参数与函数 cv2.calcHist 的参数基本相同。
其中的一个参数是我 们 查找目标的直方图。
同样再使用目标的直方图做反向投影之前
我们应 先 对其做归一化处理。
 返回的结果是一个概率图像 我们再使用一个圆盘形卷积 核对其做卷操作 最后使用 值  二值化
"""

import cv2
import numpy as np

roi = cv2.imread('tar.jpg')
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
target = cv2.imread('roi.jpg')
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.NORM_MINMAX 对数组的所有值进行转化 使它们线性映射到最小值和最大值之  间
#  归一化之后的直方图便于显示 归一化之后就成了 0 到 255 之 的数了。
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))
dst = cv2.filter2D(dst, -1, disc)
# threshold and binary AND
ret, thresh = cv2.threshold(dst, 50, 255, 0)

# 别忘了是三  图像 因此  使用 merge 变成 3
thresh = cv2.merge((thresh, thresh, thresh))

# 按位操作
res = cv2.bitwise_and(target, thresh)
res = np.hstack((target, thresh, res))
cv2.imwrite('res.jpg', res)

# 显示图像
cv2.imshow('1', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

22.4-直方图反向投影.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午11:01
# @Author  : play4fun
# @File    : 22.4-直方图反向投影.py
# @Software: PyCharm

"""
22.4-直方图反向投影.py:

直方图反向投影是由 Michael J. Swain 和 Dana H. Ballard 在他们的 文章 Indexing via color histograms 中提出。

 它到底是什么呢 它可以用来做图像分割 或者在图像中找寻我们感兴  的 分。
 简单来  它会 出与 入图像 待搜索 同样大小的图像 其中 的每一个像素值代 了 入图像上对应点属于目标对 的概率。
 用更简单的  来   输出图像中像素值越高(越白) 的点就 可能代表我们 搜索的目标
 在输入图像所在的位置 。
 这是一个直观的解释  。

 直方图投影经常与 camshift 算法等一 使用。



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

# Numpy 中的算法

# 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])

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

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

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

hist.py

#!/usr/bin/env python

''' This is a sample for histogram plotting for RGB images and grayscale images for better understanding of colour distribution

Benefit : Learn how to draw histogram of images
          Get familier with cv2.calcHist, cv2.equalizeHist,cv2.normalize and some drawing functions

Level : Beginner or Intermediate

Functions : 1) hist_curve : returns histogram of an image drawn as curves
            2) hist_lines : return histogram of an image drawn as bins ( only for grayscale images )

Usage : python hist.py <image_file>

Abid Rahman 3/14/12 debug Gary Bradski
'''

import cv2
import numpy as np

bins = np.arange(256).reshape(256, 1)


def hist_curve(im):
    h = np.zeros((300, 256, 3))
    if len(im.shape) == 2:
        color = [(255, 255, 255)]
    elif im.shape[2] == 3:
        color = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
    for ch, col in enumerate(color):
        hist_item = cv2.calcHist([im], [ch], None, [256], [0, 256])
        cv2.normalize(hist_item, hist_item, 0, 255, cv2.NORM_MINMAX)
        hist = np.int32(np.around(hist_item))
        pts = np.int32(np.column_stack((bins, hist)))
        cv2.polylines(h, [pts], False, col)
    y = np.flipud(h)
    return y


def hist_lines(im):
    h = np.zeros((300, 256, 3))
    if len(im.shape) != 2:
        print("hist_lines applicable only for grayscale images")
        # print "so converting image to grayscale for representation"
        im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
    hist_item = cv2.calcHist([im], [0], None, [256], [0, 256])
    cv2.normalize(hist_item, hist_item, 0, 255, cv2.NORM_MINMAX)
    hist = np.int32(np.around(hist_item))
    for x, y in enumerate(hist):
        cv2.line(h, (x, 0), (x, y), (255, 255, 255))
    y = np.flipud(h)
    return y


if __name__ == '__main__':

    import sys

    if len(sys.argv) > 1:
        fname = sys.argv[1]
    else:
        fname = '../data/lena.jpg'
        print("usage : python hist.py <image_file>")

    im = cv2.imread(fname)

    if im is None:
        print('Failed to load image file:', fname)
        sys.exit(1)

    gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

    print(''' Histogram plotting \n
    Keymap :\n
    a - show histogram for color image in curve mode \n
    b - show histogram in bin mode \n
    c - show equalized histogram (always in bin mode) \n
    d - show histogram for color image in curve mode \n
    e - show histogram for a normalized image in curve mode \n
    Esc - exit \n
    ''')

    cv2.imshow('image', im)
    while True:
        k = cv2.waitKey(0) & 0xFF
        if k == ord('a'):
            curve = hist_curve(im)
            cv2.imshow('histogram', curve)
            cv2.imshow('image', im)
            print('a')
        elif k == ord('b'):
            print('b')
            lines = hist_lines(im)
            cv2.imshow('histogram', lines)
            cv2.imshow('image', gray)
        elif k == ord('c'):
            print('c')
            equ = cv2.equalizeHist(gray)
            lines = hist_lines(equ)
            cv2.imshow('histogram', lines)
            cv2.imshow('image', equ)
        elif k == ord('d'):
            print('d')

            curve = hist_curve(gray)
            cv2.imshow('histogram', curve)
            cv2.imshow('image', gray)
        elif k == ord('e'):
            print('e')

            norm = np.ndarray((2, 2))
            norm = cv2.normalize(gray, norm, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)

            lines = hist_lines(norm)
            cv2.imshow('histogram', lines)
            cv2.imshow('image', norm)
        elif k == 27:
            print('ESC')

            cv2.destroyAllWindows()
            break
    cv2.destroyAllWindows()

hist-bgr多通道.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:19
同时绘制多通道 BGR 
"""

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

img = cv2.imread('../data/home.jpg')
color = ('b', 'g', 'r')
# 对一个列表或数组既要遍历索引又要遍历元素时
# 使用内置 enumerrate 函数会有更加直接 优美的做法
# enumerate 会将数组或列表组成一个索引序列。
# 使我们再获取索引和索引内容的时候更加方便
for i, col in enumerate(color):
    histr = cv2.calcHist([img], [i], None, [256], [0, 256])
    plt.plot(histr, color=col)
    plt.xlim([0, 256])
plt.show()

hist-normalized-numpy.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:26
直方图均衡化

想 一下如果一副图像中的大多是像素点的像素值  中在一个像素值范 围之内会怎样呢 例如 如果一幅图片整体很亮  所有的像素值应  会很  。但是一副   的图像的像素值分布应 很广泛。所以你应 把它的直方 图做一个横向拉伸 如下图   就是直方图均 化 做的事情。 常情况下  种操作会改善图像的对比度。
"""

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

#怎样使用 Numpy 来进行直方图均衡化
img = cv2.imread('../data/contrast75.png', 0)
# 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()

hist-normalized-numpy-2.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:26
"""

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

img = cv2.imread('../data/contrast75.png', 0)
# flatten() 将数组变成一维
hist, bins = np.histogram(img.flatten(), 256, [0, 256])
# 计算累积分布图
cdf = hist.cumsum()

##
# 构建 Numpy 掩模数组 cdf 为原数组 当数组元素为 0 时 掩盖(计算时被忽略
cdf_m = np.ma.masked_equal(cdf, 0)
cdf_m = (cdf_m - cdf_m.min()) * 255 / (cdf_m.max() - cdf_m.min())
# 对被掩盖的元素赋值,赋值为 0
cdf = np.ma.filled(cdf_m, 0).astype('uint8')
img2 = cdf[img]
# cv2.imshow("img2",img2)
# cv2.waitKey(0)

##
# flatten() 将数组变成一维
hist, bins = np.histogram(img2.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()

'''
直方图均 化经常用来使所有的图片具有相同的亮度条件的参考 工具。 在很多情况下 很有用。例如 脸  别 在 练分类器前  练  的所有图片  先  直方图均 化从而使它们 到相同的亮度条件。
'''

mask.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:22

 统计图像某个局部区域的直方图只需要构建一副掩模图像。
 将要统计的 部分设置成白色 其余 分为黑色 就构成了一副掩模图像。
 然后把这个掩模 图像传给函数就可以了。

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

img = cv2.imread('../data/home.jpg', 0)

# create a mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img, img, mask=mask)

# Calculate histogram with mask and without mask
# Check third argument for mask
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])

plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()
# 蓝线是整幅图像的直方图 绿线是进行掩模之后的直方图

使用OpenCV进行直方图均衡化.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午10:16
# @Author  : play4fun
# @File    : 使用OpenCV进行直方图均衡化.py
# @Software: PyCharm

"""
使用OpenCV进行直方图均衡化.py:
"""
import cv2
import numpy as np

img = cv2.imread('wiki.jpg', 0)
equ = cv2.equalizeHist(img)
res = np.hstack((img, equ))  # stacking images side-by-side
cv2.imwrite('res.png', res)

'''
当直方图中的数据 中在某一个灰度值范围内时 直方图均 化很有用。 但是如果像素的变化很大 而且占据的灰度范围 常广时 例如 既有很亮的 像素点又有很暗的像素点时
'''

ch23-图像变换

23.1.3 DFT 的性能优化.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/13 上午11:12
# @Author  : play4fun
# @File    : 23.1.3 DFT 的性能优化.py
# @Software: PyCharm

"""
23.1.3 DFT 的性能优化.py:
"""
import numpy as np

# In [16]: img = cv2.imread('messi5.jpg',0)
# In [17]: rows,cols = img.shape
# In [18]: print rows,cols
# 342 548
# In [19]: nrows = cv2.getOptimalDFTSize(rows)
# In [20]: ncols = cv2.getOptimalDFTSize(cols)
# In [21]: print nrows, ncols
# 360 57

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

#或者
right = ncols - cols
bottom = nrows - rows
#just to avoid line breakup in PDF file
bordertype = cv2.BORDER_CONSTANT
nimg = cv2.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)

#现在我们看看 Numpy 的 现

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= cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 13.5 ms per loop

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

23.1.4 为什么拉普拉斯算子是高通滤波器.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/13 上午11:18
# @Author  : play4fun
# @File    : 23.1.4 为什么拉普拉斯算子是高通滤波器.py
# @Software: PyCharm

"""
23.1.4 为什么拉普拉斯算子是高通滤波器.py:
从图像中我们就可以看出每一个算子允    些信号。从 些信息中我 们就可以知  些是 HPF  是 LPF
"""

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

# simple averaging filter without scaling parameter
mean_filter = np.ones((3, 3))
# creating a guassian filter
x = cv2.getGaussianKernel(5, 10)

gaussian = x * x.T
# different edge detecting filters
# scharr in x-direction
scharr = np.array([[-3, 0, 3],
                   [-10, 0, 10],
                   [-3, 0, 3]])
# sobel in x direction
sobel_x = np.array([[-1, 0, 1],
                    [-2, 0, 2],
                    [-1, 0, 1]])
# sobel in y direction
sobel_y = np.array([[-1, -2, -1],
                    [0, 0, 0],
                    [1, 2, 1]])
# laplacian
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 range(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()

fftshift-abs-Numpy.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:42

现在我们可以   域变换了 我们就可以在 域对图像  一些操 作了 例如  滤波和 建图像 DFT 的 变换 。比如我们可以使用一个 60x60 的矩形窗口对图像  掩模操作从而去 低 分 。然后再使用函数 np.fft.ifftshift()    平移操作 所以现在直流分 又回到左上 了 左 后使用函数 np.ifft2()    FFT  变换。同样又得到一堆复杂的数字 我们 可以对他们取绝对值 

"""

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

img = cv2.imread('../data/messi5.jpg', 0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)

rows, cols = img.shape
crow, ccol = int(rows / 2), int(cols / 2)
fshift[crow - 30:crow + 30, ccol - 30:ccol + 30] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
# 取绝对值
img_back = np.abs(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()

'''
如果你 察仔细的  尤其是最后一章 JET  色的图像 你会看到一些不 自然的东  如我用红色箭头标出的区域 。看上图  有些条带 的结构    成为振铃效应。
 这是由于我们使用矩形窗口做掩模 成的。 个掩模  换 成正弦形状时就会出现 个  。所以一般我们不 用矩形窗口滤波。最好的  择是高斯窗口。

'''

fftshift-Numpy中的傅里叶变换.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:42

函数 np.fft.fft2() 可以对信号   率  换  出结果是一个复杂的数组。
第一个参数是 入图像  求是灰 度格式。
第二个参数是可 的, 决定 出数组的大小。
 输出数组的大小和输入图像大小一样。如果输出结果比输入图像大 
  输入图像就需要在进行 FFT 前补0。如果输出结果比输入图像小的话   输入图像就会被切割。
"""

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

img = cv2.imread('../data/messi5.jpg', 0)
f = np.fft.fft2(img)
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()

OpenCV中的傅里叶变换-DFT.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/13 上午10:59
# @Author  : play4fun
# @File    : OpenCV中的傅里叶变换-DFT.py
# @Software: PyCharm

"""
OpenCV中的傅里叶变换-DFT.py:
OpenCV 中相应的函数是 cv2.dft() 和 cv2.idft()。和前  出的结果 一样 但是是双通道的。
第一个通道是结果的实数部 分
第二个通道是结果的虚数部分。
输入图像  先 换成 np.float32 格式

使用函数 cv2.cartToPolar() 它会同时返回幅度和相位。

"""

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

img = cv2.imread('../data/messi5.jpg', 0)

dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)

dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20 * np.log(cv2.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()

OpenCV中的傅里叶变换-逆DFT.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/13 上午11:03
# @Author  : play4fun
# @File    : OpenCV中的傅里叶变换-逆DFT.py
# @Software: PyCharm

"""
OpenCV中的傅里叶变换-逆DFT.py:
在前 的 分我们实现了一个 HPF 高通滤波   现在我们来做 LPF 低通滤波 将高频分去除。其实就是对图像进行模糊操作。
 首先我们  构建一个掩模 与低 区域对应的地方 置为 1, 与  区域 对应的地方 置为 0。
"""

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

img = cv2.imread('../data/messi5.jpg', 0)

dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)

dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow, ccol = int(rows / 2), int(cols / 2)

# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow - 30:crow + 30, ccol - 30:ccol + 30] = 1

# apply mask and inverse DFT
fshift = dft_shift * mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.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()

ch24-模板匹配

24.1-OpenCV中的模板匹配-matchTemplate.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-24 下午5:46
原理
模板匹配是用来在一副大图中搜寻查找模版图像位置的方法。OpenCV 为 我们提供了函数 cv2.matchTemplate()。
和 2D 卷积一样 它也是用模板图像在输入图像 大图 上滑动 并在每一个位置对模板图像和与其对应的 输入图像的子区域  比较。
OpenCV 提供了几种不同的比较方法 细节 看 文档 。 
返回的结果是一个灰度图像 每一个像素值 示了此区域与模板的匹配 程度。
如果输入图像的大小是 WxH  
模板的大小是 wxh   输出的结果 的大小就是 W-w+1 H-h+1 。
当你得到这幅图之后 就可以使用函数 cv2.minMaxLoc() 来找到其中的最小值和最大值的位置了。
第一个值为矩形左上角的点 位置 
w h 为 moban 模板矩形的宽和 。
这个矩形就是 找到的模板区域了。
"""

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

img = cv2.imread('../data/messi5.jpg', 0)
img2 = img.copy()
template = cv2.imread('../data/messi_face.jpg', 0)

w, h = template.shape[::-1]
# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
           'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']

for meth in methods:
    img = img2.copy()

    # exec 语句用来执行储存在字符串或文件中的 Python 语句。
    # 例如,我们可以在运行时生成一个包含 Python 代码的字符串,
    # 然后使用 exec 语句执行这些语句。
    # eval 语句用来计算存储在字符串中的有效 Python 表达式
    method = eval(meth)
    # Apply template Matching
    res = cv2.matchTemplate(img, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    # 使用不同的比较方法,对结果的解释不同
    # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc

    bottom_right = (top_left[0] + w, top_left[1] + h)
    cv2.rectangle(img, top_left, bottom_right, 255, 2)

    plt.subplot(121), plt.imshow(res, cmap='gray')
    plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(img, cmap='gray')
    plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
    plt.suptitle('method: ' + meth)
    plt.show()

24.2-多对象的模板匹配-Multiple-Objects.py

'''
假如你的目标对 只在图像中出现了很多次怎么办呢
函数 cv.imMaxLoc() 只会给出最大值和最小值。此时 我们就 使用阈值了。
在下 的例子中我们 经典游戏 Mario 的一张截屏图片中找到其中的硬币

'''

import cv2
import numpy as np

# from matplotlib import pyplot as plt

img_rgb = cv2.imread('../data/mario.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('../data/mario_coin.png', 0)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(res >= threshold)
print(len(loc))

for pt in zip(*loc[::-1]):
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 255, 0), 2)
    print("rectangle 1")

# cv2.imwrite('res.png',img_rgb)
cv2.imshow("result", img_rgb)
cv2.waitKey(0)

ch25-Hough直线变换

25.1-OpenCV中的霍夫变换-HoughLines.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-25 上午11:42

cv2.HoughLines()。 返回值就是 ρ, θ 。
ρ 的单位是像素  θ 的单位是弧度。 
第一个参数是一个二值化图像 所以在进行霍夫变换之前  先进行  二值化 或者  
Canny  缘检测。
第二和第三个值分别代  ρ 和 θ 的精确度。
第四个参数是阈值, 只有累加其中的值高于阈值时才被认为是一条直线 
也可以把它看成能检测到的直线的最短长度 以像素点为单位 。
"""

import cv2
import numpy as np

img = cv2.imread('../data/sudoku.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# edges = cv2.Canny(gray,50,150,apertureSize = 3)
edges = cv2.Canny(gray, 10, 50, apertureSize=3)
cv2.imshow("edges", edges)

lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)
print("Len of lines:", len(lines))
# print lines

for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)

    # cv2.imwrite('houghlines3.jpg',img)
    cv2.imshow("houghlines3.jpg", img)
    cv2.waitKey(1000)

cv2.waitKey(0)
cv2.destroyAllWindows()

25.2-Probabilistic-Hough-Transform-HoughLinesP.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-25 上午11:53
"""

import cv2
import numpy as np

img = cv2.imread('../data/sudoku.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

minLineLength = 100
maxLineGap = 10

lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength, maxLineGap)
print("Len of lines:", len(lines))
print(lines)

for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)

# cv2.imwrite('houghlines5.jpg',img)
cv2.imshow("houghlines3.jpg", img)
cv2.waitKey(0)

HoughLinesP_camera.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/9 下午12:01
# @Author  : play4fun
# @File    : HoughLinesP_camera.py
# @Software: PyCharm

"""
HoughLinesP_camera.py:
"""

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
# ret = cap.set(3, 640)
# ret = cap.set(4, 480)

# while (True):
while cap.isOpened():
    # Capture frame-by-frame
    ret, frame = cap.read()
    # img = cv2.imread('../data/sudoku.jpg')
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150, apertureSize=3)

    minLineLength = 100
    maxLineGap = 10
    lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength, maxLineGap)
    if lines is None:
        continue
    print("Len of lines:", len(lines))
    print(lines)

    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)

    # cv2.imwrite('houghlines5.jpg',img)
    cv2.imshow("houghlines3.jpg", frame)

    key = cv2.waitKey(1)
    if key == ord("q"):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

LineSegmentDetector1.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/26 23:42
# @Author  : play4fun
# @File    : LineSegmentDetector1.py
# @Software: PyCharm

"""
LineSegmentDetector1.py:
"""
import cv2
import numpy as np

# Read gray image
img0 = cv2.imread("pokerQ.jpg")
img = cv2.cvtColor(img0,cv2.COLOR_BGR2GRAY)
cv2.imshow('pokerQ',img0)

# Create default parametrization LSD
lsd = cv2.createLineSegmentDetector(0)

# Detect lines in the image
dlines = lsd.detect(img)#TODO 返回什么?
lines = lsd.detect(img)[0]  # Position 0 of the returned tuple are the detected lines

# Draw detected lines in the image
# drawn_img = lsd.drawSegments(img, lines)

#
cv2.waitKey(0)
for dline in dlines[0]:
    x0 = int(round(dline[0][0]))
    y0 = int(round(dline[0][1]))
    x1 = int(round(dline[0][2]))
    y1 = int(round(dline[0][3]))
    cv2.line(img0, (x0, y0), (x1,y1), (0,255,0), 1, cv2.LINE_AA)
    cv2.imshow("LSD", img0)
    cv2.waitKey(200)

#TODO 最长的直线?

# Show image
# cv2.imshow("LSD", drawn_img)
# cv2.imshow("LSD", img0)
# cv2.waitKey(0)
cv2.destroyAllWindows()

ch25-斑点检测

blob.py

#!/usr/bin/python

# Standard imports
import cv2
import numpy as np;

# Read image
im = cv2.imread("blob.jpg", cv2.IMREAD_GRAYSCALE)

# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()

# Change thresholds
params.minThreshold = 10
params.maxThreshold = 200

# Filter by Area.
params.filterByArea = True
params.minArea = 1500

# Filter by Circularity
params.filterByCircularity = True
params.minCircularity = 0.1

# Filter by Convexity
params.filterByConvexity = True
params.minConvexity = 0.87

# Filter by Inertia
params.filterByInertia = True
params.minInertiaRatio = 0.01

# Create a detector with the parameters
ver = (cv2.__version__).split('.')
if int(ver[0]) < 3:
    detector = cv2.SimpleBlobDetector(params)
else:
    detector = cv2.SimpleBlobDetector_create(params)

# Detect blobs.
keypoints = detector.detect(im)

# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures
# the size of the circle corresponds to the size of blob

im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

# Show blobs
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)

blob_camera.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/24 下午5:03
# @Author  : play4fun
# @File    : blob_camera.py
# @Software: PyCharm

"""
blob_camera.py:
"""

import cv2
import numpy as np

# Read image
# im = cv2.imread("blob.jpg", cv2.IMREAD_GRAYSCALE)
# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector_create()

cap = cv2.VideoCapture(0)
while cap.isOpened():  # 检查是否成功初始化,否则就 使用函数 cap.open()
    # Capture frame-by-frame
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Detect blobs.
    keypoints = detector.detect(gray)
    # Draw detected blobs as red circles.
    # cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
    im_with_keypoints = cv2.drawKeypoints(frame, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

    # Show keypoints
    cv2.imshow("Keypoints", im_with_keypoints)

    key = cv2.waitKey(delay=1)
    if key == ord("q"):
        break

cv2.destroyAllWindows()

斑点检测SimpleBlobDetector.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/24 下午4:51
# @Author  : play4fun
# @File    : 斑点检测SimpleBlobDetector.py
# @Software: PyCharm

"""
斑点检测SimpleBlobDetector.py:
https://www.learnopencv.com/blob-detection-using-opencv-python-c/

特别要注意,默认检测黑色点,如果要检测白色的点请设置bycolor为true,并且color数值是255.


斑点通常是指与周围有着颜色和灰度差别的区域。在实际地图中,往往存在着大量这样的斑点,如一颗树是一个斑点,一块草地是一个斑点,一栋房子也可以是一个斑点。由于斑点代表的是一个区域,相比单纯的角点,它的稳定性要好,抗噪声能力要强,所以它在图像配准上扮演了很重要的角色。

同时有时图像中的斑点也是我们关心的区域,比如在医学与生物领域,我们需要从一些X光照片或细胞显微照片中提取一些具有特殊意义的斑点的位置或数量。

比如下图中天空的飞机、向日葵的花盘、X线断层图像中的两个斑点。

"""

# Standard imports
import cv2
import numpy as np

# Read image
im = cv2.imread("blob.jpg", cv2.IMREAD_GRAYSCALE)
# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector_create()
# Detect blobs.
keypoints = detector.detect(im)
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# Show keypoints
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)

ch26-Hough圆环变换

HoughCircles.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-25 下午12:02
一个圆环 需要 3 个参数来确定。所以进行圆环 夫变换的累加器必须是 3 维的
  这样的 效率 就会很低。所以 OpenCV 用来一个比 巧妙的办法 霍夫梯度法 它可以使 用边界的梯度信息。

参数:
image: 8位,单通道图像。如果使用彩色图像,请先转换为灰度。
method:定义检测图像中的圆的方法。目前,唯一实现的方法是cv2.HOUGH_GRADIENT对应于Yuen等。纸。
dp:该参数是累加器分辨率与图像分辨率的反比(详见Yuen等人)。实质上,dp获取越大,累加器数组越小。
minDist:检测到的圆的中心(x,y)坐标之间的最小距离。如果minDist太小,则可能(错误地)检测到与原始相邻的多个圆。如果minDist太大,那么一些圈子根本就不会被检测到。
param1: Yuen等人用于处理边缘检测的梯度值 方法。
param2:该cv2.HOUGH_GRADIENT方法的累加器阈值。阈值越小,检测到的圈子越多(包括虚假圈子)。阈值越大,可能会返回的圈数越多。
minRadius:半径的最小大小(以像素为单位)。
maxRadius:半径的最大大小(以像素为单位)。
"""

import cv2
import numpy as np

img = cv2.imread('../data/OpenCV_Logo_with_text.png', 0)
img = cv2.medianBlur(img, 5)
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

#HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)

circles = np.uint16(np.around(circles))
print(circles)

for i in circles[0, :]:
    # draw the outer circle
    cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
    # draw the center of the circle
    cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)

cv2.imshow('detected circles', cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()

# Python: cv2.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)
# Parameters:
# image – 8-bit, single-channel, grayscale input image.
# 返回结果为 Output vector of found circles. Each vector is encoded as a
# 3-element floating-point vector (x, y, radius) .
# circle_storage – In C function this is a memory storage that will contain
# the output sequence of found circles.
# method – Detection method to use. Currently, the only implemented method is
# CV_HOUGH_GRADIENT , which is basically 21HT , described in [Yuen90].
# dp – Inverse ratio of the accumulator resolution to the image resolution.
# For example, if dp=1 , the accumulator has the same resolution as the input image.
# If dp=2 , the accumulator has half as big width and height.
# minDist – Minimum distance between the centers of the detected circles.
# If the parameter is too small, multiple neighbor circles may be falsely
# detected in addition to a true one. If it is too large, some circles may be missed.
# param1 – First method-specific parameter. In case of CV_HOUGH_GRADIENT ,
# it is the higher threshold of the two passed to the Canny() edge detector
# (the lower one is twice smaller).
# param2 – Second method-specific parameter. In case of CV_HOUGH_GRADIENT ,
# it is the accumulator threshold for the circle centers at the detection stage.
# The smaller it is, the more false circles may be detected. Circles,
# corresponding to the larger accumulator values, will be returned first.
# minRadius – Minimum circle radius.
# maxRadius – Maximum circle radius.

HoughCircles_camera.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/27 13:47
# @Author  : play4fun
# @File    : HoughCircles_camera.py
# @Software: PyCharm

"""
HoughCircles_camera.py:

用围棋-棋子来测试
"""

import cv2
import numpy as np
from skimage.measure import compare_mse as mse
import string, random


def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))


cap = cv2.VideoCapture(0)

# ret = cap.set(3, 640)
# ret = cap.set(4, 480)

# margin = 60
margin = 30


def draw_line_rectangle(frame, margin):
    rows, cols, ch = frame.shape  # (720, 1280, 3)
    half = int(cols / 2)
    # 中间
    cv2.line(frame, (half, 0), (half, rows), (0, 0, 255), 2)

    # margin = 40
    # 左边
    up_left1 = (margin, margin)  # 左上点
    down_right1 = (cols - margin, rows - margin)  # 右下点
    # print(up_left, down_right)
    cv2.rectangle(frame, up_left1, down_right1, (0, 255, 0), 3)


ret, temp = cap.read()
tm = 0
while cap.isOpened():
    key = cv2.waitKey(1)
    if key == ord("q"):
        break
    if key == ord('s'):
        cv2.imwrite(id_generator() + '.jpg', frame2)

    # Capture frame-by-frame
    ret, frame = cap.read()
    m = mse(cv2.cvtColor(temp, cv2.COLOR_BGR2GRAY), cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY))
    print('mse', m, '----\n')
    if abs(m - tm) < 2:  # 静止画面,不用重复计算
        continue
    else:
        temp = frame.copy()
        tm = m
    #
    # print(margin,frame.shape[0] - margin, margin,frame.shape[1] - margin)#40 680 40 1240
    frame2 = frame[margin:frame.shape[0] - margin, margin:frame.shape[1] - margin]  # .copy()
    # cv2.imshow('frame2', frame2)

    gray = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
    # edges = cv2.Canny(gray, 50, 150, apertureSize=3)

    # HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)
    # circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=100, param2=30, minRadius=10, maxRadius=40)

    # circles = circles1[0, :, :]  # 提取为二维
    # circles = np.uint16(np.around(circles1))
    print(circles)

    cimg = frame2
    if circles is not None:
        for i in circles[0, :]:
            # for i in circles[:]:
            # draw the outer circle
            cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
            # draw the center of the circle
            cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)

    # cv2.imshow('detected circles', cimg)

    draw_line_rectangle(frame, margin)
    cv2.imshow("houghlines", frame)
    # cv2.imwrite('frame3.jpg', frame[margin:frame.shape[0] - margin, margin:frame.shape[1] - margin])

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

HoughCircles_chess.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/28 11:05
# @Author  : play4fun
# @File    : HoughCircles_chess.py
# @Software: PyCharm

"""
HoughCircles_chess.py:
围棋
"""

import cv2
import numpy as np
from collections import Counter


def detect_weiqi(img):  # 检测棋子的颜色
    txt = 'black'
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, threshold = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)

    c = Counter(list(threshold.flatten()))
    print(c.most_common())
    if c.most_common()[0][0] != 0:
        txt = 'white'
    return txt, threshold


img = cv2.imread('../data/weiqi.png')

img = cv2.medianBlur(img, 5)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# ret, threshold = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)#不行
cv2.imshow('gray', gray)
# cv2.imshow('threshold', threshold)
# cv2.waitKey(0)

# HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)
# circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=10, maxRadius=40)#有一些没有检测到
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=100, param2=30, minRadius=10, maxRadius=50)

if circles is None:
    exit(-1)

circles = np.uint16(np.around(circles))
print(circles)

cv2.waitKey(0)
font = cv2.FONT_HERSHEY_SIMPLEX
for i in circles[0, :]:
    # draw the outer circle
    cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2)
    # draw the center of the circle
    cv2.circle(img, (i[0], i[1]), 2, (0, 0, 255), 3)

    x, y, r = i
    crop_img = img[y - r:y + r, x - r:x + r]
    # 检测围棋
    txt, threshold = detect_weiqi(crop_img)
    print('颜色:', '黑色' if txt == 'black' else '白色')

    cv2.putText(threshold, text=txt, org=(0, 0), fontFace=font, fontScale=0.5, color=(0, 255, 0), thickness=2)
    cv2.imshow('threshold', threshold)

    cv2.imshow('crop_img', crop_img)
    cv2.moveWindow('crop_img', x=0, y=img.shape[0])

    cv2.imshow('detected chess', img)
    cv2.moveWindow('detected chess', y=0, x=img.shape[1])

    cv2.waitKey(1500)

cv2.waitKey(0)
cv2.destroyAllWindows()

HoughCircles_eyes.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/27 10:57
# @Author  : play4fun
# @File    : HoughCircles_eyes.py
# @Software: PyCharm

"""
HoughCircles_eyes.py:

http://blog.csdn.net/on2way/article/details/47028969

"""

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

img = cv2.imread('eye-color-blue-z-c-660x440.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度图像

plt.subplot(121), plt.imshow(gray, 'gray')
plt.xticks([]), plt.yticks([])
# hough transform   #规定检测的圆的最大最小半径,不能盲目的检测,否侧浪费时间空间。
# circles1 = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1,100, param1=100, param2=30, minRadius=200, maxRadius=300)
circles1 = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 100, param1=100, param2=30, minRadius=100, maxRadius=200)  # 把半径范围调小点,检测内圆,瞳孔
circles = circles1[0, :, :]  # 提取为二维
circles = np.uint16(np.around(circles))  # 四舍五入,取整
for i in circles[:]:
    cv2.circle(img, (i[0], i[1]), i[2], (255, 0, 0), 5)  # 画圆
    cv2.circle(img, (i[0], i[1]), 2, (255, 0, 255), 10)  # 画圆心

plt.subplot(122), plt.imshow(img)
plt.xticks([]), plt.yticks([])
plt.show()

ch27-分水岭算法图像分割

watershed.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-25 下午12:09

任何一副灰度图像 可以 看成拓扑平面
灰度值 的区域可以 看成是 山峰 
灰度值低的区域可以 看成是山谷。
我们向每一个山谷中灌不同颜色的水。随着水的位的升  不同山谷的水就会相遇汇合 
为了防止不同山 的水 汇合 我们需要在水汇合的地方构建 堤坝。不停的灌水 不停的构建堤坝
直到所有的山峰都被水淹没。
我们构建好的堤坝就是对图像的分割。 
这就是分水岭算法的背后哲理。

每一次灌水 我们的标签就会 更新 当两个不同 色的标签相 时就构建堤 坝 直到将所有山峰淹没 最后我们得到的 界对  堤坝 的值为 -1

"""

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

img = cv2.imread('../data/water_coins.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
cv2.imshow('thresh', thresh)

# noise removal
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

# sure background area
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# Finding sure foreground area
# 距离变换的基本含义是计算一个图像中非像素点到最近的零像素点的距离
# 也就是到零像素点的最短距离
# 个最常见的距离变换算法就是通过连续的腐蚀操作来实现,
# 腐蚀操作的停止条件是所有前景像素都被完全腐蚀。
# 这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心骨架像素点的距离
# 根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离变换
# cv2.distanceTransform(src, distanceType, maskSize)
# 第二个参数 0,1,2 分别 示 CV_DIST_L1, CV_DIST_L2 , CV_DIST_C
dist_transform = cv2.distanceTransform(opening, 1, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)#图像相减
cv2.imshow('unknown', unknown)
# 边界

# 腐蚀


# Marker labelling创建标签
ret, markers1 = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
# 把将背景标 为 0 其他的对 使用从 1 开始的正整数标
markers = markers1 + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0

# cv2.imshow('markers', markers1)

# 到最后一步 实施分水岭算法了。标签图像将会 修 改  界区域的标 将变为 -1
markers3 = cv2.watershed(img, markers)
img[markers3 == -1] = [255, 0, 0]

cv2.imshow('watershed', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

ch28-使用GrabCut算法进行交互式前景提取

grabCut.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-25 下午12:20


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  也可以联合使用。 是用来确定我们  修改的方式 矩形模式或者掩模
模式。
"""

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

img = cv2.imread('../data/messi5.jpg')

mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
rect = (50, 50, 450, 290)

# 函数的返回值是更新的 mask, bgdModel, fgdModel
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount=5, mode=cv2.GC_INIT_WITH_RECT)
#迭代 5 次

mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img = img * mask2[:, :, np.newaxis]

plt.imshow(img), plt.colorbar(), plt.show()

grabCut2.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-25 下午12:20
实 上我是怎么做的呢 我们使用图像编  件打开 入图像 
添加一个 图层 
使用笔刷工具在  的地方使用白色绘制 比如头发  子 球等 
 使 用 色笔刷在不  的地方绘制 比如 logo 草地等 。
 然后将其他地方用灰 色填充 保存成新的掩码图像。
 在 OpenCV 中导入 个掩模图像 根据新的 掩码图像对原来的掩模图像  编 。
"""

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

img = cv2.imread('../data/messi5.jpg')
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
rect = (50, 50, 450, 290)
# 函数的返回值是更新的 mask, bgdModel, fgdModel
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img = img * mask2[:, :, np.newaxis]
plt.imshow(img), plt.colorbar(), plt.show()

# newmask is the mask image I manually labelled
newmask = cv2.imread('../data/newmask.jpg', 0)
# whereever it is marked white (sure foreground), change mask=1
# whereever it is marked black (sure background), change mask=0
mask[newmask == 0] = 0
mask[newmask == 255] = 1
mask, bgdModel, fgdModel = cv2.grabCut(img, mask, None, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_MASK)
mask = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img = img * mask[:, :, np.newaxis]
plt.imshow(img), plt.colorbar(), plt.show()

ch29-理解图像特征

ch30-Harris角点检测

30.1-OpenCV-Harris角点检测-cornerHarris.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-28 下午7:27

cv2.cornerHarris() 参数如下 
• img - 数据类型为 float32 的 入图像。
• blockSize -  点检测中 考 的 域大小。
• ksize - Sobel 求导中使用的窗口大小
• k - Harris  点检测方程中的自由参数 取值参数为 [0,04 0.06].
"""

import cv2
import numpy as np

filename = '../data/chessboard.png'
# filename = '../data/chessboard-3.png'
# filename = '../data/corner-detection.jpg'

img = cv2.imread(filename)
img = cv2.resize(img, (640, 480))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)

# 输入图像必 是 float32 最后一个参数在 0.04 到 0.05 之间
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
# result is dilated for marking the corners, not important
dst = cv2.dilate(dst, None)
# Threshold for an optimal value, it may vary depending on the image.
img[dst > 0.01 * dst.max()] = [0, 0, 255]

cv2.namedWindow('dst', cv2.WINDOW_NORMAL)
cv2.imshow('dst', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

30.2-亚像素级精确度的角点-cornerSubPix.py

# -*-coding:utf8-*-#
__author__ = 'play4fun'
"""
create time:15-10-29 上午7:47

最大精度的角点检测

首先我们 找到 Harris 角点
 然后将角点的重心传给这个函数进行修正。
 Harris 角点用红色像素标出 
 绿色像素是修正后的像素。
 在使用 个函数是我们 定义一个爹代停止条件。
 当 代次数 到或者精度条件满 后 代就会停止。
 我们同样需要定义进行角点搜索的邻域大小。
"""

import cv2
import numpy as np

filename = '../data/chessboard-2.png'
img = cv2.imread(filename)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# find Harris corners
gray = np.float32(gray)
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
dst = cv2.dilate(dst, None)
ret, dst = cv2.threshold(dst, 0.01 * dst.max(), 255, 0)
dst = np.uint8(dst)

# find centroids
# connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats,
# OutputArray centroids, int connectivity=8, int ltype=CV_32S)
ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)
# define the criteria to stop and refine the corners
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
# Python: cv2.cornerSubPix(image, corners, winSize, zeroZone, criteria)
# zeroZone – Half of the size of the dead region in the middle of the search zone
# over which the summation in the formula below is not done. It is used sometimes
# to avoid possible singularities of the autocorrelation matrix. The value of (-1,-1)
# indicates that there is no such a size.
# 返回值由 点坐标组成的一个数组 而 图像
corners = cv2.cornerSubPix(gray, np.float32(centroids), (5, 5), (-1, -1), criteria)
# Now draw them
res = np.hstack((centroids, corners))
# np.int0 可以用来省略小数点后的数字,非四舍五入
res = np.int0(res)
img[res[:, 1], res[:, 0]] = [0, 0, 255]
img[res[:, 3], res[:, 2]] = [0, 255, 0]

# cv2.imwrite('subpixel5.png',img)
cv2.imshow('subpixel5.png', img)
cv2.waitKey(0)
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐