opencv-python基础

写在前面的话,欢迎大家一起学习!

目录

安装

第一章 图像的基本操作

1.1图片读取

1.2视频的读取

1.3读取感兴趣的窗口

1.4图像通道

1.5边界填充

1.6改变图像大小以及图像混合

1.7图像融合

1.8利用mask掩膜抠出感兴趣的区域

1.9基本绘图操作

1.10 鼠标绘图

1.11几何操作

1.12亮度与对比度

1.13 轮廓检测以及多边形,凸包绘制

1.14动态绘制时钟​

第二章 阈值与(滤波)平滑处理

第三章 图像形态学操作

3.1腐蚀操作

3.2膨胀操作

3.3开运算(即先腐蚀,再膨胀)

3.4闭运算(即先膨胀,再腐蚀)

3.5梯度运算(梯度=膨胀-腐蚀)

3.6顶帽(又称礼帽= 原始输入-开运算结果)

3.7黑帽(黑帽 = 闭运算-原始输入)

第四章 梯度计算--用于边缘检测(Canny,Sobel,Scharr)​

第五章 图像金字塔

第六章轮廓检测

6.1轮廓检测

6.2利用 hsv追踪蓝色物体

第七章 图像直方图与傅里叶变换

7.1直方图

7.2傅里叶变换

第八章角点检测(Harris,shi_tomasi,sift)

 第九章 模板匹配与KNN匹配

9.1模板匹配

9.2KNN匹配

9.3利用KNN匹配加透视变换实现全景图像拼接​

第十章霍夫变换

第十一章 图像矫正

11.1仿射变换,透视变换

11.2基于傅里叶变换进行矫正​


安装

pip install opencv-python
pip install opencv-contrib-python

第一章 图像的基本操作

1.1图片读取

import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('cat.jpg') # opencv默认读取BGR格式
print(img)
# 显示图像,可以创建多个窗口
cv2.imshow('Cat', img)
# 等待,0表示键盘任意键终止,如果为1000代表1000毫秒结束显示
cv2.waitKey(0)

#如果我们需要查看图像的维度,我们可以通过以下代码进行查看:
print(img.shape)
#如果我们需要读取灰度图片的话,我们可以采用以下的方式,添加一个参数即可:
img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
#我们也可以通过以下方式将其保存起来。
print(img.size) #查看像素点的个数

cv2.destroyAllWindows()

1.2视频的读取

import cv2
vc = cv2.VideoCapture('chaplin.mp4')
# 判断是否能够读取视频
if vc.isOpened():
    open, frame = vc.read()
else:
    open =False
while open:
    ret, frame = vc.read()
    if frame is None:
        break
    if ret == True:
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        cv2.imshow('result', gray)
        if cv2.waitKey(100) & 0xFF == 27:
            break
vc.release()
cv2.destroyAllWindows()

1.3读取感兴趣的窗口

import cv2
img = cv2.imread('cat.jpg')
img2 = img[50:200, 100:400] # 切片读取感兴趣的区域
cv2.imshow('cat',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.4图像通道

import cv2
img = cv2.imread('cat1.jpg')
#我们可以通过以下的方式将其通道分开
b, g, r = cv2.split(img)
#也可以将其合并起来,记住,opencv里面颜色是bgr
img1 = cv2.merge((b, g, r))

cv2.imshow('cat_1', img1)
cop_img = img1.copy()
cop_img[:,:,0] = 0
cop_img[:,:,1] = 0
cv2.imshow('cat_only_r', cop_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.5边界填充

opencv-python基础_第1张图片

#在卷积操作中经常需要边界填充padding
import cv2
import matplotlib.pyplot as plt
top_size, bottom_size, left_size, right_size = (50, 50, 50, 50)
img = cv2.imread('my.jpg')
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)

plt.subplot(231), plt.imshow(img), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant), plt.title('CONSTANT')

plt.show()

1.6改变图像大小以及图像混合

opencv-python基础_第2张图片

import cv2
img_cat = cv2.imread('cat.jpg')
#对像素点直接进行加减。
img_cat_add = img_cat + 10
img_dog = cv2.imread('dog.jpg')
print('img_cat size',img_cat.shape)
print('img_dog size', img_dog.shape)
#改变图像大小
img_dog_resize = cv2.resize(img_dog, (550, 366))
print('img_dog_resize', img_dog_resize.shape)
#图像融合
res = cv2.addWeighted(img_cat, 0.3, img_dog_resize, 0.9, 0)
cv2.imshow('366*550',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.7图像融合

opencv-python基础_第3张图片opencv-python基础_第4张图片
 

import cv2
import numpy as np

# 1.按位操作
img1 = cv2.imread('cat.jpg')
img2 = cv2.imread('my.jpg')

# 把logo放在左上角,所以我们只关心这一块区域
rows, cols = img2.shape[:2]		#shape[0] shape[1] shape[2]  高,长,通道   
print(rows,cols)#132,132,3
roi = img1[50:182, 300:432]   #在原图切出感兴趣区域roi,roi必须与mask掩膜大小相同
print(roi.shape)
cv2.imshow('roi', roi)
cv2.waitKey(0)

# 2.创建掩膜
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)

# 保留除logo外的背景
img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
dst = cv2.add(img1_bg, img2)  # 进行融合
img1[50:182, 300:432] = dst  # 融合后放在原图上

