OpenCV-Python-Tutorial[2]

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


  • ch10-图像上的算术运算
    • addWeightedpy
    • bitwise_andpy
    • 图像相减1py
    • 图像相减2py
    • 图像相减3py
    • 图像相减_camerapy
    • 长方形1py
    • 长方形2py
  • ch11-程序性能检测及优化
    • getTickCountpy
    • ipythonpy
    • useOptimizedpy
  • ch13-颜色空间转换
    • cvtColor_flagpy
    • 物体跟踪_blue_objectpy
    • find_object_hsvpy
  • ch14-几何变换
    • 1扩展缩放resizepy
    • 2平移py
    • 2平移-2py
    • wrapAffinepy
    • 仿射变换getAffineTransformpy
    • 透视变换getPerspectiveTransformpy
    • 旋转getRotationMatrix2Dpy
  • ch15-图像阈值
    • adaptiveThresholdpy
    • THRESH_OTSUpy
    • 简单阈值thresholdpy
    • 15-How-OTSU-workpy
  • ch16-图像平衡
    • filter2Dpy
    • 图像模糊-平均py
  • ch17-形态学转换
    • dilatepy
    • erodepy
    • 其他py
  • ch18-图像梯度
    • Sobelpy
    • 一个重要的事py
  • ch19-Canny边缘检测
    • Cannypy
  • ch20-图像金字塔
    • Apple_orangepy
    • 图像金字塔py

ch10-图像上的算术运算

10.addWeighted.py

# -*- coding: utf-8 -*-
import cv2
import numpy as np

# 学习图像上的算术运算 加法 减法 位运算等

# 你可以使用函数 cv2.add() 将两幅图像进行加法运算 当然也可以直接使 用 numpy ,
# res=img1+img
# 两幅图像的大小 类型必须一致 ,或者第二个 图像可以使一个简单的标量值。


x = np.uint8([250])
y = np.uint8([10])
print(cv2.add(x, y))  # 250+10 = 260 => 255
# [[255]]
print(x + y)  # 250+10=260%256=4
# [4]


# 图像混合
img1 = cv2.imread('../data/ml.png')
img2 = cv2.imread('../data/opencv_logo.jpg')

dst = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)  # 第一幅图的权重是 0.7 第二幅图的权重是 0.3

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

10.bitwise_and.py

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

import cv2
import numpy as np

# 按位运算

# Load two images
img1 = cv2.imread('../data/messi5.jpg')
img2 = cv2.imread('../data/opencv_logo.png')

# I want to put logo on top-left corner, So I create a ROI
rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]

# Now create a mask of logo and create its inverse mask also
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)

# Now black-out the area of logo in ROI
img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)  # opencv 3.0
#TODO error

# Take only region of logo from logo image.
img2_fg = cv2.bitwise_and(img2, img2, mask=mask)

# Put logo in ROI and modify the main image
dst = cv2.add(img1_bg, img2_fg)
img1[0:rows, 0:cols] = dst

cv2.imshow('res', img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 左 的图像是我们创建的掩码。右 的是最终结果。
# 为了帮助大 家理解,我把上面程序的中间结果也显示了出来
# 特别是 img1_bg 和 img2_fg。

图像相减1.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/21 上午10:48
# @Author  : play4fun
# @File    : 图像相减1.py
# @Software: PyCharm

"""
图像相减1.py:
"""

import cv2
import numpy as np

# img1=cv2.imread('subtract1.jpg')
img1=cv2.imread('subtract1.jpg',0)#灰度图
# img2=cv2.imread('subtract2.jpg')
img2=cv2.imread('subtract2.jpg',0)

cv2.imshow('subtract1',img1)
cv2.imshow('subtract2',img2)

#
st=img2-img1
# st=img1-img2#相反
cv2.imshow('after subtract',st)

#效果好一点
# ret,threshold=cv2.threshold(st,0, 127, cv2.THRESH_BINARY)
ret,threshold=cv2.threshold(st, 50,255, cv2.THRESH_BINARY)
cv2.imshow('after threshold', threshold)


cv2.waitKey(0)

图像相减2.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/21 上午10:48
# @Author  : play4fun
# @File    : 图像相减2.py
# @Software: PyCharm

"""
图像相减2.py:
"""

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

# img1=cv2.imread('subtract1.jpg')
img1 = cv2.imread('subtract1.jpg', 0)  # 灰度图
# img2=cv2.imread('subtract2.jpg')
# img2 = cv2.imread('subtract2.jpg', 0)
img22 = cv2.imread('subtract2.jpg')
img2 = cv2.cvtColor(img22, cv2.COLOR_BGR2GRAY)

# cv2.imshow('subtract1', img1)
# cv2.imshow('subtract2', img2)

#
st = cv2.subtract(img2, img1)
# st = cv2.subtract(img1, img2)#相反
st[st <= 5] = 0  # 把小于20的像素点设为0

# cv2.imshow('after subtract', st)

'''
# 直方图,看看大部分像素集中在哪个区域
# plt.plot(st)
pxs = st.ravel()
pxs=[x for x in pxs if x>5]#20,10
plt.hist(pxs, 256, [0, 256])
plt.show()
'''

# 效果好一点
# ret,threshold=cv2.threshold(st,0, 127, cv2.THRESH_BINARY)
ret, threshold = cv2.threshold(st, 50, 255, cv2.THRESH_BINARY)
# 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)

'''
for i,are in a2:
    if are <100:
        continue
    cv2.drawContours(img22, contours, i, (0, 0, 255), 3)
    print(i,are)

    cv2.imshow('drawContours',img22)
    cv2.waitKey(0)
# cv2.destroyAllWindows()
'''

# TODO 截取原图,把长方形纠正
cnt = contours[0]
print(cnt)
hull = cv2.convexHull(cnt)
epsilon = 0.001 * cv2.arcLength(hull, True)
simplified_cnt = cv2.approxPolyDP(hull, epsilon, True)

epsilon = 0.1 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
print(approx)
cv2.drawContours(img22, [approx], 0, (255, 0, 0), 3)
cv2.imshow('approxPolyDP', img22)
cv2.waitKey(0)
exit(3)

# findHomography(srcPoints, dstPoints, method=None, ransacReprojThreshold=None, mask=None, maxIters=None, confidence=None)
# H = cv2.findHomography(srcPoints=cnt.astype('single'), dstPoints=np.array([[[0., 0.]], [[2150., 0.]], [[2150., 2800.]], [[0., 2800.]]]))
# M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)


# now that we have our screen contour, we need to determine
# the top-left, top-right, bottom-right, and bottom-left
# points so that we can later warp the image -- we'll start
# by reshaping our contour to be our finals and initializing
# our output rectangle in top-left, top-right, bottom-right,
# and bottom-left order
pts = approx.reshape(4, 2)
rect = np.zeros((4, 2), dtype="float32")

# the top-left point has the smallest sum whereas the
# bottom-right has the largest sum
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]

# compute the difference between the points -- the top-right
# will have the minumum difference and the bottom-left will
# have the maximum difference
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]

# multiply the rectangle by the original ratio
ratio = image.shape[0] / 300.0
rect *= ratio


# now that we have our rectangle of points, let's compute
# the width of our new image
(tl, tr, br, bl) = rect
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))

# ...and now for the height of our new image
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))

# take the maximum of the width and height values to reach
# our final dimensions
maxWidth = max(int(widthA), int(widthB))
maxHeight = max(int(heightA), int(heightB))

# construct our destination points which will be used to
# map the screen to a top-down, "birds eye" view
dst = np.array([
    [0, 0],
    [maxWidth - 1, 0],
    [maxWidth - 1, maxHeight - 1],
    [0, maxHeight - 1]], dtype="float32")

