2019-03-14 00:19:27 LieberVater 阅读数 417
  • Python入门视频精讲

    Python入门视频培训课程以通俗易懂的方式讲解Python核心技术,Python基础,Python入门。适合初学者的教程,让你少走弯路! 课程内容包括:1.Python简介和安装 、2.第一个Python程序、PyCharm的使用 、3.Python基础、4.函数、5.高级特性、6.面向对象、7.模块、8.异常处理和IO操作、9.访问数据库MySQL。教学全程采用笔记+代码案例的形式讲解,通俗易懂!!!

    8189 人正在学习 去看看 汤小洋

一、关于PIL库

PIL是一个图像处理经常使用到的库,全名是Python Image Library,其中有一个子库是Image,我们今天就来用一下这个库

PIL可以做很多和图像处理相关的事情:

  • 图像归档(Image Archives)。PIL非常适合于图像归档以及图像的批处理任务。你可以使用PIL创建缩略图,转换图像格式,打印图像等等。
  • 图像展示(Image Display)。PIL较新的版本支持包括Tk PhotoImage,BitmapImage还有Windows DIB等接口。PIL支持众多的GUI框架接口,可以用于图像展示。
  • 图像处理(Image Processing)。PIL包括了基础的图像处理函数,包括对点的处理,使用众多的卷积核(convolution kernels)做过滤(filter),还有颜色空间的转换。PIL库同样支持图像的大小转换,图像旋转,以及任意的仿射变换。PIL还有一些直方图的方法,允许你展示图像的一些统计特性。这个可以用来实现图像的自动对比度增强,还有全局的统计分析等。

二、PIL库的简单使用

# -*- coding: utf-8 -*-
"""
Created on Tue Mar 12 14:03:00 2019

@author: Administrator
"""

from PIL import Image
from pylab import *



img1 = Image.open('E:\\360MoveData\\Users\\Administrator\\Desktop\\things2_0\\flower.jpg')
subplot(121)
axis('off')
imshow(img1)

img2 = Image.open('E:\\360MoveData\\Users\\Administrator\\Desktop\\things2_0\\flower.jpg').convert('1')
subplot(122)
axis('off')
imshow(img2)

show()

效果:

这里面的Image.open函数就是我们读取图片的函数,看起来和前面博客提到的cv库中的imread函数作用还是很相似的,subplot的作用在于我们将这个读取出来的图片作为最后输出的一个子图的形式,axis()顾名思义是针对显示图片的坐标轴的方法,如果这里不设置成off的话,就会变成这种效果:

可以看到我们在读取第二个子图的时候使用了convert()函数,这个函数的作用是什么呢,是指明了我们对于图像处理的模式,比如我这里指定了模式为“1”,根据我们运行的效果也可以看出来,在这个模式下的图片只有黑白两种颜色,不过这样说显得有点不专业嘿,用老师在课上的话讲,把这种叫做通道,如果我们传统的RGB,是由三种基本颜色组成的,这种就是有三个颜色通道,那么我们这个模式1的图片处理,可以看到非黑即白,即便如此,它的每个像素也是用八位来表示,0表示黑,255表示白,经过convert函数处理之后读取出来的图片,就如同我们刚才看到的右侧子图,变成了黑白的颜色。

另外一种模式是L,在这种模式下会出现什么效果呢?让我们试一下

嘿,明显看到这个图片处理得比刚才的模式细腻多了呀,而且也不只有黑白两种颜色,而是一种灰灰的颜色,与模式1相似,模式L的每个像素用8个bit表示,0表示黑,255表示白,其他数字表示不同的灰度。在PIL中,从模式“RGB”转换为“L”模式是这样转换的:

L = R * 299/1000 + G * 587/1000+ B * 114/1000

https://www.jianshu.com/p/bdd9bfcbedb7这篇博客中看到了有关convert函数几种模式的介绍,如下:

convert()是图像实例对象的一个方法,接受一个 mode 参数,用以指定一种色彩模式
1 ------------------(1位像素,黑白,每字节一个像素存储)
L ------------------(8位像素,黑白)
P ------------------(8位像素,使用调色板映射到任何其他模式)
RGB------------------(3x8位像素,真彩色)
RGBA------------------(4x8位像素,带透明度掩模的真彩色)
CMYK--------------------(4x8位像素,分色)
YCbCr--------------------(3x8位像素,彩色视频格式)
I-----------------------(32位有符号整数像素)
F------------------------(32位浮点像素)