cv2.imshow('result', img1)
cv2.waitKey(0)

1.8利用mask掩膜抠出感兴趣的区域

opencv-python基础_第5张图片

import cv2
import numpy as np

img = cv2.imread('my.jpg')
#圆心坐标,半径
x = 11
y = 11
r = 55
#创建掩膜
mask = np.zeros(img.shape[:2], dtype=np.uint8)
#mask[50:250, 130:320] = 255创建矩形区域
mask = cv2.circle(mask, (66, 66), r, (255, 255, 255), -1)
cv2.imshow("mask", mask)
#融合
result = cv2.add(img, np.zeros(np.shape(img), dtype=np.uint8), mask=mask)
res=np.hstack((img,result))
cv2.imshow("res", res)
cv2.waitKey()
cv2.destroyAllWindows()

1.9基本绘图操作

opencv-python基础_第6张图片

import cv2
import numpy as np

# 创建一副黑色的图片
img = np.zeros((512, 512, 3), np.uint8)
# 1.画一条线宽为5的蓝色直线,参数2:起点,参数3:终点
cv2.line(img, (0, 0), (512, 512), (255, 0, 0), 5)


# 2.画一个绿色边框的矩形,参数2:左上角坐标,参数3:右下角坐标
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)


# 3.画一个填充红色的圆,参数2:圆心坐标,参数3:半径
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)


# 4.在图中心画一个填充的半圆
cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, (255, 0, 0), -1)


# 5.画一个闭合的四边形
# 定义四个顶点坐标
pts = np.array([[10, 5],  [50, 10], [70, 20], [20, 30]], np.int32)

# 顶点个数:4,矩阵变成顶点数*1*2维(注意numpy中-1的用法)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, (0, 255, 255))

#使用cv2.polylines()画多条直线
line1 = np.array([[100, 20],  [300, 20]], np.int32).reshape((-1, 1, 2))
line2 = np.array([[100, 60],  [300, 60]], np.int32).reshape((-1, 1, 2))
line3 = np.array([[100, 100],  [300, 100]], np.int32).reshape((-1, 1, 2))
cv2.polylines(img, [line1, line2, line3], True, (0, 255, 255))


# 6.添加文字
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'zcz', (10, 500), font,
            4, (255, 255, 255), 2, lineType=cv2.LINE_AA)

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

1.10 鼠标绘图

opencv-python基础_第7张图片

import cv2
import numpy as np

start, end = (0, 0), (0, 0)
drawing = False


def mouse_event(event, x, y, flags, param):
    global start, drawing, end, temp

    # 鼠标按下,开始画图:记录下起点
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        start = (x, y)
    # 实时移动的位置作为矩形终点(右下角点)
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            end = (x, y)
    # 鼠标释放后,停止绘图
    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        cv2.rectangle(img, start, (x, y), (0, 255, 0), 2)
        start = end = (0, 0)


img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image', mouse_event)

while(True):
    # 下面这句话很关键,拷贝出原图,这样才可以实时画一个矩形
    temp = np.copy(img)
    if(drawing and end != (0, 0)):
        cv2.rectangle(temp, start, end, (255, 0, 0), 2)

    cv2.imshow('image', temp)
    if cv2.waitKey(20) == 27:
        break

1.11几何操作

opencv-python基础_第8张图片

import cv2

img = cv2.imread('my.jpg')
cv2.imshow('src', img)
cv2.waitKey(0)

# 1.按照指定的宽度、高度缩放图片
res = cv2.resize(img, (30, 30))
# 按照比例缩放,如x,y轴均放大一倍
res2 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)

cv2.imshow('shrink', res), cv2.imshow('zoom', res2)
cv2.waitKey(0)

# 2.翻转图片,镜像操作
import numpy as np

# 参数2=0:垂直翻转(沿x轴),参数2>0: 水平翻转(沿y轴)
# 参数2<0: 水平垂直翻转
dst = cv2.flip(img, -1)
# np.hstack: 横向并排,对比显示
cv2.imshow('flip', np.hstack((img, dst)))  # np.hstack: 横向并排,对比显示
cv2.waitKey(0)


# 3.平移图片
rows, cols = img.shape[:2]
# 定义平移矩阵,需要是numpy的float32类型
# x轴平移100,y轴平移50
M = np.float32([[1, 0, 100], [0, 1, 50]])
dst = cv2.warpAffine(img, M, (cols, rows))

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


# 4.45°顺时针旋转图片并缩小一半
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), -45, 0.5)
dst = cv2.warpAffine(img, M, (cols, rows))

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

1.12亮度与对比度

opencv-python基础_第9张图片
 

import cv2
import numpy as np


def nothing(x):
    '''
    ### 回调函数,暂时无用
    '''
    pass


img = cv2.imread('lena.jpg')
cv2.namedWindow('image')

# 创建两个滑块
cv2.createTrackbar('brightness', 'image', 0, 100, nothing)
cv2.createTrackbar('contrast', 'image', 100, 300, nothing)

temp = img.copy()
rows, cols = img.shape[:2]

while(True):
    cv2.imshow('image', temp)
    if cv2.waitKey(1) == 27:
        break

    # 得到两个滑块的值
    brightness = cv2.getTrackbarPos('brightness', 'image')
    contrast = cv2.getTrackbarPos('contrast', 'image') * 0.01
    # 进行对比度和亮度调整
    temp = np.uint8(np.clip(contrast * img + brightness, 0, 255))

