循环神经网络和图像分割

CV_tutorial1

  • Recurrent Neural Networks
    • 序列数据sequence data
    • 语言模型languag model
    • 循环神经网络recurrent neural networks
    • 门控循环单元gated recurrent unit
    • 长短期记忆网络long short-term memory
  • OpenCV 图形图像操作
      • 文档矫正
      • Gamma变化
      • 开运算
    • 传统图像分割
      • 分水岭算法

Recurrent Neural Networks

序列数据sequence data

前后数据通常具有关联性
比如:语音识别、音乐生成、视频行为识别、机器翻译、DNA序列分析。

语言模型languag model

语言模型是自然语言处理(NLP)的重要技术。NLP中常把文本看作是离散时间序列,一段长度为T的文本的词依次为 w 1 w_1 w1 w 2 w_2 w2、…、 w t w_t wt,其中 w t w_t wt时间步(Time Step)t 的输出或标签。
统计语料库(corpus)中的词频,语言模型将会计算该序列的概率P( w 1 , w 2 , . . . , w t w_1,w_2,...,w_t w1,w2,...,wt)
缺点:时间步t的词需要考虑t-1步的词,计算量随t呈指数增长。

循环神经网络recurrent neural networks

RNN是针对序列数据而生的神经网络结构,核心在于循环使用网络层参数,避免时间步增大带来的参数激增。并且,引入隐藏状态(Hidden State)用于记录历史信息,有效的处理数据的前后关联性。

激活函数为tanh,值域为(-1,1)

RNN的隐藏状态可以捕捉截至当前时间步的序列的历史信息。

但是梯度会随时间t呈指数变化,易引发梯度变化或梯度爆炸。

门控循环单元gated recurrent unit

GRU
缓解RNN梯度消失带来的问题,引入门概念,来控制信息流动,使模型更好记住长远时期的信息,并缓解梯度消失。

重置门 R t R_t Rt:哪些信息需要遗忘
更新门 Z t Z_t Zt:哪些信息需要注意

激活函数为Sigmoid,值域为(0,1),0表示遗忘,1表示保留。

更新门一直保持为1的话,信息可有效传递到当前步。

长短期记忆网络long short-term memory

一种带门控机制的循环神经网络LSTM,

引入3个门和记忆细胞(特殊的隐藏状态,记忆历史信息)
遗忘门:哪些信息需要遗忘
输入门:哪些信息需要流入当前记忆细胞
输出门:哪些记忆信息流入隐藏状态

OpenCV 图形图像操作

环境安装:
python.exe -m pip install --upgrade pip
pip install jupyter
pip install opencv-contrib-python

  • 读入图像
    cv2.imread()
    读取为B-G-R的通道顺序
    使用cv2.cvtColor(src, cv2.COLOR_BGR2RGB)即可转换为RGB顺序图像

  • 通道分离
    cv2.split(img)

  • 添加文字
    cv2.putText()

import numpy as np
import cv2
# 创建一个黑色的背景图
img = np.zeros((512,512,3),np.uint8)

# 添加文字
font = cv2.FONT_HERSHEY_SIMPLEX  # 自带的字体
cv2.putText(img, 'caiman', (20, 200), font, 3, (0,255,0), 5)
# 背景,‘文字内容’,左下角起点坐标,字体,比例(越大越大),颜色,线条粗细

# 创建窗口
winname = 'like'
cv2.namedWindow(winname)

# 显示图像
cv.imshow(winname, img)

# 等待键盘'ESC'命令退出窗口
cv2.waitKey(0)
cv2.destroyWindow(winname)

循环神经网络和图像分割_第1张图片

文档矫正

放射变换、透视变化

#encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像
src = cv2.imread('paper.png')

# 获取图像大小
rows, cols = src.shape[:2]

# 将源图像高斯模糊(去噪)
img = cv2.GaussianBlur(src, (3, 3), 0)
# 灰度化(方便边缘检测)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 边缘检测
edges = cv2.Canny(gray, 50, 250, apertureSize = 3)
cv2.imwrite("canny.jpg", edges)
cv2.imshow("canny", edges)