所以接下来依次验证几种模式,左面的都是原图,右面的代表不同的模式效果

模式P:



模式RGBA:

模式CMYK:

模式YCbCr:

模式I:

模式F:

 

针对PIL库中的几个函数的实验大概就是这样,在这个过程中参考了一些大佬的博客,我自己也是刚刚开始这方面的学习,后面会慢慢更新学习过程中的感受和新知识

2017-11-26 11:20:01 thatluck 阅读数 271
  • Python入门视频精讲

    Python入门视频培训课程以通俗易懂的方式讲解Python核心技术,Python基础,Python入门。适合初学者的教程,让你少走弯路! 课程内容包括:1.Python简介和安装 、2.第一个Python程序、PyCharm的使用 、3.Python基础、4.函数、5.高级特性、6.面向对象、7.模块、8.异常处理和IO操作、9.访问数据库MySQL。教学全程采用笔记+代码案例的形式讲解,通俗易懂!!!

    8189 人正在学习 去看看 汤小洋

1.转换成灰度图片

from PIL import Image
Image.open('in.jpg').convert('L').save('out.jpg');

一行代码搞定,是不是很酷~

2.图形复制与粘贴

from PIL import Image
import os

pil_im = Image.open('in.png');
box = (0,162,30,192)
box2 = (200,162,230,192)
region = pil_im.crop(box)
pil_im.paste(region,box2)
pil_im.save('out.png')
2019-03-23 15:38:35 LieberVater 阅读数 193
  • Python入门视频精讲

    Python入门视频培训课程以通俗易懂的方式讲解Python核心技术,Python基础,Python入门。适合初学者的教程,让你少走弯路! 课程内容包括:1.Python简介和安装 、2.第一个Python程序、PyCharm的使用 、3.Python基础、4.函数、5.高级特性、6.面向对象、7.模块、8.异常处理和IO操作、9.访问数据库MySQL。教学全程采用笔记+代码案例的形式讲解,通俗易懂!!!

    8189 人正在学习 去看看 汤小洋

上一次进行了读取图片的人脸识别,这一次要进行一点不一样的事情,所以我们要再进步一点,如果使用我们电脑的摄像头,并且可以读取出我们的人脸,这样会更酷一点。那么大概的思路其实是这样的,视频识别和人脸识别的区别其实是从视频中读取出一帧的图像处理,再用上一次的处理办法,框出我们识别出的人脸,就可以了

一、获取摄像头

之前学习Android开发的时候,如果开发的应用需要摄像头的话是需要获取到摄像头权限的,这一次使用python想着会不会也需要这样做,然后查了一下,发现真的是要方便很多,直接获取就可以了。具体方法是这样的:

cap = cv2.VideoCapture(0) 

是的,opencv中支持了直接使用摄像头,这里的参数是0,看到有一位大佬电脑配了不止一个摄像头,这里就会修改参数,类似于摄像头的编号,比如我装了三个摄像头,这里的参数可能设置为0-2都是可以的。

然后的工作和之前的类似,首先我们要获取到识别器,具体操作这样:

face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml') 

然后把它加载进来

face_cascade.load('E:\\anaconda\\pkgs\\libopencv-3.4.1-h875b8b8_3\\Library\\etc\\haarcascades\\haarcascade_frontalface_default.xml')

二、后续处理

从上一次我们大概知道,至少现阶段我做的图像处理都是先转换为灰色,再处理,这一次也是这样,先读取视频中的一帧,再转换为灰色的:

ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 

然后通过我们上次说的通过使用detectMultiScale函数,调整参数完成识别,这里不再赘述

需要说的是这里其实是需要一个while(true)的循环来一直处理的,为什么?因为这是一个视频呀,而且是打开摄像头获取到的视频,如果我们不关闭摄像头的话甚至可以认为这是一段无限长的视频,使用一个这样的循环保证我们可以对每一帧图像进行处理,持续地对人脸进行识别。

三、遇到的问题

运行时遇到了这样的问题:

error: (-215) scn == 3 || scn == 4 in function cv::cvtColor