1.13 轮廓检测以及多边形,凸包绘制

opencv-python基础_第10张图片opencv-python基础_第11张图片

import cv2
import numpy as np


# 多边形逼近
# 1.先找到轮廓
img = cv2.imread('unregular.jpg', 0)
_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
image, contours, hierarchy = cv2.findContours(thresh, 3, 2)
cnt = contours[0]

# 2.进行多边形逼近,得到多边形的角点
approx = cv2.approxPolyDP(cnt, 3, True)

# 3.画出多边形
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
cv2.polylines(image, [approx], True, (0, 255, 0), 2)
print(len(approx))  # 角点的个数
cv2.imshow('approxPloyDP', image)
cv2.waitKey(0)


# 凸包
# 1.先找到轮廓
img = cv2.imread('convex.jpg', 0)
_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
image, contours, hierarchy = cv2.findContours(thresh, 3, 2)
cnt = contours[0]

# 2.寻找凸包,得到凸包的角点
hull = cv2.convexHull(cnt)

# 3.绘制凸包
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
cv2.polylines(image, [hull], True, (0, 255, 0), 2)
cv2.imshow('convex hull', image)
cv2.waitKey(0)

# 轮廓是否是凸形的
print(cv2.isContourConvex(hull))  # True

# 关于returnPoints的理解:
print(hull[0])  # [[362 184]](坐标)
hull2 = cv2.convexHull(cnt, returnPoints=False)
print(hull2[0])  # [510](cnt中的索引)
print(cnt[510])  # [[362 184]]


# 点到轮廓距离(多边形测试)
dist = cv2.pointPolygonTest(cnt, (100, 100), True)  # -3.53
print(dist)

1.14动态绘制时钟
opencv-python基础_第12张图片

import cv2
import math
import datetime
import numpy as np

margin = 5  # 上下左右边距
radius = 220  # 圆的半径
center = (center_x, center_y) = (225, 225)  # 圆心

# 1. 新建一个画板并填充成白色
img = np.zeros((450, 450, 3), np.uint8)
img[:] = (255, 255, 255)

# 2. 画出圆盘
cv2.circle(img, center, radius, (0, 0, 0), thickness=5)

pt1 = []

# 3. 画出60条秒和分钟的刻线
for i in range(60):
    # 最外部圆,计算A点
    x1 = center_x+(radius-margin)*math.cos(i*6*np.pi/180.0)
    y1 = center_y+(radius-margin)*math.sin(i*6*np.pi/180.0)
    pt1.append((int(x1), int(y1)))

    # 同心小圆,计算B点
    x2 = center_x+(radius-15)*math.cos(i*6*np.pi/180.0)
    y2 = center_y+(radius-15)*math.sin(i*6*np.pi/180.0)

    cv2.line(img, pt1[i], (int(x2), int(y2)), (0, 0, 0), thickness=2)

# 4. 画出12条小时的刻线
for i in range(12):
    # 12条小时刻线应该更长一点
    x = center_x+(radius-25)*math.cos(i*30*np.pi/180.0)
    y = center_y+(radius-25)*math.sin(i*30*np.pi/180.0)
    # 这里用到了前面的pt1
    cv2.line(img, pt1[i*5], (int(x), int(y)), (0, 0, 0), thickness=5)


# 到这里基本的表盘图就已经画出来了

while(1):
    # 不断拷贝表盘图,才能更新绘制,不然会重叠在一起
    temp = np.copy(img)

    # 5. 获取系统时间,画出动态的时-分-秒三条刻线
    now_time = datetime.datetime.now()
    hour, minute, second = now_time.hour, now_time.minute, now_time.second

    # 画秒刻线
    # 参见博客,OpenCV中的角度是顺时针计算的,所以需要转换下
    sec_angle = second*6+270 if second <= 15 else (second-15)*6
    sec_x = center_x+(radius-margin)*math.cos(sec_angle*np.pi/180.0)
    sec_y = center_y+(radius-margin)*math.sin(sec_angle*np.pi/180.0)
    cv2.line(temp, center, (int(sec_x), int(sec_y)), (203, 222, 166), 2)

    # 画分刻线
    min_angle = minute*6+270 if minute <= 15 else (minute-15)*6
    min_x = center_x+(radius-35)*math.cos(min_angle*np.pi/180.0)
    min_y = center_y+(radius-35)*math.sin(min_angle*np.pi/180.0)
    cv2.line(temp, center, (int(min_x), int(min_y)), (186, 199, 137), 8)

    # 画时刻线
    hour_angle = hour*30+270 if hour <= 3 else (hour-3)*30
    hour_x = center_x+(radius-65)*math.cos(hour_angle*np.pi/180.0)
    hour_y = center_y+(radius-65)*math.sin(hour_angle*np.pi/180.0)
    cv2.line(temp, center, (int(hour_x), int(hour_y)), (169, 198, 26), 15)

    # 6. 添加当前日期文字
    font = cv2.FONT_HERSHEY_SIMPLEX
    time_str = now_time.strftime("%d/%m/%Y")
    cv2.putText(img, time_str, (135, 275), font, 1, (0, 0, 0), 2)

    cv2.imshow('clocking', temp)
    if cv2.waitKey(1) == 27:  # 按下ESC键退出
        break

 

第二章 阈值与(滤波)平滑处理