# calculate the perspective transform matrix and warp
# the perspective to grab the screen
M = cv2.getPerspectiveTransform(rect, dst)
warp = cv2.warpPerspective(img22, M, (maxWidth, maxHeight))

# final_image = cv2.warpPerspective(img22, H, (2150, 2800))

cv2.imshow('final_image', warp)
cv2.waitKey(0)

图像相减3.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/21 上午10:57
# @Author  : play4fun
# @File    : 图像相减3.py
# @Software: PyCharm

"""
图像相减3.py:

3张图片

"""
import cv2

def diff(img, img1):  # returns just the difference of the two images
    return cv2.absdiff(img, img1)


def diff_remove_bg(img0, img, img1):  # removes the background but requires three images
    d1 = diff(img0, img)
    d2 = diff(img, img1)
    return cv2.bitwise_and(d1, d2)


# img1=cv2.imread('subtract1.jpg')
img1 = cv2.imread('subtract1.jpg', 0)  # 灰度图
# img2=cv2.imread('subtract2.jpg')
img2 = cv2.imread('subtract2.jpg', 0)

cv2.imshow('subtract1', img1)
cv2.imshow('subtract2', img2)

#
st = diff_remove_bg(img2, img1,img2)

cv2.imshow('after subtract', st)

cv2.waitKey(0)

图像相减_camera.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/24 下午5:20
# @Author  : play4fun
# @File    : 图像相减_camera.py
# @Software: PyCharm

"""
图像相减_camera.py:
"""

import cv2
import numpy as np

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

cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
cap.read()
'''
cal=[cap.read()[1] for x in range(20)]

#mean 直接的加减是不行的
# bgimg0=np.mean(np.sum(cal))
# bgimg0=np.average(cal)
# bgimg0=np.mean(cal)
nps1=sum(cal)
mean1=nps1/len(cal)
# mean1[mean1<0]=0
# mean1[mean1>255]=255
cv2.imshow('bgimg', mean1)
cv2.waitKey(0)
exit(3)
'''

frame_no = 100
# cap.set(1, frame_no)#第10帧
ret, bgimg0 = cap.read()  # 背景
bgimg = cv2.cvtColor(bgimg0, cv2.COLOR_BGR2GRAY)
cv2.imshow('bgimg' + str(frame_no), bgimg0)
# cv2.imwrite('desk_bgimg.jpg',bgimg)

while cap.isOpened():
    ret, frame = cap.read()  # TODO 图像稳定
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    #
    st = cv2.subtract(gray, bgimg)
    # st = cv2.subtract(img1, img2)#相反
    # st[st <= 5] = 0  # 把小于20的像素点设为0

    ret, threshold = cv2.threshold(st, 50, 255, cv2.THRESH_BINARY)
    image, contours, hierarchy = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    print("contours size: ", len(contours))

    # img = cv2.drawContours(st, contours, -1, (0, 0, 0), 13)
    img = cv2.drawContours(st, contours, -1, (255, 255, 255), 3)
    #
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area < 200:
            continue

        peri = cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, 0.04 * peri, True)
        if len(approx) == 4:
            (x, y, w, h) = cv2.boundingRect(approx)
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)

    # TODO 对比前几/十几帧,新放一张扑克,知道是那张
    # 等待图像稳定,不放牌后,再计算


    cv2.imshow("frame", frame)
    cv2.imshow("subtract", img)
    cv2.moveWindow("subtract", y=bgimg.shape[0], x=0)
    cv2.imshow('threshold', threshold)
    cv2.moveWindow("threshold", x=bgimg.shape[1], y=0)

    key = cv2.waitKey(delay=1)
    if key == ord("q"):
        break
    elif key == ord("s"):
        cv2.imwrite('poker-threshold.jpg', threshold)

cv2.destroyAllWindows()

长方形1.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/21 下午6:12
# @Author  : play4fun
# @File    : 长方形1.py
# @Software: PyCharm

"""
长方形1.py:
[[[183 199]]
 [[ 69 214]]
 [[ 97 390]]
 [[210 373]]]

"""
import cv2
import numpy as np

img22 = cv2.imread('subtract2.jpg')

# src_pts = np.array([[8, 136], [415, 52], [420, 152], [14, 244]], dtype=np.float32)

src_pts = np.array([[[97, 390], [210, 373], [183, 199], [69, 214]]], dtype=np.float32)

dst_pts = np.array([[0, 0], [50, 0], [50, 100], [0, 100]], dtype=np.float32)

M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warp = cv2.warpPerspective(img22, M, (50, 100))

cv2.imshow('src', img22)
cv2.imshow('warp', warp)
cv2.waitKey(0)

长方形2.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/21 下午6:12
# @Author  : play4fun
# @File    : 长方形1.py
# @Software: PyCharm

"""
长方形1.py:

https://stackoverflow.com/questions/42262198/4-point-persective-transform-failure
透视变换矩阵

[[[183 199]]
 [[ 69 214]]
 [[ 97 390]]
 [[210 373]]]

"""
import cv2
import numpy as np


def get_euler_distance(pt1, pt2):
    return ((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2) ** 0.5


img22 = cv2.imread('subtract2.jpg')

# src_pts = np.array([[8, 136], [415, 52], [420, 152], [14, 244]], dtype=np.float32)

src_pts = np.array([[[97, 390], [210, 373], [183, 199], [69, 214]]], dtype=np.float32)
# src_pts = np.array([[ [210, 373], [183, 199], [69, 214],[97, 390]]], dtype=np.float32)

width = get_euler_distance(src_pts[0][0], src_pts[0][1])
height = get_euler_distance(src_pts[0][0], src_pts[0][3])

dst_pts = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32)

M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warp = cv2.warpPerspective(img22, M, (int(width), int(height)))

warp=cv2.flip(warp,flipCode=1)

cv2.imshow('src', img22)
cv2.imshow('warp', warp)
# cv2.imwrite('crop0.jpg',warp)
cv2.waitKey(0)

ch11-程序性能检测及优化

11.getTickCount.py

# -*- coding: utf-8 -*-
import cv2
import numpy as np

'''
使用 OpenCV 检测程序效率
'''
img1 = cv2.imread('../data/ml.jpg')

e1 = cv2.getTickCount()

for i in range(5, 49, 2):
    img1 = cv2.medianBlur(img1, i)

e2 = cv2.getTickCount()
t = (e2 - e1) / cv2.getTickFrequency()  # 时钟频率 或者 每秒钟的时钟数
print(t)  # 0.034773332

# Result I got is 0.521107655 seconds

11.ipython.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 上午11:16
# @Author  : play4fun
# @File    : 11.ipython.py
# @Software: PyCharm

"""
11.ipython.py:
"""

import cv2
import numpy as np
'''

In [10]: x = 5
In [11]: %timeit y=x**2
10000000 loops, best of 3: 73 ns per loop
In [12]: %timeit y=x*x
10000000 loops, best of 3: 58.3 ns per loop
In [15]: z = np.uint8([5])
In [17]: %timeit y=z*z
1000000 loops, best of 3: 1.25 us per loop
In [19]: %timeit y=np.square(z)
1000000 loops, best of 3: 1.16 us per loop
#Python 的标量运算比 Nump 的标量运算 快。
#对于仅包含一两个 元素的操作 Python 标量比 Numpy 的数组 快。
#但是当数组稍微大一点时 Numpy 就会胜出了
'''

'''
In [35]: %timeit z = cv2.countNonZero(img)
100000 loops, best of 3: 15.8 us per loop
In [36]: %timeit z = np.count_nonzero(img)
1000 loops, best of 3: 370 us per loop
#OpenCV 的函数是 Numpy 函数的 25 倍

#一般情况下 OpenCV 的函数 比 Numpy 函数快。所以对于相同的操
作最好使用 OpenCV 的函数。当然也有例外 尤其是当使用 Numpy 对 图  而 复制   操作时
'''