# 通过霍夫变换得到A4纸边缘(点集合)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 50, minLineLength = 90, maxLineGap = 10)
print(lines)
# 下面输出的点为四个顶点
for x1,y1,x2,y2 in lines[0]:
	print(x1,y1)
	print(x2,y2)
for x3,y3,x4,y4 in lines[1]:
	print(x3,y3)
	print(x4,y4)

# 绘制边缘
for x1,y1,x2,y2 in lines[0]:
	cv2.lines(gray, (x1, y1), (x2, y2), (0, 0, 255), 1)

# 根据四个顶点设置图像透视变换矩阵
pos1 = np.float32([[x2,y2], [x4,y4], [x1,y1], [x3,y3]]) 
pos2 = np.float32([[0, 0], [188, 0], [0, 262], [188, 262]])
M = cv2.getPerspectiveTransform(pos1, pos2)
print(M)

# 图像透视变换
result = cv2.warpPerspective(src, M, (190, 272))

# 显示图像
cv2.imshow("original", src)
cv2.imshow("result",result)
cv2.imshow("gray",gray)

# 等待显示
cv2.waitKey(0)
cv2.distroyAllWindows()

循环神经网络和图像分割_第2张图片

Gamma变化

非线性操作
gamma值调整的是图像中的亮度部分,而不会改变过暗或过亮的部分:
当gamma>1时,校正会降低图像亮度,使亮部细节更明显;
当gamma<1时,校正会增加图像亮度,使暗部细节更明显。

import cv2
import numpy as np
img = cv2.imread('img1.png')

def adjust_gamma(image, gamma = 1.0)
	invGamma = 1.0/gamma
	table = []
	for i in range(256):
		table.append(((i / 255.0) ** invGamma) * 255)
	table = np.array(table).astype("uint8")
	print(table)
	return cv2.LUT(image, table)

img_gamma = adjust_gamma(img, 0.8)
cv2.imshow("img", img)
cv2.imshow("img_gamma", img_gamma)

cv2.waitKey(0)
cv2.destoryAllWindows()

开运算

腐蚀(erode)操作,后膨胀(dilate)操作

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('img.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 设置结构元素的形状和尺寸
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) 

#121:1行2列的第1个图像,122:1行2列的第2个图像
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(openning), plt.title('opening')
plt.xticks([]), plt.yticks([])
plt.show()

对于消除噪音效果很好,
调整结构元素的大小和形状有不同效果。
这是5*5刷子的结果:
循环神经网络和图像分割_第3张图片

传统图像分割

图像分割是指将图像分成若干具有相似性质的区域的过程

  • 自适应阈值与固定阈值对比
    threshold vs adaptiveThreshold
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('img.png', 0) # 默认为1,0作为灰度图读入

# 固定阈值
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESHOLD_BINARY)
# 自适应阈值(原图,最大阈值、一般为255,小区域阈值的计算方法,阈值方式,小区域面积,最终阈值等于小区域计算出的阈值再减去此值)
th2 = cv2.adaptiveThreshold(
    img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,11, 4)