opencv-python基础_第13张图片

opencv-python基础_第14张图片

#ret, dst = cv2.threshold(src, thresh, maxval, type)
#src: 输入图,只能输入单通道图像,通常来说为灰度图
#thresh: 阈值
#maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
#type:二值化操作的类型,就是怎么处理阈值,包含以下5种类型:
	#cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
	#cv2.THRESH_BINARY_INV THRESH_BINARY的反转
	#cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
	#cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
	#cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
	#cv2.THRESH_OTSU opencv自动选取阈值,适用于双峰图像


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

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

ret1, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret2, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
ret3, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
ret4, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret5, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
ret6,thresh6 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV','THRESH_OTSU']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5,thresh6]
for i in range(7):
    plt.subplot(2, 4, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()
cv2.waitKey(0)

#平滑处理,起到平滑图像,虑去噪声的功能
img = cv2.imread('my.jpg')
#均值滤波(卷积核参数都是1)
blur = cv2.blur(img, (3, 3))
#方框滤波
#基本和均值一样,可以选择归一化,容易越界,如果归一化normalize等于True,那么和均值滤波一样,如果#normalize为False,那么大部分都将会发生越界的情况。
box = cv2.boxFilter(img,-1,(3,3), normalize=False) 
#高斯滤波,更重视中值
aussian = cv2.GaussianBlur(img, (5, 5), 1)
#中值滤波
median = cv2.medianBlur(img, 5)  # 中值滤波
#展示所有的
res = np.hstack((img,blur,box,aussian,median))
#加上这一句就可以调整窗口大小
cv2.namedWindow("median vs average",cv2.WINDOW_NORMAL);
cv2.imshow('median vs average', res)

cv2.waitKey(0)
cv2.destroyAllWindows()

第三章 图像形态学操作

3.1腐蚀操作

opencv-python基础_第15张图片

#通常都是二值的图像来做腐蚀操作。腐蚀的大概意思就是往里面缩一些。
import cv2
import numpy as np
#灰度化
img_gray = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)
#img =  cv2.imread('my.jpg')
#img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#二值化
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

kernel = np.ones((3, 5), np.uint8)
erosion = cv2.erode(thresh,kernel,iterations = 1) #迭代次数表示做几次腐蚀操作

#展示所有的
res = np.hstack((img_gray,thresh,erosion))
#加上这一句就可以调整窗口大小
cv2.namedWindow("erosion",cv2.WINDOW_NORMAL);
cv2.imshow('erosion', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.2膨胀操作

opencv-python基础_第16张图片

import cv2
import numpy as np
#灰度化
img_gray = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)
#img =  cv2.imread('my.jpg')
#img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#二值化
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

kernel = np.ones((3, 5), np.uint8)
dilate = cv2.dilate(thresh, kernel, iterations=1)#迭代次数表示做几次膨胀操作

#展示所有的
res = np.hstack((img_gray,thresh,dilate))
#加上这一句就可以调整窗口大小
cv2.namedWindow("dilate",cv2.WINDOW_NORMAL);
cv2.imshow('dilate', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.3开运算(即先腐蚀,再膨胀)

opencv-python基础_第17张图片

#开运算消除小物体(白色)
import cv2
import numpy as np
#灰度化
img_gray = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)
#img =  cv2.imread('my.jpg')
#img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#二值化
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

kernel = np.ones((5,5), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

#展示所有的
res = np.hstack((img_gray,thresh,opening))
#加上这一句就可以调整窗口大小
cv2.namedWindow("opening",cv2.WINDOW_NORMAL);
cv2.imshow('opening', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.4闭运算(即先膨胀,再腐蚀)

opencv-python基础_第18张图片

#闭运算消除小型黑洞
import cv2
import numpy as np
#灰度化
img_gray = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)
#img =  cv2.imread('my.jpg')
#img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#二值化
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

kernel = np.ones((5,5), np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

#展示所有的
res = np.hstack((img_gray,thresh,closing))
#加上这一句就可以调整窗口大小
cv2.namedWindow("closing",cv2.WINDOW_NORMAL);
cv2.imshow('closing', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.5梯度运算(梯度=膨胀-腐蚀)

opencv-python基础_第19张图片

#梯度运算凸显出边缘
import cv2
import numpy as np
#灰度化
img_gray = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)
#二值化
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

kernel = np.ones((2,2),np.uint8)
gradient = cv2.morphologyEx(thresh, cv2.MORPH_GRADIENT, kernel)

#展示所有的
res = np.hstack((img_gray,thresh,gradient))
#加上这一句就可以调整窗口大小
cv2.namedWindow("gradient",cv2.WINDOW_NORMAL);
cv2.imshow('gradient', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.6顶帽(又称礼帽= 原始输入-开运算结果)

opencv-python基础_第20张图片

#礼帽用来分离比邻近点亮一些的斑块
import cv2
import numpy as np
#灰度化
img_gray = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)
#二值化
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

kernel = np.ones((7,7),np.uint8)
tophat = cv2.morphologyEx(thresh, cv2.MORPH_TOPHAT, kernel)

#展示所有的
res = np.hstack((img_gray,thresh,tophat))
#加上这一句就可以调整窗口大小
cv2.namedWindow("tophat",cv2.WINDOW_NORMAL);
cv2.imshow('tophat', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.7黑帽(黑帽 = 闭运算-原始输入)

opencv-python基础_第21张图片
 

#黑帽用来分离比邻近点暗一些的斑块
import cv2
import numpy as np
#灰度化
img_gray = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)
#二值化
ret, thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

kernel = np.ones((7,7),np.uint8)
blackhat  = cv2.morphologyEx(thresh,cv2.MORPH_BLACKHAT, kernel)

#展示所有的
res = np.hstack((img_gray,thresh,blackhat))
#加上这一句就可以调整窗口大小
cv2.namedWindow("blackhat",cv2.WINDOW_NORMAL);
cv2.imshow('blackhat', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

第四章 梯度计算--用于边缘检测(Canny,Sobel,Scharr)

opencv-python基础_第22张图片

import cv2
import numpy as np
def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()
img = cv2.imread('my.jpg',cv2.IMREAD_GRAYSCALE)

#canny算子
canny=cv2.Canny(img,80,150)

#sobel算子
#dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
#ddepth:图像的深度,一般取-1。
#dx和dy分别表示水平和竖直方向
#ksize是Sobel算子的大小

#白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值。
#sobel算子 能够捕获更加细致的纹理信息。
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)

sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)  

sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
 
#Scharr算子
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharrx = cv2.convertScaleAbs(scharrx)

scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharry = cv2.convertScaleAbs(scharry)  

scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0) 