'''
有些技术和编程方法可以 我们最大的发挥 Python 和 Numpy 的威力。 
我们  仅仅提一下相关的,你可以超链接查找更多 细信息。
我们 要说的最重要的一点是:
 先用简单的方式实现你的算法(结果正确最重要)
 当结果正确后 再使用上面的提到的方法找到程序的瓶 来优化它。
1. 尽量避免使用循环 尤其双层三层循环 它们天生就是 常慢的。
2. 算法中尽量使用向量操作 因为 Numpy 和 OpenCV  对向量操作了优化。
3. 利用高速缓存一致性。
4. 没有必要的话就不要复制数组。使用视图来代替复制。数组复制是非常浪费资源的。
'''

11.useOptimized.py

# -*- coding: utf-8 -*-
import cv2
import numpy as np

'''
OpenCV 中的默认优化
在编译时 优化是 默认开启的。因此 OpenCV   的就是优化后的代码 
如果你把优化 关闭的 就只能执行低效的代码了。
你可以使用函数 cv2.useOptimized() 来查看优化是否 开启了 
使用函数 cv2.setUseOptimized() 来开启优化
'''
# check if optimization is enabled
"""
In [5]: cv2.useOptimized()
Out[5]: True
In [6]: %timeit res = cv2.medianBlur(img,49)
10 loops, best of 3: 34.9 ms per loop
# Disable it
In [7]: cv2.setUseOptimized(False)
In [8]: cv2.useOptimized()
Out[8]: False
In [9]: %timeit res = cv2.medianBlur(img,49)
#优化后中值滤波的速度是原来的两倍
"""
print(cv2.useOptimized())
cv2.setUseOptimized(False)
print(cv2.useOptimized())

ch13-颜色空间转换

1.cvtColor_flag.py

# -*- coding: utf-8 -*-
'''
在 OpenCV 中有超过150 种进行颜色空间转换的方法。但是你以后就会 发现我们经常用到的也就两种 BGR↔Gray 和 BGR↔HSV。
我们 用到的函数是 cv2.cvtColor(input_image flag) 其中 flag 就是转换类型。
对于 BGR↔Gray 的转换, 我们 使用的 flag 就是 cv2.COLOR_BGR2GRAY。 同样对于 BGR↔HSV 的转换 我们用的 flag 就是 cv2.COLOR_BGR2HSV
'''

import cv2
from pprint import pprint

flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
pprint(flags)
#在 OpenCV 的 HSV 格式中 H 色彩/色度 的取值范围是 [0 179]
#  S 饱和度 的取值范围 [0 255]
# V 亮度 的取值范围 [0 255]。
# 但是不 同的 件使用的值可能不同。
# 所以当你  拿 OpenCV 的 HSV 值与其他  件的 HSV 值  对比时 ,一定记得得归一化。