上网查看了一下,对代码做了一定的改进,对上述读取出的ret进行判断,如果为true的话再开始转灰度,否则的话则终止,查了一下videoCapture.read这个函数返回的两个参数的意义,ret表示对当前帧的判断,如果是一张合法的帧或者说,是一张可处理的帧,才返回true,否则返回false,frame则返回的是我们获取到的帧对象,所以这个报错信息大概可能是因为有些帧不合法而我们紧接着就进行了灰度转换,这时候就会出错,所以以后如果还要使用这个函数的话还是记得对ret这个返回值有一个判断会比较好,否则可能会出错

四、程序

# -*- coding: utf-8 -*-
"""
Created on Sat Mar 23 14:43:48 2019

@author: Administrator
"""

import cv2
cap = cv2.VideoCapture(0) 
face_cascade = cv2.CascadeClassifier(r'haarcascade_frontalface_default.xml') # 加载人脸特征库
face_cascade.load('E:\\anaconda\\pkgs\\libopencv-3.4.1-h875b8b8_3\\Library\\etc\\haarcascades\\haarcascade_frontalface_default.xml')
while(True):
    ret, frame = cap.read() 
    if ret is True: 
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 

    else:   

        break
 
    faces = face_cascade.detectMultiScale(gray, scaleFactor = 1.15, minNeighbors = 5, minSize = (5, 5)) 
    for(x, y, w, h) in faces:
        cv2.rectangle(gray, (x, y), (x + w, y + h), (0, 0, 255), 2) 
 
    cv2.imshow('Face Recognition', gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release() 
cv2.destroyAllWindows()

 

五、效果(马赛克版)

嗯中间还测试了一下,即使移动,也可以识别出来,而且由于我们使用了一个死循环的方式,点击关闭之后还会弹出视频窗口

2019-03-13 22:06:01 LieberVater 阅读数 1639
  • Python入门视频精讲

    Python入门视频培训课程以通俗易懂的方式讲解Python核心技术,Python基础,Python入门。适合初学者的教程,让你少走弯路! 课程内容包括:1.Python简介和安装 、2.第一个Python程序、PyCharm的使用 、3.Python基础、4.函数、5.高级特性、6.面向对象、7.模块、8.异常处理和IO操作、9.访问数据库MySQL。教学全程采用笔记+代码案例的形式讲解,通俗易懂!!!

    8189 人正在学习 去看看 汤小洋

一、环境

由于这学期开了图像处理这门课,所以想着在各种实验开始之前自己先动手试一下

图像处理那首先要配个环境嘛,配环境真的是我长久以来的噩梦了,每次都会出现奇奇怪怪的问题,首先上网查找了一下,opencv这个库还是用的比较多的,如果想要使用C++来做图像处理的话,那么使用visual studio搭配opencv是比较常见的,所以就照着网上的教程下载好了vs之后下载了opencv的包,将包导入指定的路径也设置好环境变量之后发现还是不行,怎么办呢?这个时候想到那还不如自己直接用python,一来现在python使用的越来越多,二来方法也多,语法什么的也比较简单,正好自己电脑上之前配置了pycharm,这样省了很多事

本来以为直接在pycharm里面的settings里面导入opencv的包就可以了,可是查了一下发现没有,这里还是要自己从网上下载然后导入,还是好麻烦呀,从网上查到可以从anaconda里面下载,比较方便,可是一个问题是我的pycharm的python解释器是用的自己下载的,而没用anaconda自带的解释器,这样下载下来可能也用不了,机智的我想到把原来的解释器卸载掉然后使用anaconda带来的解释器不就得了,不巧的是卸载的时候脑子一热把anaconda也卸载了……(这可怎么办好)无奈下只好重新下载了anaconda

anaconda有两种下载途径,第一种是从官网下载,第二种是使用清华镜像,清华镜像要快一点,但是一个问题是pycharm使用的时候会报错,这个时候要修改一个.condarc文件,后来又出了各种问题我就想那还是用国外的下载吧,慢就慢一点呗,意外的是其实也没有很慢,这个时候又出了一个错误,这时候重新使用国外下载的版本会报另外一个错误,有些博客提到使用conda update 或者conda update --reset这两条指令,由于前面修改了.condarc文件,所以并没有解决我的问题。可以采用两种方法解决,第一种是改回原来的样子,但是如果像我一样忘了原来的文件怎么办,就可以用第二种方法,将这个文件删掉,再重新执行conda update,成功了。

接下来是修改pycharm中的解释器,需要提到的是不仅要修改interpreter,还需要在pycharm的Run按钮旁边的这个位置

我这里对应到cvTest2的下拉框,找到Edit Configuration,修改其中使用的解释器,不然的话由于原来的python解释器和现在的anaconda解释器不同,仍然会提示路径错误,找不到python

就在刚刚可以在pycharm中运行cv且不报错的时候,突然发现anaconda自带了一个神奇的小东西,它的名字叫做spyder,这个小可爱如果早点出现的话,可省了我好多麻烦

Spyder是什么呢?

嗯这是一个看着很让人喜欢的python编译器,界面大概是这样的

简洁又可爱是不是?更好的是在这个环境里,anaconda下载的库可以直接使用,我的cv使用的第一个成功 的例子就是在Spyder运行成功的,对它的好感又多了一分。

二、实例——读取一个图片

opencv这个库提供了很多有关图像处理的方法,在这里我们首先执行一个可以读取图片的程序:

import cv2 as cv

# 读入图片文件
src = cv.imread('E:\\360MoveData\\Users\\Administrator\\Desktop\\things2_0\\flower.jpg')
# 创建一个名字加 “ input image ” 的窗口,
# 窗口可以根据图片大小自动调整
cv.namedWindow('input image', cv.WINDOW_AUTOSIZE)
# 在窗口显示图片
cv.imshow('input image', src)

# 等待用户操作
cv.waitKey(0)
# 释放所有窗口
cv.destroyAllWindows()


imread这个方法提供了读取数据的方法,下面的nameWindow方法根据其名字就可以得知是对读取图片之后弹出的窗口做设置的,具体可看代码中注释,接下来我们看一下执行出来的效果

哈,读取出来的图片和保存的原图是一样的,这是我要学习图像处理的第一步,那么下一步就要对这个图片做一些改动,这部分放在下一篇博客再讲

2019-04-18 22:00:00 fendouaini 阅读数 844
  • Python入门视频精讲

    Python入门视频培训课程以通俗易懂的方式讲解Python核心技术,Python基础,Python入门。适合初学者的教程,让你少走弯路! 课程内容包括:1.Python简介和安装 、2.第一个Python程序、PyCharm的使用 、3.Python基础、4.函数、5.高级特性、6.面向对象、7.模块、8.异常处理和IO操作、9.访问数据库MySQL。教学全程采用笔记+代码案例的形式讲解,通俗易懂!!!

    8189 人正在学习 去看看 汤小洋

640?wx_fmt=jpeg

 


【前言】图像预处理对于整个图像处理任务来讲特别重要。如果我们没有进行恰当的预处理,无论我们有多么好的数据也很难得到理想的结果。

本篇是视觉入门系列教程的第二篇。整个视觉入门系列内容如下:

  1. 理解颜色模型与在图像上绘制图形(图像处理基本操作)。

  2. 基本的图像处理与滤波技术。

  3. 从特征检测到人脸检测。

  4. 图像分割与分水岭(Watershed)算法(TBU)

在边缘和轮廓检测中,噪声对检测的精度有很大的影响。因此,去除噪声和控制像素值的大小可以帮助模型聚焦于整体特征,获得更高的精度。对应的图像处理技术包括:模糊化(Blurring)、阈值化(thresholding)和形态转换(morphological transformation)。本篇我们将详细介绍这几个常见的图像预处理技术。(本文假设读者已经熟悉卷积的概念。)

模糊化(Blurring)

模糊化的目标是实现降噪。我们必须格外注意的是:如果我们把边缘检测算法应用到高分辨率的图像上,我们就会得到很多我们不感兴趣的检测结果;

640?wx_fmt=png

相反,如果我们把图像模糊太多,我们就会丢失数据。因此,我们需要找到一个适当的模糊量,从而不失去理想的边缘。

有多种技术用于实现模糊效果,在这里我们讨论OpenCV中常用的四种技术:平均模糊(Averaging blurring)、高斯模糊(Gaussian blurring)、中值模糊(median blurring)和双边滤波(bilateral filtering)。这四种技术应用一个共同的基本原理,即使用滤波器(内核)对图像进行卷积运算。不同的是,在四种模糊方法中使用的滤波器的值是不同的。

平均模糊(Average blurring)是取给定内核(kernel)区域下所有像素值的平均值替换中心的值。例如,假设给定一个大小为5X5的内核(kernel),我们计算卷积结果的平均值,并将结果放在给定区域的中心。示例如下:

640?wx_fmt=png

如果我们增加内核的大小,像素值将更加归一化。因此图像也会变得越来越模糊。让我们用下面的代码对比处理结果。(为了便于比较,将把原始图像加到结果中,进行对比显示。)

# Import the image and convert to RGB 
img = cv2.imread('text.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# Plot the image with different kernel sizes
kernels = [51117]
fig, axs = plt.subplots(nrows = 1, ncols = 3, figsize = (2020))
for ind, s in enumerate(kernels):
    img_blurred = cv2.blur(img, ksize = (s, s))
    ax = axs[ind]
    ax.imshow(img_blurred)
    ax.axis('off')
plt.show()

640?wx_fmt=png

中值模糊(Medium blurring)和平均模糊(Average blurring)是一样的,只是它使用的是中值而不是平均值。正由于这个特性,当我们需要处理图像中突然出现的噪音时(如“椒盐噪音”),使用中值模糊(medium blurring)的效果要比平均模糊(average blurring)效果好。

640?wx_fmt=png


高斯模糊(Gaussian blurring)是使用“值”具有高斯分布的核函数。由于这些值是由高斯函数生成的,因此它的参数需要一个sigma值。如上图,内核的值在靠近中心的地方变高,在靠近角的地方变小。将该方法应用于具有正态分布的噪声,如白噪声,效果较好。

 

双边滤波(Bilateral Filtering)是高斯模糊的一个高级版本。模糊化不仅可以溶解噪声,而且还会平滑边缘。而双边滤波器能在去除噪声的同时保持边缘锐化。这是由于它不仅使用高斯分布值,还同时考虑了距离和像素值的差异。因此,需要指定sigmaSpace和sigmaColor这两个参数。

# Blur the image 
img_0 = cv2.blur(img, ksize = (77))
img_1 = cv2.GaussianBlur(img, ksize = (77), sigmaX = 0)   
img_2 = cv2.medianBlur(img, 7)
img_3 = cv2.bilateralFilter(img, 7, sigmaSpace = 75, sigmaColor =75)
# Plot the images
images = [img_0, img_1, img_2, img_3]
fig, axs = plt.subplots(nrows = 1, ncols = 4, figsize = (2020))
for ind, p in enumerate(images):
    ax = axs[ind]
    ax.imshow(p)
    ax.axis('off')
plt.show()

640?wx_fmt=png

阈值化(Thresholding)

图像的阈值化就是利用图像像素点分布规律,设定阈值进行像素点分割,进而得到图像的二值图像。我们需要设置阈值和最大值,然后据此相应地进行像素值转换。常用的阈值化包含有五种不同的类型:二进制阈值化、反二进制阈值化、阈值化到零、反阈值化到零,和阈值截断。

img = cv2.imread('gradation.png')
# Thresholding 
_, thresh_0 = cv2.threshold(img, 127255, cv2.THRESH_BINARY)
_, thresh_1 = cv2.threshold(img, 127255, cv2.THRESH_BINARY_INV)
_, thresh_2 = cv2.threshold(img, 127255, cv2.THRESH_TOZERO)
_, thresh_3 = cv2.threshold(img, 127255, cv2.THRESH_TOZERO_INV)
_, thresh_4 = cv2.threshold(img, 127255, cv2.THRESH_TRUNC)
# Plot the images
images = [img, thresh_0, thresh_1, thresh_2, thresh_3, thresh_4]
fig, axs = plt.subplots(nrows = 2, ncols = 3, figsize = (1313))
for ind, p in enumerate(images):
    ax = axs[ind//3, ind%3]
    ax.imshow(p)
plt.show()

640?wx_fmt=png

640?wx_fmt=png

ia_10008

如上图所示,每种类型的阈值都可以用数学公式表示,I(x, y)是像素点的强度(也称为点(x, y)的像素值)。上图中的图像示例,可以更直观的理解不同阈值化类型之间的区别。

只取一个阈值并将其应用于图像的所有部分并不能满足我们的全部需求。如果我们有一张在多个不同区域亮度差异较多的图片这种情况,将一个值应用于整个图像一般不利于我们的图像处理任务。其对应更好的方法是对图像的每个部分使用不同的阈值。对应这种情况还有另外一种阈值化技术称为自适应阈值化(Adaptive threshilding)。通过对图像邻域内阈值的计算,可以得到不同光照条件下的较好结果。

# Convert the image to grayscale
img = cv2.imread('text.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Adaptive Thresholding
_, thresh_binary = cv2.threshold(img, thresh = 127, maxval = 255, type = cv2.THRESH_BINARY)
adap_mean_2 = cv2.adaptiveThreshold(img, 255, 
                                    cv2.ADAPTIVE_THRESH_MEAN_C, 
                                    cv2.THRESH_BINARY, 72)
adap_mean_2_inv = cv2.adaptiveThreshold(img, 255, 
                                        cv2.ADAPTIVE_THRESH_MEAN_C, 
                                        cv2.THRESH_BINARY_INV, 72)
adap_mean_8 = cv2.adaptiveThreshold(img, 255, 
                                    cv2.ADAPTIVE_THRESH_MEAN_C, 
                                    cv2.THRESH_BINARY, 78)
adap_gaussian_8 = cv2.adaptiveThreshold(img, 255, 
                                    cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
                                    cv2.THRESH_BINARY, 78)

我们需要将颜色模式转换为灰度来进行自适应阈值化。自适应阈值的参数有maxValue(在上面的示例中设置为255)、adaptiveMethod、thresholdType、blocksize和C。这里使用的自适应方法有两种:adaptive_threshold_mean_c和adaptive_threshold_gaussian_c。让我们通过下方代码对比自适应阈值化的不同结果。

# Plot the images
images = [img, thresh_binary, adap_mean_2, adap_mean_2_inv, 
          adap_mean_8, adap_gaussian_8]
fig, axs = plt.subplots(nrows = 2, ncols = 3, figsize = (1515))
for ind, p in enumerate(images):
    ax = axs[ind%2, ind//2]
    ax.imshow(p, cmap = 'gray')
    ax.axis('off')
plt.show()

640?wx_fmt=png

如上图所示,左边为原始图像与二进制阈值化结果图。对比二进制阈值化结果图与右上方两张结果图(由adaptive_threshold_mean_c方法生成)可得,后者生成了更为详细的结果。我们还可以看出,当C值更大时,图像将变得更显式。C代表从均值或加权均值中减去值的大小。通过观察上图右子图上下两幅图像,我们还可以对比查看相同C值下adaptive_threshold _mean_c和adaptive_threshold _gaussian_c两种方法生成的不同效果图。

梯度(Gradient)

在数学中,梯度用于几何地表示多变量函数图形的斜率。由于它是一个向量值函数,代表着方向和大小两种属性。在这里,我们也可以将同样的概念引入到图像的像素值中。图像梯度表示像素强度或颜色模式的方向变化,因此可以通过梯度来定位边缘。

# Apply gradient filtering
sobel_x = cv2.Sobel(img, cv2.CV_64F, dx = 1, dy = 0, ksize = 5)
sobel_y = cv2.Sobel(img, cv2.CV_64F, dx = 0, dy = 1, ksize = 5)
blended = cv2.addWeighted(src1=sobel_x, alpha=0.5, src2=sobel_y,
                          beta=0.5, gamma=0)
laplacian = cv2.Laplacian(img, cv2.CV_64F)

Sobel运算同时使用高斯平滑和微分。我们通过cv2.Sobel()函数使用它,可以定义两个不同的方向:垂直方向(sobel_x)和水平方向(sobel_y)。dx和dy表示导数。当dx = 1时,通过计算像素值沿水平方向的导数,从而进行图像滤波。

通过函数cv2.addWeighted()对sobel_x和sobel_y的两种过滤器加权求和,可以实现两个方向上的梯度求解及图像滤波。上述代码中两种过滤器设定了相同的权重。

拉普拉斯运算使用的是x和y的二阶导数,数学表达式如下。

640?wx_fmt=png

让我们通过下方代码更直观的看看这些处理后图像是什么样的。

# Plot the images
images = [sobel_x, sobel_y, blended, laplacian]
plt.figure(figsize = (2020))
for i in range(4):
    plt.subplot(14, i+1)
    plt.imshow(images[i], cmap = 'gray')
    plt.axis('off')
plt.show()

640?wx_fmt=png

如上图所示,第一幅和第二幅图像均含有一个方向图样。在第一张图中,我们可以清楚地看到垂直方向上的边缘。在第二幅图中,我们可以看到水平线。第三幅和第四幅图像,两个方向的边缘都凸显出来了。

形态转换(Morpgological transformations)

通过滤波操作来转换图像的形态的技术称为形态变换(morphological transformation)。首先,让我们了解下腐蚀(erosion)和扩张(dilation)。

腐蚀(Erosion) 是一种缩小图形形态的技术,通常被应用在灰度图上。过滤器的形状可以是矩形、椭圆和交叉形状。通过过滤器删除给定区域下的全部0值。

640?wx_fmt=png

代码实现如下:

img = cv2.imread('simpson.jpg')
# Create erosion kernels 
kernel_0 = np.ones((99), np.uint8)
kernel_1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (99))
kernel_2 = cv2.getStructuringElement(cv2.MORPH_CROSS, (99))
kernels = [kernel_0, kernel_1, kernel_2]
# Plot the images
plt.figure(figsize = (2020))
for i in range(3):
    img_copy = img.copy()
    img_copy = cv2.erode(img_copy, kernels[i], iterations = 3)
    plt.subplot(13, i+1)
    plt.imshow(img_copy)
    plt.axis('off')
plt.show()

640?wx_fmt=png

上图形象的展示出不同滤波器下的不同缩放结果。我们可以看到三张分别使用基础(方形)滤波器、椭圆形滤波器和交叉滤波器处理过的结果图。可以看出其分别以“圆形”、“线性”和“对角线”的方式进行收缩。

扩张(Dilation)与侵蚀是相反的。它是一种对图形形态进行放大的操作。其作用也与侵蚀相反。实现代码如下。

# Apply dilation
kernel = np.ones((99), np.uint8)
img_dilate = cv2.dilate(img, kernel, iterations = 3)
plt.figure(figsize = (2010))
plt.subplot(121); plt.imshow(img, cmap="gray")
plt.subplot(122); plt.imshow(img_dilate, cmap="gray")
plt.show()

640?wx_fmt=png

开闭运算是侵蚀和扩张的混合形式。开运算是指先进行侵蚀,然后对侵蚀结果进行扩张操作。相对应的,闭运算是指先进行扩张,再进行侵蚀。

640?wx_fmt=png

正如上图所示,闭运算一般用于检测图形的整体轮廓,开运算用于检测图形的子模式(subpatterns)。可以使用函数cv2.morphologyEx()来实现这些操作。参数op用于指定使用哪种运算类型(开/闭)。完整代码如下所示。

# Apply the operations
kernel = np.ones((99), np.uint8)
img_open = cv2.morphologyEx(img, op= cv2.MORPH_OPEN, kernel)
img_close = cv2.morphologyEx(img, op= cv2.MORPH_CLOSE, kernel)
img_grad = cv2.morphologyEx(img, op= cv2.MORPH_GRADIENT, kernel)
img_tophat = cv2.morphologyEx(img, op= cv2.MORPH_TOPHAT, kernel)
img_blackhat = cv2.morphologyEx(img, op= cv2.MORPH_BLACKHAT, kernel)
# Plot the images
images = [img, img_open, img_close, img_grad, 
          img_tophat, img_blackhat]
fig, axs = plt.subplots(nrows = 2, ncols = 3, figsize = (1515))
for ind, p in enumerate(images):
    ax = axs[ind//3, ind%3]
    ax.imshow(p, cmap = 'gray')
    ax.axis('off')
plt.show()

640?wx_fmt=png

注意,原图中的手在分别使用开闭操作进行处理时会产生不同的结果。梯度滤波(MORPH_CGRADIENT)运算是计算扩张结果图与腐蚀结果图之差。顶帽(Top-hat)运算(MORPH_TOPHAT)是计算开运算结果图与原始图像之差,黑帽(Black Hot)运算(MORPH_BLACKHAT)是计算闭运算结果图与原始图像之差。形态学运算详细介绍参看(https://homepages.inf.ed.ac.uk/rbf/HIPR2/morops.htm)。

总结与展望

本篇介绍了OpenCV中几项比较常用的运算。下篇将介绍轮廓检测和人脸检测等检测技术。欢迎批评指正。

 

欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/

欢迎关注PyTorch官方中文教程站:
http://pytorch.panchuang.net/

没有更多推荐了,返回首页