#laplacian算子
laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)   

res = np.hstack((canny,sobelxy,scharrxy,laplacian))
cv_show(res,'res')

第五章 图像金字塔

opencv-python基础_第23张图片opencv-python基础_第24张图片opencv-python基础_第25张图片 opencv-python基础_第26张图片

import cv2
import numpy as np
def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()
img=cv2.imread("my.jpg")
cv_show(img,'img')

#高斯金字塔:向上采样方法(放大)
up=cv2.pyrUp(img)
cv_show(up,'up')

#高斯金字塔:向下采样方法(缩小)
down=cv2.pyrDown(img)
cv_show(down,'down')

#拉普拉斯金字塔
down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
cv_show(l_1,'l_1')

 

第六章轮廓检测
 

6.1轮廓检测

opencv-python基础_第27张图片

#均值滤波,二值化,以及形态学等操作的顺序要根据不同场景的图像调整次序
import cv2
import numpy as np
img = cv2.imread('bee.jpg')
#灰度化 
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#Sobel边缘检测
sobelx = cv2.Sobel(img_gray,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img_gray,cv2.CV_64F,0,1,ksize=3)
gradient = cv2.subtract(sobelx, sobely)
gradient = cv2.convertScaleAbs(gradient)

#均值滤波
blurred = cv2.blur(gradient , (9, 9))

#findContours(_,_,_)
#第二个参数
#cv2.RETR_EXTERNAL表示只检测外轮廓
#cv2.RETR_LIST检测的轮廓不建立等级关系
#cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
#cv2.RETR_TREE建立一个等级树结构的轮廓。
#第三个参数
#cv2.CHAIN_APPROX_SIMPLE	压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标(矩形只需四顶点)
#cv2.CHAIN_APPROX_TC89_L1	使用teh-Chinl chain 近似算法
#CV_CHAIN_APPROX_TC89_KCOS  使用teh-Chinl chain 近似算法
#cv2.CHAIN_APPROX_NONE	存储所有的轮廓点,相邻的两个点的像素位置差不超过1

#重点  寻找轮廓
(cnts, _) = cv2.findContours(blurred.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#将轮廓按大小降序排序
c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]

#计算最小斜矩形
rect = cv2.minAreaRect(c)
box = np.int0(cv2.boxPoints(rect))

#画出轮廓
cv2.drawContours(img,[box], -1, (0, 255, 0), 2)

cnt = cnts[0] #取第几个轮廓
print(cv2.arcLength(cnt,True))#周长,True表示闭合的

#边界矩形
area=cv2.contourArea(cnt)#面积
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
rect_area = w * h
extent = float(area) / rect_area
print ('轮廓面积',area,'边界矩形',rect_area,'轮廓面积与边界矩形比',extent)

#外接圆
(x,y),radius = cv2.minEnclosingCircle(cnt) 
center = (int(x),int(y)) 
radius = int(radius) 
cv2.circle(img,center,radius,(255,0,0),2)

#展示所有的
res = np.hstack((img_gray,gradient,blurred))
cv2.namedWindow("res",cv2.WINDOW_NORMAL);
cv2.imshow("res", res)
cv2.namedWindow("img",cv2.WINDOW_NORMAL);
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

6.2利用 hsv追踪蓝色物体

import cv2
import numpy as np

# 蓝色的HSV值
blue = np.uint8([[[255, 0, 0]]])
hsv_blue = cv2.cvtColor(blue, cv2.COLOR_BGR2HSV)
#print(hsv_blue)  # [[[120 255 255]]]


# 追踪蓝色物体
capture = cv2.VideoCapture(0)

# 蓝色的范围,不同光照条件下不一样,可灵活调整
lower_blue = np.array([100, 110, 110])
upper_blue = np.array([130, 255, 255])