'''
['COLOR_BAYER_BG2BGR',
 'COLOR_BAYER_BG2BGR_EA',
 'COLOR_BAYER_BG2BGR_VNG',
 'COLOR_BAYER_BG2GRAY',
 'COLOR_BAYER_BG2RGB',
 'COLOR_BAYER_BG2RGB_EA',
 'COLOR_BAYER_BG2RGB_VNG',
 'COLOR_BAYER_GB2BGR',
 'COLOR_BAYER_GB2BGR_EA',
 'COLOR_BAYER_GB2BGR_VNG',
 'COLOR_BAYER_GB2GRAY',
 'COLOR_BAYER_GB2RGB',
 'COLOR_BAYER_GB2RGB_EA',
 'COLOR_BAYER_GB2RGB_VNG',
 'COLOR_BAYER_GR2BGR',
 'COLOR_BAYER_GR2BGR_EA',
 'COLOR_BAYER_GR2BGR_VNG',
 'COLOR_BAYER_GR2GRAY',
 'COLOR_BAYER_GR2RGB',
 'COLOR_BAYER_GR2RGB_EA',
 'COLOR_BAYER_GR2RGB_VNG',
 'COLOR_BAYER_RG2BGR',
 'COLOR_BAYER_RG2BGR_EA',
 'COLOR_BAYER_RG2BGR_VNG',
 'COLOR_BAYER_RG2GRAY',
 'COLOR_BAYER_RG2RGB',
 'COLOR_BAYER_RG2RGB_EA',
 'COLOR_BAYER_RG2RGB_VNG',
 'COLOR_BGR2BGR555',
 'COLOR_BGR2BGR565',
 'COLOR_BGR2BGRA',
 'COLOR_BGR2GRAY',
 'COLOR_BGR2HLS',
 'COLOR_BGR2HLS_FULL',
 'COLOR_BGR2HSV',
 'COLOR_BGR2HSV_FULL',
 'COLOR_BGR2LAB',
 'COLOR_BGR2LUV',
 'COLOR_BGR2Lab',
 'COLOR_BGR2Luv',
 'COLOR_BGR2RGB',
 'COLOR_BGR2RGBA',
 'COLOR_BGR2XYZ',
 'COLOR_BGR2YCR_CB',
 'COLOR_BGR2YCrCb',
 'COLOR_BGR2YUV',
 'COLOR_BGR2YUV_I420',
 'COLOR_BGR2YUV_IYUV',
 'COLOR_BGR2YUV_YV12',
 'COLOR_BGR5552BGR',
 'COLOR_BGR5552BGRA',
 'COLOR_BGR5552GRAY',
 'COLOR_BGR5552RGB',
 'COLOR_BGR5552RGBA',
 'COLOR_BGR5652BGR',
 'COLOR_BGR5652BGRA',
 'COLOR_BGR5652GRAY',
 'COLOR_BGR5652RGB',
 'COLOR_BGR5652RGBA',
 'COLOR_BGRA2BGR',
 'COLOR_BGRA2BGR555',
 'COLOR_BGRA2BGR565',
 'COLOR_BGRA2GRAY',
 'COLOR_BGRA2RGB',
 'COLOR_BGRA2RGBA',
 'COLOR_BGRA2YUV_I420',
 'COLOR_BGRA2YUV_IYUV',
 'COLOR_BGRA2YUV_YV12',
 'COLOR_BayerBG2BGR',
 'COLOR_BayerBG2BGR_EA',
 'COLOR_BayerBG2BGR_VNG',
 'COLOR_BayerBG2GRAY',
 'COLOR_BayerBG2RGB',
 'COLOR_BayerBG2RGB_EA',
 'COLOR_BayerBG2RGB_VNG',
 'COLOR_BayerGB2BGR',
 'COLOR_BayerGB2BGR_EA',
 'COLOR_BayerGB2BGR_VNG',
 'COLOR_BayerGB2GRAY',
 'COLOR_BayerGB2RGB',
 'COLOR_BayerGB2RGB_EA',
 'COLOR_BayerGB2RGB_VNG',
 'COLOR_BayerGR2BGR',
 'COLOR_BayerGR2BGR_EA',
 'COLOR_BayerGR2BGR_VNG',
 'COLOR_BayerGR2GRAY',
 'COLOR_BayerGR2RGB',
 'COLOR_BayerGR2RGB_EA',
 'COLOR_BayerGR2RGB_VNG',
 'COLOR_BayerRG2BGR',
 'COLOR_BayerRG2BGR_EA',
 'COLOR_BayerRG2BGR_VNG',
 'COLOR_BayerRG2GRAY',
 'COLOR_BayerRG2RGB',
 'COLOR_BayerRG2RGB_EA',
 'COLOR_BayerRG2RGB_VNG',
 'COLOR_COLORCVT_MAX',
 'COLOR_GRAY2BGR',
 'COLOR_GRAY2BGR555',
 'COLOR_GRAY2BGR565',
 'COLOR_GRAY2BGRA',
 'COLOR_GRAY2RGB',
 'COLOR_GRAY2RGBA',
 'COLOR_HLS2BGR',
 'COLOR_HLS2BGR_FULL',
 'COLOR_HLS2RGB',
 'COLOR_HLS2RGB_FULL',
 'COLOR_HSV2BGR',
 'COLOR_HSV2BGR_FULL',
 'COLOR_HSV2RGB',
 'COLOR_HSV2RGB_FULL',
 'COLOR_LAB2BGR',
 'COLOR_LAB2LBGR',
 'COLOR_LAB2LRGB',
 'COLOR_LAB2RGB',
 'COLOR_LBGR2LAB',
 'COLOR_LBGR2LUV',
 'COLOR_LBGR2Lab',
 'COLOR_LBGR2Luv',
 'COLOR_LRGB2LAB',
 'COLOR_LRGB2LUV',
 'COLOR_LRGB2Lab',
 'COLOR_LRGB2Luv',
 'COLOR_LUV2BGR',
 'COLOR_LUV2LBGR',
 'COLOR_LUV2LRGB',
 'COLOR_LUV2RGB',
 'COLOR_Lab2BGR',
 'COLOR_Lab2LBGR',
 'COLOR_Lab2LRGB',
 'COLOR_Lab2RGB',
 'COLOR_Luv2BGR',
 'COLOR_Luv2LBGR',
 'COLOR_Luv2LRGB',
 'COLOR_Luv2RGB',
 'COLOR_M_RGBA2RGBA',
 'COLOR_RGB2BGR',
 'COLOR_RGB2BGR555',
 'COLOR_RGB2BGR565',
 'COLOR_RGB2BGRA',
 'COLOR_RGB2GRAY',
 'COLOR_RGB2HLS',
 'COLOR_RGB2HLS_FULL',
 'COLOR_RGB2HSV',
 'COLOR_RGB2HSV_FULL',
 'COLOR_RGB2LAB',
 'COLOR_RGB2LUV',
 'COLOR_RGB2Lab',
 'COLOR_RGB2Luv',
 'COLOR_RGB2RGBA',
 'COLOR_RGB2XYZ',
 'COLOR_RGB2YCR_CB',
 'COLOR_RGB2YCrCb',
 'COLOR_RGB2YUV',
 'COLOR_RGB2YUV_I420',
 'COLOR_RGB2YUV_IYUV',
 'COLOR_RGB2YUV_YV12',
 'COLOR_RGBA2BGR',
 'COLOR_RGBA2BGR555',
 'COLOR_RGBA2BGR565',
 'COLOR_RGBA2BGRA',
 'COLOR_RGBA2GRAY',
 'COLOR_RGBA2M_RGBA',
 'COLOR_RGBA2RGB',
 'COLOR_RGBA2YUV_I420',
 'COLOR_RGBA2YUV_IYUV',
 'COLOR_RGBA2YUV_YV12',
 'COLOR_RGBA2mRGBA',
 'COLOR_XYZ2BGR',
 'COLOR_XYZ2RGB',
 'COLOR_YCR_CB2BGR',
 'COLOR_YCR_CB2RGB',
 'COLOR_YCrCb2BGR',
 'COLOR_YCrCb2RGB',
 'COLOR_YUV2BGR',
 'COLOR_YUV2BGRA_I420',
 'COLOR_YUV2BGRA_IYUV',
 'COLOR_YUV2BGRA_NV12',
 'COLOR_YUV2BGRA_NV21',
 'COLOR_YUV2BGRA_UYNV',
 'COLOR_YUV2BGRA_UYVY',
 'COLOR_YUV2BGRA_Y422',
 'COLOR_YUV2BGRA_YUNV',
 'COLOR_YUV2BGRA_YUY2',
 'COLOR_YUV2BGRA_YUYV',
 'COLOR_YUV2BGRA_YV12',
 'COLOR_YUV2BGRA_YVYU',
 'COLOR_YUV2BGR_I420',
 'COLOR_YUV2BGR_IYUV',
 'COLOR_YUV2BGR_NV12',
 'COLOR_YUV2BGR_NV21',
 'COLOR_YUV2BGR_UYNV',
 'COLOR_YUV2BGR_UYVY',
 'COLOR_YUV2BGR_Y422',
 'COLOR_YUV2BGR_YUNV',
 'COLOR_YUV2BGR_YUY2',
 'COLOR_YUV2BGR_YUYV',
 'COLOR_YUV2BGR_YV12',
 'COLOR_YUV2BGR_YVYU',
 'COLOR_YUV2GRAY_420',
 'COLOR_YUV2GRAY_I420',
 'COLOR_YUV2GRAY_IYUV',
 'COLOR_YUV2GRAY_NV12',
 'COLOR_YUV2GRAY_NV21',
 'COLOR_YUV2GRAY_UYNV',
 'COLOR_YUV2GRAY_UYVY',
 'COLOR_YUV2GRAY_Y422',
 'COLOR_YUV2GRAY_YUNV',
 'COLOR_YUV2GRAY_YUY2',
 'COLOR_YUV2GRAY_YUYV',
 'COLOR_YUV2GRAY_YV12',
 'COLOR_YUV2GRAY_YVYU',
 'COLOR_YUV2RGB',
 'COLOR_YUV2RGBA_I420',
 'COLOR_YUV2RGBA_IYUV',
 'COLOR_YUV2RGBA_NV12',
 'COLOR_YUV2RGBA_NV21',
 'COLOR_YUV2RGBA_UYNV',
 'COLOR_YUV2RGBA_UYVY',
 'COLOR_YUV2RGBA_Y422',
 'COLOR_YUV2RGBA_YUNV',
 'COLOR_YUV2RGBA_YUY2',
 'COLOR_YUV2RGBA_YUYV',
 'COLOR_YUV2RGBA_YV12',
 'COLOR_YUV2RGBA_YVYU',
 'COLOR_YUV2RGB_I420',
 'COLOR_YUV2RGB_IYUV',
 'COLOR_YUV2RGB_NV12',
 'COLOR_YUV2RGB_NV21',
 'COLOR_YUV2RGB_UYNV',
 'COLOR_YUV2RGB_UYVY',
 'COLOR_YUV2RGB_Y422',
 'COLOR_YUV2RGB_YUNV',
 'COLOR_YUV2RGB_YUY2',
 'COLOR_YUV2RGB_YUYV',
 'COLOR_YUV2RGB_YV12',
 'COLOR_YUV2RGB_YVYU',
 'COLOR_YUV420P2BGR',
 'COLOR_YUV420P2BGRA',
 'COLOR_YUV420P2GRAY',
 'COLOR_YUV420P2RGB',
 'COLOR_YUV420P2RGBA',
 'COLOR_YUV420SP2BGR',
 'COLOR_YUV420SP2BGRA',
 'COLOR_YUV420SP2GRAY',
 'COLOR_YUV420SP2RGB',
 'COLOR_YUV420SP2RGBA',
 'COLOR_YUV420p2BGR',
 'COLOR_YUV420p2BGRA',
 'COLOR_YUV420p2GRAY',
 'COLOR_YUV420p2RGB',
 'COLOR_YUV420p2RGBA',
 'COLOR_YUV420sp2BGR',
 'COLOR_YUV420sp2BGRA',
 'COLOR_YUV420sp2GRAY',
 'COLOR_YUV420sp2RGB',
 'COLOR_YUV420sp2RGBA',
 'COLOR_mRGBA2RGBA']
'''

2.物体跟踪_blue_object.py

# -*- coding: utf-8 -*-
import cv2
import numpy as np

