OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)

继上一篇博文,本片博客继续介绍图像处理基础,整理完毕之后会使用OpenCV完成一个小项目。

OpenCV自学记录(2)——图像处理基础(形态学处理、图像阈值化)

  • 1、形态学处理
    • 1.1腐蚀与膨胀
    • 1.2开运算与闭运算
    • 1.3黑帽与礼帽
    • 1.4形态梯度
  • 2、图像阈值化(三种方法)
    • 2.1固定阈值分割和自适应阈值分割
    • 2.2 Otsu’s Binarization: 基于直方图的二值化分割方法
  • 3、总结
  • 4、参考

1、形态学处理

1.1腐蚀与膨胀

腐蚀和膨胀主要针对二值化图像的白色部分
腐蚀(erode):是将灰度值小(灰度值最小为黑色)的区域增强扩展,主要用来去除比较亮的噪点,可以将图像断开裂缝变大
膨胀(dilate):是将灰度值大(灰度值最小为白色)的区域增强扩展,主要用来连通相似颜色或强度的区域,可以将图像断开裂缝变小
膨胀就是求局部最大值的操作:就是将图像与核进行卷积,计算核B覆盖区域的像素点的最大值,并把这个最大值赋给指定的元素——“求白”
腐蚀就是求局部最小值的操作:与膨胀的操作恰恰相反,腐蚀是求局部最小值。高亮区域逐渐变小,使其完全消失或在在细连通处断裂。——“求黑”
代码及操作效果如下:

import cv2
import numpy as np
image = cv2.imread("02.jpg")
#定义一个5x5的核
kernel = np.ones((5,5), np.uint8)
#iteration的值越高,模糊程度(腐蚀程度)就越高 呈正相关关系且只能是整数
#cv2.erode()函数实现腐蚀
img_erosion = cv2.erode(image, kernel, iterations=1)
#cv2.dilate()函数实现膨胀
img_dilation = cv2.dilate(image, kernel, iterations=1)
cv2.imshow('fushi',img_erosion)
cv2.imshow('pengzhang',img_dilation)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)_第1张图片

1.2开运算与闭运算

开运算是先腐蚀后膨胀。主要用于消除小物体,在纤细点处分离物体,并且在平滑较大物体的边界的同时不明显改变其面积,同时抑制比结构元小的亮细节。开运算断开前景连接,抑制亮细节
闭运算是先膨胀后腐蚀。用来填充物体内细小空洞、连接邻近物体、平滑其边界的同时并不明显改变其面积,同时抑制比结构元小的暗细节。闭运算闭合前景连接,抑制暗细节
首先介绍一下openvc中morphologyEx()函数,它是一种形态学变化函数

cv2.morphologyEx(img, op, kernel)

各参数意义:
img:传入的图片
op:进行变化的方式, cv2.MORPH_OPEN 进行开运算;cv2.MORPH_CLOSE 进行闭运算;cv2.MORPH_GRADIENT进行图像梯度;cv2.MORPH_TOPHAT为顶帽(top-hat)操作;cv2.MORPH_BLACKHAT为黑帽(black-hat)
kernel:表示方框的大小

下面是开运算和闭运算的代码和效果图:

# 开运算,闭运算
import cv2
import numpy as np
image = cv2.imread("02.jpg")
kernel = np.ones((5, 5), np.uint8)
# 开:先腐蚀,再膨胀:用于消除小物体,在纤细点处分离物体
opening = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
# 闭:先膨胀,再腐蚀:用来填充物体内细小空洞、连接邻近物体
closing = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
cv2.imshow('image', image)
cv2.imshow('closing', closing)
cv2.imshow('opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)_第2张图片

1.3黑帽与礼帽

礼帽 (top-hat),将突出比原轮廓亮的部分。礼帽 = 原始输入-开运算结果
黑帽(black-hat),将突出比原轮廓暗的部分。黑帽 = 闭运算-原始输入

# 礼帽和黑帽
import cv2
import numpy as np

img = cv2.imread("02.jpg")
kernel = np.ones((5, 5), np.uint8)
# 礼帽 = 原始输入-开运算结果
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
# 黑帽 = 闭运算-原始输入
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('image', img)
cv2.imshow('blackhat', blackhat)
cv2.imshow('tophat', tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()

1.4形态梯度

形态梯度可以突出团块(blob)的边缘,能够保留物体的边缘轮廓。形态滤波可以实现边缘检测。

# 梯度运算
import cv2
import numpy as np

img = cv2.imread("02.jpg")
kernel = np.ones((5, 5), np.uint8)
dilate = cv2.dilate(img, kernel, iterations=1)
erossion = cv2.erode(img, kernel, iterations=1)

# 将两个维度相同的numpy数组横向拼接。将腐蚀和膨胀的结果拼接在一起
res = np.hstack((dilate, erossion))
# 梯度=膨胀-腐蚀
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('res', res)
cv2.imshow('gradient', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)_第3张图片

2、图像阈值化(三种方法)

图像阈值化就是利用图像像素点的分布规律,设定阈值进行像素点分割,对图像中的像素做出取舍和决策。阈值可以作为简单的图像分割方法

2.1固定阈值分割和自适应阈值分割

通过函数cv2.threshold()和cv2.adaptiveThreshold() 实现,下面详细介绍两个函数
固定阈值分割:cv2.threshold()函数

#固定阈值分割函数
ret,dist = cv2.threshold(src,thresh,maxval,type)

参数意义:
src:输入图,只能输入单通道图像,通常来说为灰度图
dist:输出图
thresh:阈值
maxval:当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
type:二值化操作的类型,包括以下5种类型:cv2.THRESH_BINARY;cv2.THRESH_BINARY_INV;cv2.THRESH_TRUNC;cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV。
1、cv2.THRESH_BINARY:超过阈值部分取maxval(最大值),否则取0
2、cv2.THRESH_BINARY_INV:THRESH_BINARY的反转,即超过阈值部分取0,否则取maxval(最大值)
3、cv2.THRESH_TRUNC:大于阈值部分设为阈值,否则不变
4、cv2.THRESH_TOZERO:大于阈值部分不改变,否则设为0
5、cv2.THRESH_TOZERO_INV:THRESH_TOZERO的反转

固定阈值分割:设定阈值为127,进行五种不同二值化阈值操作,代码与效果图如下,效果图中第一张为原图,依次是不同的阈值分割方法的效果

import cv2
import numpy as np

img = cv2.imread("02.jpg",0)
# 二值化操作的类型,包括5种类型;ret为设置的阈值;thresh1为返回的阈值分割图
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)
# 将维度相同的numpy数组横向拼接。
res3 = np.hstack((img,thresh1, thresh2))
res5 = np.hstack((thresh3,thresh4,thresh5))
cv2.imshow('img', res3)
cv2.imshow('res', res5)
cv2.waitKey(0)

OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)_第4张图片OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)_第5张图片
自适应阈值分割:cv2.adaptiveThreshold()函数

#图像自适应阈值二值化函数
dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, Block Size, C)

参数意义:
dst:输出图
src:输入图,只能输入单通道图像,通常来说为灰度图
maxval:当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
thresh_type:阈值的计算方法,包含以下2种类型:cv2.ADAPTIVE_THRESH_MEAN_C:区域内均值;cv2.ADAPTIVE_THRESH_GAUSSIAN_C:区域内像素点加权和,权重为一个高斯窗口
type:二值化操作的类型,与固定阈值函数相同,用于控制参数2 maxval,包含以下5类,见固定阈值函数参数意义
Block Size:图片中区域的大小
C :阈值计算方法中的常数项

自适应阈值分割:两种不同的阈值计算方法的代码与效果图如下:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread("02.jpg",0)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# cv2.adaptiveThreshold(输入图, 所赋予的值, 阈值的计算方法, 二值化操作的类型, 图片中分块的大小, 阈值计算方法中的常数项)
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()

OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)_第6张图片

2.2 Otsu’s Binarization: 基于直方图的二值化分割方法

Otsu’s Binarization是一种基于直方图的二值化方法,它需要和threshold函数配合使用。Otsu(大律法)方法可用于提取前后背景,适用于有两个尖峰的灰度直方图的图片中(这样的图片前后背景乍看会分得很开)
Otsu过程:
1. 计算图像直方图;
2. 设定一阈值,把直方图强度大于阈值的像素分成一组,把小于阈值的像素分成另外一组;
3. 分别计算两组内的偏移数,并把偏移数相加;
4. 把0~255依照顺序多为阈值,重复1-3的步骤,直到得到最小偏移数,其所对应的值即为结果阈值。
代码(来自官方文档)和效果图如下:

import cv2
from matplotlib import pyplot as plt
img = cv2.imread('02.jpg',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
blur = cv2.GaussianBlur(img,(5,5),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"]
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()

OpenCV自学记录(2)——(一拳超人)图像处理基础(形态学处理、图像阈值化)_第7张图片

3、总结

本篇博客继上一篇之后,介绍了图像处理中的形态学操作——主要用于从图像中提取对表达和描绘区域形状有意义的图像分量,使后续的识别工作能够抓住目标对象最为本质(最具区分能力)的形状特征。以及图像阈值处理——阈值处理即图像二值化,是图像分割的一种最简单的方法。图像分割常见的有阈值和区域的方式,这里一共介绍了三种常用的阈值分割的方法。

4、参考

https://blog.csdn.net/sinat_21258931/article/details/61418681

你可能感兴趣的:(OPenCV自学记录,opencv,计算机视觉,python)