while(True):
    # 1.捕获视频中的一帧
    ret, frame = capture.read()

    # 2.从BGR转换到HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # 3.inRange():介于lower/upper之间的为白色,其余黑色
    mask = cv2.inRange(hsv, lower_blue, upper_blue)

    # 4.只保留原图中的蓝色部分
    res = cv2.bitwise_and(frame, frame, mask=mask)

    img_gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
	#Sobel边缘检测
    sobelx = cv2.Sobel(img_gray,cv2.CV_64F,1,0,ksize=3)
    sobely = cv2.Sobel(img_gray,cv2.CV_64F,0,1,ksize=3)
    gradient = cv2.subtract(sobelx, sobely)
    gradient = cv2.convertScaleAbs(gradient)

	#均值滤波
    blurred = cv2.blur(gradient , (9, 9))

    #重点  寻找轮廓,opencv3版本
    (_,cnts, _) = cv2.findContours(blurred.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    #opencv4版本
    #(cnts, _) = cv2.findContours(blurred.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    #将轮廓按大小降序排序
    c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]

    #计算最小斜矩形
    rect = cv2.minAreaRect(c)
    box = np.int0(cv2.boxPoints(rect))

    #画出轮廓
    cv2.drawContours(frame,[box], -1, (0, 255, 0), 2)
	
    cv2.imshow('frame', frame)
    cv2.imshow('mask', mask)
    cv2.imshow('res', res)

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

 

第七章 图像直方图与傅里叶变换

7.1直方图

opencv-python基础_第28张图片opencv-python基础_第29张图片

opencv-python基础_第30张图片opencv-python基础_第31张图片

opencv-python基础_第32张图片

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

img = cv2.imread('my.jpg',0) #0表示灰度图

#1.直方图
hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.hist(img.ravel(),256); 
plt.show()

#2.直方图均衡化
equ = cv2.equalizeHist(img) 
plt.hist(equ.ravel(),256)
plt.show()

#3.自适应直方图均衡化
#将图像划分为多个小格子,然后对其进行均衡化处理,再对每个小格子的图像边界处理一下:
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
res_clahe = clahe.apply(img) 
plt.hist(res_clahe.ravel(),256)
plt.show()

#4.灰度图,直方图均衡化后的图,自适应直方图均衡化后的图 展示
res = np.hstack((img,equ,res_clahe))
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

#5.b g r分布图
img2 = cv2.imread('my.jpg') 
color = ('b','g','r')
for i,col in enumerate(color): 
    histr = cv2.calcHist([img2],[i],None,[256],[0,256]) 
    plt.plot(histr,color = col) 
    plt.xlim([0,256])
plt.show()

7.2傅里叶变换

opencv-python基础_第33张图片

#opencv中主要就是cv2.dft()和cv2.idft(),输入图像需要先转换成np.float32 格式。
#得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现。
#cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才能展示(0,255)


#1.dft
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('my.jpg',0)

img_float32 = np.float32(img)

dft = cv2.dft(img_float32, 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-python基础_第34张图片

#idft_低通滤波
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('my.jpg',0)

img_float32 = np.float32(img)

dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)     # 中心位置

# 低通滤波
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

# IDFT
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('Result'), plt.xticks([]), plt.yticks([])

plt.show()      


#idft_高通滤波
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('my.jpg',0)

img_float32 = np.float32(img)

dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)     # 中心位置

# 高通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0

# IDFT
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('Result'), plt.xticks([]), plt.yticks([])

plt.show()      


第八章角点检测(Harris,shi_tomasi,sift)

opencv-python基础_第35张图片

import cv2
import numpy as np

img = cv2.imread('chessboard.png')

# 1. Harris角点检测基于灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 2. Harris角点检测
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
# 腐蚀一下,便于标记
dst = cv2.dilate(dst, None)
# 3. 角点标记为红色
img[dst > 0.01 * dst.max()] = [0, 255, 255]

cv2.imshow('harris', img)
cv2.waitKey()
cv2.destroyAllWindows()

opencv-python基础_第36张图片
 

import cv2
import numpy as np