'''
物体跟踪

• 从视频中获取每一帧图像
• 将图像转换到 HSV 空间
• 设置 HSV 阈值到蓝色范围。
• 获取蓝色物体 当然我们 可以做其他任何我们想做的事 
比如 在蓝色 物体周围画一个圈。


当你学习了【轮廓】之后 你就会学到更多 相关知识
那是你就可以找到物体的重心 并根据重心来跟踪物体
仅仅在摄像头前挥挥手就可以画出同的图形,或者其他更有趣的事。
'''

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

# 定蓝色的阈值
# lower = np.array([110, 50, 50])
# upper = np.array([130, 255, 255])

#黄色-乒乓球
lower = np.array([20, 100, 100])
upper = np.array([30, 255, 255])

# 黑色
# lower_black = np.array([0, 0, 0])
# upper_black = np.array([180, 255, 30])

while True:
    # 获取每一帧
    ret, frame = cap.read()
    # 换到 HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # 根据阈值构建掩模
    mask = cv2.inRange(hsv, lower, upper)
    # mask = cv2.inRange(hsv, lower_black, upper_black)
    # 对原图像和掩模位运算
    res = cv2.bitwise_and(frame, frame, mask=mask)

    # 显示图像
    cv2.imshow('frame', frame)
    cv2.moveWindow('frame', x=0, y=0)  # 原地
    cv2.imshow('mask', mask)
    cv2.moveWindow('mask', x=frame.shape[1], y=0)#右边
    cv2.imshow('res', res)
    cv2.moveWindow('res', y=frame.shape[0], x=0)#下边

    k = cv2.waitKey(1)  # & 0xFF
    if k == ord('q'):
        break
# 关闭窗口
cap.release()
cv2.destroyAllWindows()

13.find_object_hsv.py

# -*- coding: utf-8 -*-
import cv2
import numpy as np

# wrong
# green=np.uint8([0,255,0])
# print green
# hsv_green=cv2.cvtColor(green,cv2.COLOR_BGR2HSV)
# print hsv_green


# scn (the number of channels of the source),
# i.e. self.img.channels(), is neither 3 nor 4.
#
# depth (of the source),
# i.e. self.img.depth(), is neither CV_8U nor CV_32F.
# 所以不能用 [0,255,0] 而 用 [[[0,255,0]]]
# 的三层括号应 分别对应于 cvArray cvMat IplImage


green = np.uint8([[[0, 255, 0]]])
hsv_green = cv2.cvtColor(green, cv2.COLOR_BGR2HSV)
print(hsv_green)
# [[[60 255 255]]]

black = np.uint8([[[0, 0, 0]]])
hsv_black = cv2.cvtColor(black, cv2.COLOR_BGR2HSV)
print(hsv_black)
# [[[0 0 0]]]

ch14-几何变换

14.1.扩展缩放resize.py

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

'''
扩展缩放

在缩放时我们推荐使用 cv2.INTER_AREA
在扩展时我们推荐使用 v2.INTER_CUBIC 慢) 和 v2.INTER_LINEAR。
默认情况下所有改变图像尺寸大小的操作使用的插值方法 是 cv2.INTER_LINEAR。

Resize(src, dst, interpolation=CV_INTER_LINEAR)
'''

import cv2
import numpy as np

img = cv2.imread('../data/messi5.jpg')
# 下面的 None 本应 是 出图像的尺寸 但是因为后边我们设置了缩放因子
# 因此这里为 None
res = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)

# OR
# 我们直接设置输出图像的尺寸 所以不用设置缩放因子
# height, width = img.shape[:2]
# res = cv2.resize(img, (2 * width, 2 * height), interpolation=cv2.INTER_CUBIC)

cv2.imshow('resize', res)
cv2.imshow('src img', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

14.2平移.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午12:21
# @Author  : play4fun
# @File    : 平移.py
# @Software: PyCharm

"""
平移.py:平移就是将对 换一个位置。如果你 沿 (x, y) 方向移动
移动的距离 是 (tx,ty)
"""

import cv2
import numpy as np

cap = cv2.VideoCapture(0)
ret = cap.set(3, 640)
ret = cap.set(4, 480)
while True:
    # 获取每一帧
    ret, frame = cap.read()

    #  换到 HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    #  定蓝色的阈值
    lower_blue = np.array([110, 50, 50])
    upper_blue = np.array([130, 255, 255])
    # 根据阈值构建掩模
    mask = cv2.inRange(hsv, lower_blue, upper_blue)
    # 对原图像和掩模 进行位运算
    res = cv2.bitwise_and(frame, frame, mask=mask)

    # 显示图像
    cv2.imshow('frame', frame)
    cv2.imshow('mask', mask)
    cv2.imshow('res', res)

    k = cv2.waitKey(1)  # & 0xFF
    if k == ord('q'):
        break
# 关 窗口
cv2.destroyAllWindows()

14.2平移-2.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午12:31
# @Author  : play4fun
# @File    : 14.2平移-2.py
# @Software: PyCharm

"""
14.2平移-2.py:
http://docs.opencv.org/3.2.0/da/d6e/tutorial_py_geometric_transformations.html
函数 cv2.warpAffine() 的第三个参数的是 出图像的大小 ,它的格式 应 是图像的(宽,高) 。
图像的宽对应的是列数, 高对应的是行数。
"""

import cv2
import numpy as np

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

M = np.float32([[1, 0, 100], [0, 1, 50]])
dst = cv2.warpAffine(img, M, (cols, rows))

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

14.wrapAffine.py

# -*- coding: utf-8 -*-
import cv2
import numpy as np

# 移动了100,50 个像素。
img = cv2.imread('../data/messi5.jpg', 0)
rows, cols = img.shape

M = np.float32([[1, 0, 100], [0, 1, 50]])
dst = cv2.warpAffine(img, M, (cols, rows))

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

14.仿射变换getAffineTransform.py

# -*- coding: utf-8 -*-
'''
仿射变换
在仿射变换中 原图中所有的平行线在结果图像中同样平行。
为了创建 这个矩阵,我们需要从原图像中找到三个点以及他们在 出图像中的位置。
然后 cv2.getAffineTransform 会创建一个 2x3 的矩  最后 个矩 会 传给 函数 cv2.warpAffine。
'''

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

img = cv2.imread('drawing.png')
rows, cols, ch = img.shape
print(img.shape)

pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[10, 100], [200, 50], [100, 250]])

M = cv2.getAffineTransform(pts1, pts2)
dst = cv2.warpAffine(img, M, (cols, rows))

# plt.subplot(121, plt.imshow(img), plt.title('Input'))
# plt.subplot(122, plt.imshow(dst), plt.title('Output'))

plt.figure(figsize=(8, 7), dpi=98)
p1 = plt.subplot(211)
p1.show(img)
p1.set_title('Input')

p2 = plt.subplot(212)
p2.show(dst)
p2.set_title('Output')

plt.show()

14.透视变换getPerspectiveTransform.py

# -*- coding: utf-8 -*-
'''
透视变换
对于透视变换 ,我们需要一个 3x3 变换矩 。
在变换前后直线 是直线。
构建 个变换矩  你需要在输入图像上找 4 个点, 以及他们在输出图 像上对应的位置。
四个点中的任意三个都不能共线。这个变换矩阵可以用函数 cv2.getPerspectiveTransform() 构建。
然后把这个矩阵传给函数 cv2.warpPerspective。

'''

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

img = cv2.imread('../data/sudoku.jpg')
rows, cols, ch = img.shape

pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])

M = cv2.getPerspectiveTransform(pts1, pts2)
dst = cv2.warpPerspective(img, M, (300, 300))