#全局阈值,均值自适应,高斯加权自适应对比
titles = ['Original', 'Global(v = 127)', 'Adaptive Mean(11,4)', 'Adaptive Mean(55,4)', 'Adaptive Gaussian(17,6)', 'Adaptive Gaussian(11,4)']
images = [img, th1, th2, th3, th4, th5]
for i in range(6):
    plt.subplot(3, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

循环神经网络和图像分割_第4张图片

  • 边缘检测算子
    Canny边缘检测算法:
    • 彩色图像转换为灰度图像
    • 对图像进行高斯模糊(去噪)
    • 计算图像梯度,根据梯度计算图像边缘幅值与角度
    • 沿梯度方向进行非极大值抑制(边缘细化)
    • 双阈值边缘连接处理
    • 二值化图像输出结果
import cv2
import numpy as np
# 以灰度图单通道图读入(彩色图像转换为灰度图像)
img = cv2.imread('lyx.png', 0)
# Canny(源图像,下阈值,上阈值,kernel_size)
v1 = cv2.Canny(img, 80, 200, (3, 3))
v2 = cv2.Canny(img, 50, 100, (5, 5))

# np.vstack():在竖直方向上堆叠
# np.hstack():在水平方向上堆叠
ret = np.hstack((v1, v2)) #拼接这样可以对比来看参数不同的效果不同
cv.imshow('caiman', ret)
cv2.waitKey(0)
cv2.destroyAllWindows()

循环神经网络和图像分割_第5张图片

分水岭算法

综合应用一下分割methods

分水岭算法步骤:

  1. 加载原始图像
  2. 阈值分割,将图像分割为黑白两个部分
  3. 对图像进行开运算
  4. 对开运算结果再进行膨胀,获取大部分背景区域
  5. 通过距离变换DistanceTransform获取大部分前景区域
  6. 背景区域和前景区域相减abstrac,得到二者重合区域
  7. 连通区域处理
  8. 最后使用分水岭算法
import cv2
import numpy as np
import matplotlib.pyplot as plt

# Step1.加载图像
img = cv2.imread('image/yezi.jpg')
# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Step2.固定阈值分割,将图像分为黑白部分
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# Step3.对图像进行‘开运算’(先腐蚀后膨胀)
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

# Step4.对‘开运算’的结果进行膨胀,得到基本就是背景的区域
sure_bg = cv2.dilate(opening, kernel, iterations=3)

# Step5.通过distanceTransform获取基本就是前景的区域sure_fg
# DIST_L1 DIST_C 只能对应掩膜为3, DIST_L2 可以为3或者5
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
print(dist_transform.max())
ret, sure_fg = cv2.threshold(dist_transform, 0.1 * dist_transform.max(), 255,0)

# Step6.sure_bg和sure_fg相减,得到背景和前景的重合区域
# 此区域和轮廓区域的关系位未知
sure_fg = np.uint8(sure_fg)
unknow = cv2.subtract(sure_bg, sure_fg)

# 连通区域处理
ret, markers = cv2.connectedComponents(sure_fg, connectivity=8) # 对连通区域标号,序号为0~N-1
print("原始markers")
print(markers) # markers相当于对前景目标都做了标记
# OpenCV分水岭算法对物体做的标注都必须大于1,背景标号为0,因此需要加1
markers = markers + 1
# 去掉属于背景区域的部分(让其变为0,成为背景)
markers[unknow==255] = 0

# Step8.分水岭算法
markers = cv2.watershed(img, markers) # 分水岭算法后,所有轮廓的像素点被标注为 -1
print("分水岭的markers")
print(markers)
# 标注为-1的像素点标红,OpenCV中颜色通道顺序为BGR
img[markers == -1] = [0, 0, 255]

# *************************打印******************************
titles = ['thresh', 'sure_bg', 'dist_transform', 'sure_fg', 'unknow','dst']
sure_bg2 = cv2.cvtColor(sure_bg, cv2.COLOR_BGR2RGB)
dist_transform2 = cv2.cvtColor(dist_transform, cv2.COLOR_BGR2RGB)
unknow2 = cv2.cvtColor(unknow, cv2.COLOR_BGR2RGB)
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
images = [cv2.cvtColor(thresh, cv2.COLOR_BGR2RGB),sure_bg2, dist_transform2, cv2.cvtColor(sure_fg, cv2.COLOR_BGR2RGB),
          unknow2,img2]
for i in range(6):
    plt.subplot(3, 2, i+1), plt.imshow(images[i],)
    plt.title(titles[i], fontsize = 8)
    plt.xticks([]), plt.yticks([])
plt.show()

循环神经网络和图像分割_第6张图片

145.3628
原始markers
[[0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 ...
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]]
分水岭的markers
[[-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  1  1 ...  1  1 -1]
 [-1 -1 -1 ... -1 -1 -1]]

处理结果放大:循环神经网络和图像分割_第7张图片

可以实现像素级别的分割,传统方法的精度要比深度学习方法更高

你可能感兴趣的:(计算机视觉基础,机器学习,python)