img = cv2.imread('chessboard.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Shi-Tomasi角点检测  速度相比Harris有所提升,可以直接得到角点坐标
corners = cv2.goodFeaturesToTrack(gray, 20, 0.01, 10)
corners = np.int0(corners)  # 12个角点坐标

for i in corners:
    # 压缩至一维:[[62,64]]->[62,64]
    x, y = i.ravel()
    cv2.circle(img, (x, y), 4, (0, 0, 255), -1)

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

opencv-python基础_第37张图片
 

#sift已经被申请专利了,所以,在opencv3.4.3.16 版本后,这个功能就不能用了。
#解决方法版本回退
#sudo pip uninstall opencv-python
#sudo pip uninstall opencv-contrib-python
#sudo pip install opencv-python==3.4.2.16
#sudo pip install opencv-contrib-python==3.4.2.16

import cv2
import numpy as np

img = cv2.imread('chessboard.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)

cv2.drawKeypoints(gray, kp, img,(0,255,0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('sift.jpg', img)
cv2.waitKey()
cv2.destroyAllWindows()

 第九章 模板匹配与KNN匹配

9.1模板匹配

opencv-python基础_第38张图片opencv-python基础_第39张图片

opencv-python基础_第40张图片opencv-python基础_第41张图片

opencv-python基础_第42张图片

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


# 1.模板匹配
img = cv2.imread('lena.jpg', 0)
template = cv2.imread('face.jpg', 0)
h, w = template.shape[:2]  # rows->h, cols->w

# 6种匹配方法
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:
    img2 = img.copy()

    # 匹配方法的真值
    method = eval(meth)
    res = cv2.matchTemplate(img, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    # 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
    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(img2, top_left, bottom_right, 255, 2)

    plt.subplot(121), plt.imshow(res, cmap='gray')
    plt.xticks([]), plt.yticks([])  # 隐藏坐标轴
    plt.subplot(122), plt.imshow(img2, cmap='gray')
    plt.xticks([]), plt.yticks([])
    plt.suptitle(meth)
    plt.show()


# 2.匹配多个物体
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
h, w = template.shape[:2]

res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):  # *号表示可选参数
    bottom_right = (pt[0] + w, pt[1] + h)
    cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)

cv2.imshow('img_rgb', img_rgb)
cv2.waitKey(0)


# 3.有关几个函数的说明:
x = np.arange(9.).reshape(3, 3)
print(np.where(x > 5))
# 结果:(array([2, 2, 2]), array([0, 1, 2]))

x = [1, 2, 3]
y = [4, 5, 6]
print(list(zip(x, y)))  # [(1, 4), (2, 5), (3, 6)]

9.2KNN匹配

opencv-python基础_第43张图片

import cv2
import numpy as np
import matplotlib.pyplot as plt
img1 = cv2.imread('box.png', 0)
img2 = cv2.imread('box_in_scene.png', 0)
def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
# cv_show('img1',img1)
# cv_show('img2',img2)
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
good = []
for m, n in matches:
    if m.distance < 0.75 * n.distance:
        good.append([m])
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv_show('img3',img3)

9.3利用KNN匹配加透视变换实现全景图像拼接
opencv-python基础_第44张图片

opencv-python基础_第45张图片

#Stitcher.py
import numpy as np
import cv2

class Stitcher:

    #拼接函数
    def stitch(self, images, ratio=0.75, reprojThresh=4.0,showMatches=False):
        #获取输入图片
        (imageB, imageA) = images
        #检测A、B图片的SIFT关键特征点,并计算特征描述子
        (kpsA, featuresA) = self.detectAndDescribe(imageA)
        (kpsB, featuresB) = self.detectAndDescribe(imageB)

        # 匹配两张图片的所有特征点,返回匹配结果
        M = self.matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh)

        # 如果返回结果为空,没有匹配成功的特征点,退出算法
        if M is None:
            return None

        # 否则,提取匹配结果
        # H是3x3视角变换矩阵      
        (matches, H, status) = M
        # 将图片A进行视角变换,result是变换后图片
        result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
        self.cv_show('result', result)
        # 将图片B传入result图片最左端
        result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
        self.cv_show('result', result)
        # 检测是否需要显示图片匹配
        if showMatches:
            # 生成匹配图片
            vis = self.drawMatches(imageA, imageB, kpsA, kpsB, matches, status)
            # 返回结果
            return (result, vis)

        # 返回匹配结果
        return result
    def cv_show(self,name,img):
        cv2.imshow(name, img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

    def detectAndDescribe(self, image):
        # 将彩色图片转换成灰度图
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        # 建立SIFT生成器
        descriptor = cv2.xfeatures2d.SIFT_create()
        # 检测SIFT特征点,并计算描述子
        (kps, features) = descriptor.detectAndCompute(image, None)

        # 将结果转换成NumPy数组
        kps = np.float32([kp.pt for kp in kps])

        # 返回特征点集,及对应的描述特征
        return (kps, features)

    def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh):
        # 建立暴力匹配器
        matcher = cv2.BFMatcher()
  
        # 使用KNN检测来自A、B图的SIFT特征匹配对,K=2
        rawMatches = matcher.knnMatch(featuresA, featuresB, 2)

        matches = []
        for m in rawMatches:
            # 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对
            if len(m) == 2 and m[0].distance < m[1].distance * ratio:
            # 存储两个点在featuresA, featuresB中的索引值
                matches.append((m[0].trainIdx, m[0].queryIdx))

        # 当筛选后的匹配对大于4时,计算视角变换矩阵
        if len(matches) > 4:
            # 获取匹配对的点坐标
            ptsA = np.float32([kpsA[i] for (_, i) in matches])
            ptsB = np.float32([kpsB[i] for (i, _) in matches])

            # 计算视角变换矩阵
            (H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh)

            # 返回结果
            return (matches, H, status)

        # 如果匹配对小于4时,返回None
        return None

    def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status):
        # 初始化可视化图片,将A、B图左右连接到一起
        (hA, wA) = imageA.shape[:2]
        (hB, wB) = imageB.shape[:2]
        vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
        vis[0:hA, 0:wA] = imageA
        vis[0:hB, wA:] = imageB

        # 联合遍历,画出匹配对
        for ((trainIdx, queryIdx), s) in zip(matches, status):
            # 当点对匹配成功时,画到可视化图上
            if s == 1:
                # 画出匹配对
                ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
                ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
                cv2.line(vis, ptA, ptB, (0, 255, 0), 1)

        # 返回可视化结果
        return vis
#ImageStiching.py
from Stitcher import Stitcher
import cv2

# 读取拼接图片
imageA = cv2.imread("left_01.png")
imageB = cv2.imread("right_01.png")

# 把图片拼接成全景图
stitcher = Stitcher()
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)