plt.figure(figsize=(8, 7), dpi=98)
p1 = plt.subplot(211)
p1.show(img)
p1.set_title('Input')

p2 = plt.subplot(212)
p2.show(dst)
p2.set_title('Output')

plt.show()

14.旋转getRotationMatrix2D.py

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

# 旋转
import cv2
import numpy as np

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

# 的第一个参数为旋转中心 第二个为旋转角度
#  第三个为旋转后的缩放因子
# 可以通过设置旋转中心,缩放因子,以及窗口大小来防止旋转后超出边界的问题
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 0.6)

# 第三个参数是输出图像的尺寸中心
dst = cv2.warpAffine(img, M, (2 * cols, 2 * rows))

cv2.imshow('img', dst)

cv2.waitKey(0)  # & 0xFF
cv2.destroyAllWindows()

ch15-图像阈值

15.adaptiveThreshold.py

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

'''
自适应阈值

Adaptive Method- 指定 算阈值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C  值取自相邻区域的平均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C  值取值相邻区域 的加权和 ,权重为一个高斯窗口
'''

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

# img = cv2.imread('dave.jpg', 0)
img = cv2.imread('../data/sudoku.jpg', 0)
# 中值滤波
img = cv2.medianBlur(img, 5)
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# 11 为 Block size 邻域大小 用来计算阈值的区域大小 ,
# 2 为 C值,常数, 阈值就等于的平均值或者加权平均值减去这个常数。
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
          'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])

plt.show()

15.THRESH_OTSU.py

# -*- coding: utf-8 -*-
'''
Otsu's 二值化

在第一 分中我们提到  retVal 当我们使用 Otsu 二值化时会用到它。  么它到底是什么呢
在使用全局 值时 我们就是 便给了一个数来做 值  我们怎么知  我们 取的 个数的好坏呢?
 答案就是不停的尝 。
 如果是一副双峰图像 ,简 单来 双峰图像是指图像直方图中存在两个峰 呢 ?
 我们岂不是应 在两个峰 之 的峰  一个值作为阈值 。
  就是 Otsu 二值化 做的。
  简单来说,就是对一副双峰图像自动根据其直方图计算出一个阈值。
  对于非双峰图像 这 种方法 得到的结果可能会不理想 。

 这里 用到的函数 是 cv2.threshold() 但是  需要多传入一个参数  flag  cv2.THRESH_OTSU。
  这时 把 值 为 0。然后算法会找到最 优阈值 ,这 个最优 值就是 回值 retVal。
  如果不使用 Otsu 二值化 返回的retVal 值与 设定的 阈值相等。

下 的例子中  输入图像是一副带有噪声的图像。
第一种方法 我们 设127 为全局 阈值。
第二种方法 我们直接使用 Otsu 二值化。
第三种方法 我 们 先使用一个 5x5 的 高斯核 去噪  然后再使用 Otsu 二值化。
看看噪音 去除对结果的影响有多大吧。
'''

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

img = cv2.imread('noisy2.png', 0)
# global thresholding
ret1, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# Otsu's thresholding
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
# 5,5 为 斯核的大小 0 为标准差
blur = cv2.GaussianBlur(img, (5, 5), 0)
# 阀值一定为 0
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image', 'Histogram', 'Global Thresholding (v=127)',
          'Original Noisy Image', 'Histogram', "Otsu's Thresholding",
          'Gaussian filtered Image', 'Histogram', "Otsu's Thresholding"]
# 使用了 pyplot 中画直方图的方法 plt.hist,
# 注意的是它的参数是一维数组
# 所以使用了 numpy ravel 方法 将多维数组 换成一维 也可以使用 flatten 方法
# ndarray.flat 1-D iterator over an array.
# ndarray.flatten 1-D array copy of the elements of an array in row-major order.

for i in range(3):
    plt.subplot(3, 3, i * 3 + 1), plt.imshow(images[i * 3], 'gray')
    plt.title(titles[i * 3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i * 3 + 2), plt.hist(images[i * 3].ravel(), 256)
    plt.title(titles[i * 3 + 1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i * 3 + 3), plt.imshow(images[i * 3 + 2], 'gray')
    plt.title(titles[i * 3 + 2]), plt.xticks([]), plt.yticks([])
plt.show()

15.简单阈值threshold.py

# -*- coding: utf-8 -*-
'''
简单阈值
像素值高于阈值时 我们给这个像素 赋予一个新值, 可能是白色 ,
 否则我们给它赋予另外一种颜色, 或是黑色 。
 这个函数就是 cv2.threshhold()。
 这个函数的第一个参数就是原图像
 原图像应 是灰度图。
 第二个参数就是用来对像素值进行分类的阈值。
 第三个参数 就是当像素值高于, 有时是小于  阈值时应该被赋予的新的像素值。
 OpenCV 提供了多种不同的阈值方法 , 是由第四个参数来决定的。
  些方法包括
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV • cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
'''

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

img = cv2.imread('grey-gradient.jpg', 0)

ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

15-How-OTSU-work.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午1:27
# @Author  : play4fun
# @File    : 15-How-OTSU-work.py
# @Software: PyCharm

"""
15-How-OTSU-work.py:
"""

import cv2
import numpy as np

img = cv2.imread('noisy2.png', 0)
blur = cv2.GaussianBlur(img, (5, 5), 0)
# find normalized_histogram, and its cumulative distribution function
#  算归一化直方图
# CalcHist(image, accumulate=0, mask=NULL)

hist = cv2.calcHist([blur], [0], None, [256], [0, 256])
hist_norm = hist.ravel() / hist.max()
Q = hist_norm.cumsum()

bins = np.arange(256)
fn_min = np.inf
thresh = -1

for i in range(1, 256):
    p1, p2 = np.hsplit(hist_norm, [i])  # probabilities
    q1, q2 = Q[i], Q[255] - Q[i]  # cum sum of classes
    b1, b2 = np.hsplit(bins, [i])  # weights

    # finding means and variances
    m1, m2 = np.sum(p1 * b1) / q1, np.sum(p2 * b2) / q2
    v1, v2 = np.sum(((b1 - m1) ** 2) * p1) / q1, np.sum(((b2 - m2) ** 2) * p2) / q2

    # calculates the minimization function
    fn = v1 * q1 + v2 * q2
    if fn < fn_min:
        fn_min = fn
        thresh = i

# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

print(thresh, ret)

ch16-图像平衡

16.filter2D.py

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

'''
2D 卷积
OpenCV 提供的函数 cv.filter2D() 可以 我们对一幅图像  卷积操
作。
操作如下 将核放在图像的一个像素 A 上 求与核对应的图像上 25 5x5  个像素的和 在取平均数 用 个平均数替代像素 A 的值。 复以上操作直到 将图像的每一个像素值 更新一 。
'''

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

img = cv2.imread('../data/opencv_logo.png')
kernel = np.ones((5, 5), np.float32) / 25
# cv.Filter2D(src, dst, kernel, anchor=(-1, -1))
# ddepth –desired depth of the destination image;
# if it is negative, it will be the same as src.depth();
# the following combinations of src.depth() and ddepth are supported:
# src.depth() = CV_8U, ddepth = -1/CV_16S/CV_32F/CV_64F
# src.depth() = CV_16U/CV_16S, ddepth = -1/CV_32F/CV_64F
# src.depth() = CV_32F, ddepth = -1/CV_32F/CV_64F
# src.depth() = CV_64F, ddepth = -1/CV_64F
# when ddepth=-1, the output image will have the same depth as the source.

dst = cv2.filter2D(img, -1, kernel)

plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(dst), plt.title('Averaging')
plt.xticks([]), plt.yticks([])

plt.show()

图像模糊-平均.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午1:35
# @Author  : play4fun
# @File    : 图像模糊-平均.py
# @Software: PyCharm

"""
图像模糊-平均.py:
 是由一个归一化卷积框完成的。他只是用卷积框 盖区域所有像素的平 均值来代替中心元素。可以使用函数 cv2.blur() 和 cv2.boxFilter() 来完  个任务。
"""

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

img = cv2.imread('../data/opencv_logo.png')
# blur = cv2.blur(img, (5, 5))

'''
现在把卷积核换成 斯核 简单来  方框不变 将原来每个方框的值是 相等的 现在  的值是符合 斯分布的 方框中心的值最大 其余方框根据  离中心元素的 离 减 构成一个 斯小山包。原来的求平均数现在变成求 加权平均数 全就是方框 的值 。
'''
# 0 是指根据窗口大小 (5,5) 来计算高斯函数标准差
blur = cv2.GaussianBlur(img, (5, 5), 0)  # 高斯模糊

'''
 名思义就是用与卷积框对应像素的中值来替代中心像素的值。 个滤波 器经常用来去 椒盐噪声。前 的滤波器 是用 算得到的一个新值来取代中 心像素的值 而中值滤波是用中心像素周围 也可以使他本  的值来取代他。 他能有效的去 噪声。卷积核的大小也应 是一个奇数。
'''
median = cv2.medianBlur(img, 5)  # 中值模糊

'''
函数 cv2.bilateralFilter() 能在保持边界清晰的情况下有效的去 噪  。
但是 种操作与其他滤波器相比会比 慢。
我们已经知 高斯滤波器是求 中心点 邻近区域像素的高斯加权平均值。
 种 斯滤波器只考虑像素之间的空间关系 
 而不会考虑像素值之间的关系 ,像素的相似度 。
 所以 种方法不会考 虑 一个像素是否位于边界。
 因此边界也会被模糊掉 而 这正不是我们想要。

双边滤波在同时使用空 高斯权重和灰度值相似性 斯权 。
空 高斯函数确保只有邻近区域的像素对中心点有影响
 灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。
 所以 种方法会确保边界不会被模糊掉
  因为边界处的灰度值变化比较大。
'''

#16.4 双边滤波
# cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace)
# d – Diameter of each pixel neighborhood that is used during filtering. # If it is non-positive, it is computed from sigmaSpace
# 9  域直径 两个 75 分别是空  斯函数标准差 灰度值相似性 斯函数标准差
# blur = cv2.bilateralFilter(img, 9, 75, 75)

plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()

ch17-形态学转换

17.dilate.py

# -*- coding: utf-8 -*-
'''
与腐 相反 与卷积核对应的原图像的像素值中只 有一个是 1 中心元 素的像素值就是 1。所以 个操作会增加图像中的白色区域 前景 。一般在去 噪声时先用腐 再用膨胀。因为腐 在去掉白噪声的同时 也会使前景对 变 小。所以我们再对他  膨胀。 时噪声已经 去 了 不会再回来了 但是 前景 在并会增加。膨胀也可以用来 接两个分开的物体。
'''

import cv2
import numpy as np

img = cv2.imread('j.png', 0)
cv2.imshow('j.png', img)
print(img.shape)

kernel = np.ones((5, 5), np.uint8)
dilation = cv2.dilate(img, kernel, iterations=1)

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

cv2.waitKey(0)
cv2.destroyAllWindows()

17.erode.py

# -*- coding: utf-8 -*-
'''
两个基本的形态学操作是腐 和膨胀。他们 的变体构成了开运算 ,闭运算, 梯度等。

根据卷积核的大小  前景的所有像素 会 腐  掉 变为 0  ,所以前景物体会变小 整幅图像的白色区域会减少。
对于去除白噪声很有用 也可以用来断开两个 在一块的物体等。
'''

import cv2
import numpy as np

img = cv2.imread('j.png', 0)
cv2.imshow('j.png', img)
print(img.shape)

#您可以将内核看作是一个小矩阵,我们在图像上滑动以进行(卷积)操作,例如模糊,锐化,边缘检测或其他图像处理操作。
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)

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

cv2.waitKey(0)
cv2.destroyAllWindows()

17.其他.py

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


import cv2
import numpy as np

img = cv2.imread('j.png', 0)
cv2.imshow('j.png', img)
print(img.shape)

#您可以将内核看作是一个小矩阵,我们在图像上滑动以进行(卷积)操作,例如模糊,锐化,边缘检测或其他图像处理操作。
kernel = np.ones((5, 5), np.uint8)

# 开运算:先腐蚀再膨胀就叫做开运算。就像我们上 介绍的 样, 它 用来,去噪声。
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

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

# 闭运算
# 先膨胀再腐 。它经常 用来填充前景物体中的小洞 或者前景物体上的小黑点。
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imshow('closing', closing)
cv2.moveWindow('closing', x=img.shape[1] * 2, y=0)

# 形态学梯度
# 其实就是一幅图像膨胀与腐 的差别。
# 结果看上去就像前景物体的 廓。
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('gradient', gradient)
cv2.moveWindow('gradient', x=img.shape[1] * 3, y=0)

# 礼帽
# 原始图像与  开运算之后得到的图像的差。
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv2.imshow('tophat', tophat)
cv2.moveWindow('tophat', x=img.shape[1] * 4, y=0)

# 黑帽  进行闭运算之后得到的图像与原始图像的差
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('blackhat', blackhat)
cv2.moveWindow('blackhat', x=img.shape[1] * 5, y=0)

cv2.waitKey(0)
cv2.destroyAllWindows()

'''
结构化元素
在前 的例子中我们使用 Numpy 构建了结构化元素 它是正方形的。
但 有时我们 需要 构建一个椭圆形/圆形的核。
为了实现 这种需求 ,提供了 OpenCV 函数 cv2.getStructuringElement()。
你只  告诉 他 你需要的核的形状和大小。
# Rectangular Kernel
>>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]], dtype=uint8)
# Elliptical Kernel
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
array([[0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0]], dtype=uint8)
# Cross-shaped Kernel
>>> cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
array([[0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 1, 1, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=uint8)
'''

ch18-图像梯度

18.Sobel.py

# -*- coding: utf-8 -*-
'''
原理
梯度简单来说就是求导。
OpenCV 提供了三种不同的梯度滤波器 或者说是高通滤波器:Sobel,  Scharr 和 Laplacian。我们会意义介绍他们。
Sobel Scharr 其实就是求一阶或二阶导数。
Scharr 是对 Sobel (使用小的卷积核求解 梯度角度时 )的优化。
Laplacian 是求二阶导数。


Sobel 算子是高斯平滑与微分操作的结合体 所以它的抗噪声能力很好。
 你可以设定求导的方向 xorder 或 yorder 。
 可以设定使用的卷积核的大 小 ksize 。
 如果 ksize=-1 会使用 3x3 的 Scharr 滤波器
 它的的效果  比 3x3 的 Sobel 滤波器好 而且 度相同 所以在使用 3x3 滤波器时应 尽 量 使用 Scharr 滤波器 。

Laplacian 算子
拉普拉斯算子可以使用二阶导数的形式定义 ,可假设其离散实现类似于二阶Sobel 导数
事实上 OpenCV 在 算拉普拉斯算子时直接 用 Sobel 算 子
'''

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

img = cv2.imread('../data/sudoku.jpg', 0)
# cv2.CV_64F 出图像的深度 数据类型 可以使用 -1, 与原图像保持一致 np.uint8
laplacian = cv2.Laplacian(img, cv2.CV_64F)
# 参数 1,0 为只在 x 方向求一 导数 最大可以求 2 导数。
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)
# 参数 0,1 为只在 y 方向求一 导数 最大可以求 2 导数。
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)