# 显示所有图片
cv2.imshow("Image A", imageA)
cv2.imshow("Image B", imageB)
cv2.imshow("Keypoint Matches", vis)
cv2.imshow("Result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

第十章霍夫变换

opencv-python基础_第46张图片
 

# ex2tron's blog:
# http://ex2tron.wang

import cv2
import numpy as np


# 1. 霍夫直线变换
img = cv2.imread('shapes.jpg')
cv2.imshow('src', img)

drawing = np.zeros(img.shape[:], dtype=np.uint8)  # 创建画板
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)

# 霍夫直线变换
lines = cv2.HoughLines(edges, 0.8, np.pi / 180, 90)

# 将检测的线画出来(注意是极坐标噢)
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(drawing, (x1, y1), (x2, y2), (0, 0, 255))

cv2.imshow('hough lines', np.hstack((img, drawing)))
cv2.waitKey(0)


# 2. 统计概率霍夫线变换
drawing = np.zeros(img.shape[:], dtype=np.uint8)

lines = cv2.HoughLinesP(edges, 0.8, np.pi / 180, 90,
                        minLineLength=50, maxLineGap=10)

# 将检测的线画出来
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(drawing, (x1, y1), (x2, y2), (0, 255, 0), 1, lineType=cv2.LINE_AA)

cv2.imshow('probabilistic hough lines', np.hstack((img, drawing)))
cv2.waitKey(0)


# 3. 霍夫圆变换
drawing = np.zeros(img.shape[:], dtype=np.uint8)

circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 20, param2=30)
circles = np.int0(np.around(circles))

# 将检测的圆画出来
for i in circles[0, :]:
    cv2.circle(drawing, (i[0], i[1]), i[2], (0, 255, 0), 2)  # 画出外圆
    cv2.circle(drawing, (i[0], i[1]), 2, (0, 0, 255), 3)  # 画出圆心

cv2.imshow('circles', np.hstack((img, drawing)))
cv2.waitKey(0)

第十一章 图像矫正

11.1仿射变换,透视变换

opencv-python基础_第47张图片opencv-python基础_第48张图片

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

img = cv2.imread('drawing.jpg')
rows, cols = img.shape[:2]


# 1.仿射变换

# 变换前的三个点
pts1 = np.float32([[50, 65], [150, 65], [210, 210]])
# 变换后的三个点
pts2 = np.float32([[50, 100], [150, 65], [100, 250]])

# 生成变换矩阵,维数:2*3
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.show()


# 2.透视变换

img = cv2.imread('card.jpg')

# 原图中卡片的四个角点
pts1 = np.float32([[148, 80], [437, 114], [94, 247], [423, 288]])
# 变换后分别在左上、右上、左下、右下四个点
pts2 = np.float32([[0, 0], [320, 0], [0, 178], [320, 178]])

# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)
# 进行透视变换,参数3是目标图像大小
dst = cv2.warpPerspective(img, M, (320, 178))

# matplotlib默认以RGB通道显示,所以需要用[:, :, ::-1]翻转一下
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('input')
plt.subplot(122), plt.imshow(dst[:, :, ::-1]), plt.title('output')
plt.show()

11.2基于傅里叶变换进行矫正
opencv-python基础_第49张图片

import cv2
import numpy as np
import math

def fourier_demo():
    #1、灰度化读取文件,
    img = cv2.imread('english.png',0)

    #2、图像延扩
    h, w = img.shape[:2]
    new_h = cv2.getOptimalDFTSize(h)
    new_w = cv2.getOptimalDFTSize(w)
    right = new_w - w
    bottom = new_h - h
    nimg = cv2.copyMakeBorder(img, 0, bottom, 0, right, borderType=cv2.BORDER_CONSTANT, value=0)
    cv2.imshow('src ', nimg)

    #3、执行傅里叶变换,并过得频域图像
    f = np.fft.fft2(nimg)
    fshift = np.fft.fftshift(f)
    magnitude = np.log(np.abs(fshift))


    #二值化
    magnitude_uint = magnitude.astype(np.uint8)
    ret, thresh = cv2.threshold(magnitude_uint, 11, 255, cv2.THRESH_BINARY)
    print(ret)

    cv2.imshow('thresh', thresh)
    print(thresh.dtype)
    #霍夫直线变换
    lines = cv2.HoughLinesP(thresh, 2, np.pi/180, 30, minLineLength=40, maxLineGap=100)
    print(len(lines))

    #创建一个新图像,标注直线
    lineimg = np.ones(nimg.shape,dtype=np.uint8)
    lineimg = lineimg * 255

    piThresh = np.pi/180
    pi2 = np.pi/2
    print(piThresh)

    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(lineimg, (x1, y1), (x2, y2), (0, 255, 0), 2)
        if x2 - x1 == 0:
            continue
        else:
            theta = (y2 - y1) / (x2 - x1)
        if abs(theta) < piThresh or abs(theta - pi2) < piThresh:
            continue
        else:
            print(theta)

    angle = math.atan(theta)
    print(angle)
    angle = angle * (180 / np.pi)
    print(angle)
    angle = (angle - 90)/(w/h)
    print(angle)

    center = (w//2, h//2)
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    rotated = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)
    cv2.imshow('line image', lineimg)
    cv2.imshow('rotated', rotated)

fourier_demo()
cv2.waitKey(0)
cv2.destroyAllWindows()

 

额!肝一整天,终于肝完了!!!!>_<  ========>  ^_^

你可能感兴趣的:(Opencv,OpenCV实例程序教程,python,opencv)