plt.subplot(2, 2, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 2, 2), plt.imshow(laplacian, cmap='gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 2, 3), plt.imshow(sobelx, cmap='gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])

plt.subplot(2, 2, 4), plt.imshow(sobely, cmap='gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])

plt.show()

一个重要的事.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午2:23
# @Author  : play4fun
# @File    : 一个重要的事.py
# @Software: PyCharm

"""
一个重要的事.py:
当我们可以  参 数 -1 来 定 出图像的深度 数据类型 与原图像保持一致
但是我们在代 码中使用的却是 cv2.CV_64F。 是为什么呢 ?
想象一下一个从黑到白的边界的导数是整数,而一个从白到黑的边界点导数却是负数。
如果原图像的深度是 np.int8 时 所有的负值 会 截断变成 0
 换句话就是把边界丢失掉。
所以如果 两种边界你 想检测到
最好的的办法就是将输出的数据类型 设置的更高
  比如 cv2.CV_16S cv2.CV_64F 等。
  取绝对值然后再把它 回 到 cv2.CV_8U。
  下 的示例演示了输出图片的深度不同造成的不同效果。
"""

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

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

# Output dtype = cv2.CV_8U
sobelx8u = cv2.Sobel(img, cv2.CV_8U, 1, 0, ksize=5)
# Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U
sobelx64f = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)

abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)

plt.subplot(1, 3, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 2), plt.imshow(sobelx8u, cmap='gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 3), plt.imshow(sobel_8u, cmap='gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])

plt.show()

ch19-Canny边缘检测

19.Canny.py

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

'''
Canny 边缘检测是一种 常流 的 缘检测算法 是 John F.Canny 在
1986 年提出的。它是一个有很多步构成的算法
由于 缘检测很容易受到噪声影响 所以第一步是使用 5x5 的 斯滤波器 去 噪声
对平滑后的图像使用 Sobel 算子 算水平方向和竖直方向的一 导数 图 像梯度  Gx 和 Gy
梯度的方向一般总是与边界垂直。
梯度方向 归为四类: 垂直 水平 和 两个对角线。
非极大值抑制

滞后阈值
现在 确定 些 界才是真正的边界。 时我们   置两个阈值  minVal 和 maxVal。
当图像的灰度梯度 于 maxVal 时  为是真的边界
那些低于 minVal 的 界会 抛弃。
如果介于两者之间的  就 看这个点是否与某个被确定为真正的边界点相连
如果是就认为它也是边界点 如果不是 就抛弃。

OpenCV 中的 Canny 边界检测
在 OpenCV 中只 需要 一个函数 cv2.Canny() 就可以完成以上几步。
  我们看如何使用这个函数。
第一个参数是输入图像。
第二和第三 个分别是 minVal 和 maxVal。
第三个参数 置用来计算图像梯度的 Sobel卷积核的大小  默认值为 3。
最后一个参数是 L2gradient 它可以用来 设定 求梯度大小的方程。
如果 为 True 就会使用我们上 提到 的方程 否则 使用方程 Edge−Gradient (G) = |G2x| + |G2y| 代替,  默认值为 False。
'''
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('../data/messi5.jpg',0)
edges = cv2.Canny(img, 100, 200)

cv2.imshow('Edges',edges)
cv2.waitKey(0)

# plt.subplot(121), plt.imshow(img, cmap='gray')
# plt.title('Original Image'), plt.xticks([]), plt.yticks([])
# plt.subplot(122), plt.imshow(edges, cmap='gray')
# plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
# plt.show()

ch20-图像金字塔

20.Apple_orange.py

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

'''
图像 字塔的一个应用是图像 合。例如 在图像缝合中 你  将两幅 图叠在一  但是由于 接区域图像像素的不 续性 整幅图的效果看 来会 很差。 时图像 字塔就可以排上用场了 他可以帮你实现无缝 接。  的 一个经典案例就是将两个水果 合成一个 看看下图也 你就明白我在 什么 了。


实现上 效果的步 如下
1.  入两幅图像 苹果和句子
2. 构建苹果和橘子的 斯 字塔 63. 根据 斯 字塔 算拉普拉斯 字塔
4. 在拉普拉斯的每一层  图像 合 苹果的左 与橘子的右  合  5. 根据 合后的图像 字塔 建原始图像。
'''

import cv2
import numpy as np, sys

A = cv2.imread('apple.jpg')
B = cv2.imread('orange.jpg')

# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpA.append(G)

# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in range(6):
    G = cv2.pyrDown(G)
    gpB.append(G)

# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpA[i])
    L = cv2.subtract(gpA[i - 1], GE)#TODO error
    lpA.append(L)
    #cv2.error: /Users/play/Temp/opencv/modules/core/src/arithm.cpp:659: error: (-209) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function arithm_op


# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in range(5, 0, -1):
    GE = cv2.pyrUp(gpB[i])
    L = cv2.subtract(gpB[i - 1], GE)
    lpB.append(L)

# Now add left and right halves of images in each level
# numpy.hstack(tup)
# Take a sequence of arrays and stack them horizontally
# to make a single array.
LS = []
for la, lb in zip(lpA, lpB):
    rows, cols, dpt = la.shape
    ls = np.hstack((la[:, 0:cols / 2], lb[:, cols / 2:]))
    LS.append(ls)

# now reconstruct
ls_ = LS[0]
for i in range(1, 6):
    ls_ = cv2.pyrUp(ls_)
    ls_ = cv2.add(ls_, LS[i])

# image with direct connecting each half
real = np.hstack((A[:, :cols / 2], B[:, cols / 2:]))

cv2.imwrite('Pyramid_blending2.jpg', ls_)
cv2.imwrite('Direct_blending.jpg', real)

图像金字塔.py

# -*- coding: utf-8 -*-
# @Time    : 2017/7/12 下午3:06
# @Author  : play4fun
# @File    : 图像金字塔.py
# @Software: PyCharm

"""
图像金字塔.py:
一般情况下 我们 处理是一副具有固定分辨率的图像。
但是有些情况下  我们  对同一图像的不同分 率的子图像  处理。
比如 我们 在一幅图 像中查找某个目标 比如脸 我们不知 目标在图像中的尺寸大小。
 这种情况下 ,我们  创建创建一组图像 , 这些图像是具有不同分 率的原始图像。
 我们把这组图像叫做图像金字塔
 简单来说 就是同一图像的不同分辨率的子图集合 。

 如果我们把最大的图像放在底部,最小的放在顶部
看起来像一座金字塔, 故而得名:图像金字塔。
  有两类图像金字塔: 高斯金字塔和拉普拉斯金字塔。

高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。
图像中的每个像素值等于下一层图像中 5 个像素的 斯加权平均值。
这样 操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。
所以 这幅图像 的面积就变为原来图像面积的四分之一。 这称为 Octave。
连续进行这样 的操作我们就会得到一个分辨率不断下降的图像金字塔。
我们可以使用函数 cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。


"""

import cv2
import numpy as np

higher_reso = cv2.imread('../data/messi5.jpg')
# 函数 cv2.pyrDown() 从一个 分辨率大尺寸的图像向上构建一个金子塔
# 尺寸变小 分辨率降低 。
lower_reso = cv2.pyrDown(higher_reso)
cv2.imshow('lower_reso', lower_reso)

# 从一个低分 率小尺寸的图像向下构建一个 子塔 尺 寸变大 但分 率不会增加
higher_reso2 = cv2.pyrUp(lower_reso)
cv2.imshow('higher_reso2', higher_reso2)

# 你  住的是是 higher_reso2 和 higher_reso 是不同的。因为一旦使 用 cv2.pyrDown() 图像的分辨率就会 低 ,信息就会 丢失

cv2.waitKey(0)
cv2.destroyAllWindows()

你可能感兴趣的:(opencv)