网站建设哪家稳妥,高端网站开发地址,wordpress模板页面怎么添加图片,网站被镜像怎么办总结
本系列是机器学习课程的系列课程#xff0c;主要介绍机器学习中图像处理技术。
参考
【人工智能】PythonOpenCV图像处理#xff08;一篇全#xff09;
一文讲解方向梯度直方图#xff08;hog#xff09;
【杂谈】计算机视觉在人脸图像领域的十几个大的应用方向主要介绍机器学习中图像处理技术。
参考
【人工智能】PythonOpenCV图像处理一篇全
一文讲解方向梯度直方图hog
【杂谈】计算机视觉在人脸图像领域的十几个大的应用方向你懂了几分
开源地理空间基金会中文分会 Pillow (PIL Fork) 10.0.1 文档
python使用opencv对图像添加(高斯/椒盐/泊松/斑点)噪声
【OpenCV实战】简洁易懂的车牌号识别PythonOpenCV实现“超详解”含代码
本门课程的目标
完成一个特定行业的算法应用全过程
懂业务会选择合适的算法数据处理算法训练算法调优算法融合 算法评估持续调优工程化接口实现
机器学习定义 关于机器学习的定义Tom Michael Mitchell的这段话被广泛引用 对于某类任务T和性能度量P如果一个计算机程序在T上其性能P随着经验E而自我完善那么我们称这个计算机程序从经验E中学习。 图像数据
pip list
PIL模块
Image模块
PIL提供了大量常用的、基本的图像操作方法。本节将介绍几个图像处理中非常重要的模块。 1Image模块 Image模块中定义的Image类是PIL类库中最重要的类实现了图像文件的读写、显示、颜色空间转换等方法。 Image类的open()方法接收图像文件路径为参数用于读取图像文件。如果载入文件失败则会引起一个IOError载入成功则返回一个Image对象。例如读取当前目录下文件名为“python.png”的图像
#导入PIL类库中的Image模块
from PIL import Image
#加载图像数据到Image对象Image对象的open()方法可以根据文件扩展名判断图像的格式
imImage.open(python.png)# 利用Image对象的属性打印输出图像的类型、大小和模式
print(im.format, im.size, im.mode)
# JPEG (256, 256) RGB
# PNG (369, 379) RGB这里有三个属性format识别图像的源格式如果该文件不是从文件中读取的则被置为 None 值size是有两个元素的元组其值为像素意义上的宽和高mode表示颜色空间模式定义了图像的类型和像素的位宽。 PIL支持如下模式 11位像素表示黑和白但是存储的时候每个像素存储为8bit。 L8位像素对应灰度图像可以表示256级灰度。 P8位像素使用调色板映射到其他模式。 RGB3x8位像素为真彩色。 RGBA4x8位像素有透明通道的真彩色。 CMYK4x8位像素颜色分离。 YCbCr3x8位像素彩色视频格式。 I32位整型像素。 F32位浮点型像素。 PIL也支持一些特殊的模式包括RGBX有padding的真彩色和RGBa有自左乘alpha的真彩色。上述print语句的输出结果表示python.jpg文件对应的图像格式为JPEG宽和高均为256颜色模式为RGB的彩色图像。 读取的图像数据可以利用Image对象的show()方法进行显示
im.show()
# 标准版本的show()方法不是很有效率
# 因为Linux系统下它先将图像保存为一个临时文件然后使用xv进行显示。
# 如果没有安装xv该函数甚至不能工作。Windows系统下该方法调用默认图片查看器打开图像。输出为
# 图像颜色空间转换可以使用convert()方法来实现例如将读取的im数据转换为灰度图像
im_grayim.convert(L)
im_gray.show()输出为
# 图像数据的保存使用save()方法
#将im_gray保存为png图像文件文件名为python_gray.png
im_gray.save(python_gray.png)#Image对象的crop()方法可以从一副图像中裁剪指定的矩形区域它接收包含四个元素的元组作为参数
#各元素的值分别对应裁剪区域在原图像中的左上角和右下角位置的坐标坐标系统的原点0, 0在图像的左上角
#使用四元组(左上右下)指定裁剪区域
box (10, 10, 300, 300)
#裁剪图像区域
region im.crop(box)
#保存裁剪的图像区域数据到图像文件
region.save(python_region.png)
region.show()输出为
#Image对象的transpose()方法通过传入参数Image.ROTATE_##代表旋转的角度可以是90°、180°、270°可以将图像数据进行旋转
#也可以传入参数Image.FLIP_LEFT_RIGHT将图像做水平翻转传入参数Image.FLIP_TOP_BOTTOM做垂直翻转等
#将图像数据region旋转90°
region_90 region.transpose(Image.ROTATE_90)
region_90.save(region_90.png) #保存图像
region_90.show()输出为
# Image对象的rotate ()方法可以将图像数据进行任意角度的旋转
#将图像数据region逆时针旋转30°
region_30 region.rotate(30)
region_30.save(region_30.png) #保存图像
region_30.show()输出为
需要注意的粘贴的图像数据必须与粘贴区域具有相同的大小但是它们的颜色模式可以不同 paste()方法在粘贴之前自动将粘贴的图像数据转换为与被粘贴图像相同的颜色模式。 读者可以通过将从灰度图像裁剪的区域粘贴在彩色图像或者将从彩色图像裁剪的区域粘贴在灰度图像进行验证。
# Image对象的paste ()方法可以为图像对象在特定位置粘贴图像数据
#创建图像对象im的拷贝
im_pasteim
#将region_90贴在图像对象im_paste中box对应的位置
im_paste.paste(region_90, box)
im_paste.show() #显示图像
im_paste.save(python_region_90_paste.png) #保存图像输出为
PIL可以对多波段图像的每个波段分别处理。 Image对象的getbands()方法可以获得每个波段的名称split()方法将多波段图像分解为多个单波段图像merge()方法可以按照用户指定的颜色模式和单波段图像数据的顺序将它们组合成新的图像。
#需要注意的粘贴的图像数据必须与粘贴区域具有相同的大小
#但是它们的颜色模式可以不同
#paste()方法在粘贴之前自动将粘贴的图像数据转换为与被粘贴图像相同的颜色模式。
#读者可以通过将从灰度图像裁剪的区域粘贴在彩色图像或者将从彩色图像裁剪的区域粘贴在灰度图像进行验证。
#PIL可以对多波段图像的每个波段分别处理。
#Image对象的getbands()方法可以获得每个波段的名称
#split()方法将多波段图像分解为多个单波段图像
#merge()方法可以按照用户指定的颜色模式和单波段图像数据的顺序将它们组合成新的图像
#显示每个波段的名称
print(im.getbands())
# (R, G, B)
#将RGB彩色图像对象im分解为三个单波段图像红、绿、蓝
r, g, b im.split()
#显示每个波段图像
r.show(titler)
# g.show(titleg)
# b.show(titleb)
输出为
#按照RGB颜色模式并将波段按蓝、绿、红顺序组合生成新的图像
im_bgr Image.merge(RGB, (b, g, r))
im_bgr.show(titleBGR)输出为
#Image对象的point()方法用于对图像每个像素的值进行数值运算由此可以完成图像反色、线性拉伸、归一化等。
from PIL import Image
im_grayImage.open(python_gray.png)
#将图像数据im_gray进行反色处理
im_gray_inv im_gray.point(lambda i: 255-i)
im_gray_inv.save(im_gray_inv.png) #保存图像
im_gray_inv.show()输出为
#图像的直方图用来表征该图像的像素值的分布情况。
#Image对象的histogram()方法将像素值的范围分成一定数目的小区间统计落入每个小区间的像素值数目。
#以下代码可以生成一副图像的直方图
from PIL import Image
from pylab import *
imImage.open(lena.png)
im.show()输出为
imin im.convert(L)
im_histimin.histogram() #获得直方图数据
plot(im_hist)输出为
# 利用PIL模块我们可以调用Image对象的resize()方法调整一副图像的大小
#该方法接受一个表示新图像大小的元组为参数返回原图像缩放后的拷贝
im_half im.resize((128, 128)) #将im调整为宽和高均为128像素
im_half.show()
# resize()方法中指定的图像宽度和高度也可以不一致
#新图像的宽度或高度可以比原图像的大对应图像放大也可以比原图像的小对应图像缩小。
#给一张特别小的图像当放大该图像时通常会出现马赛克我们希望把细节填充进来。
#resize()方法也可以指定两个参数resize(size, filter)
#其中filter
#Image.Resampling.NEAREST (0), Image.Resampling.LANCZOS (1), Image.Resampling.BILINEAR (2),
# Image.Resampling.BICUBIC (3), Image.Resampling.BOX (4) or Image.Resampling.HAMMING (5)。输出为
#将im调整为宽和高均为128像素
im_four im_half.resize((1280, 1280),Image.Resampling.BILINEAR)
im_four.show()输出为
ImageFilter模块
PIL提供的ImageFilter模块包含一组预先定义的滤波器可以结合Image对象的filter()方法实现图像平滑和增强。 目前该模块支持BLUR、CONTOUR、DETAIL、EDGE_ENHANCE、EDGE_ENHANCE_MORE、EMBOSS、FIND_EDGES、SMOOTH、SMOOTH_MORE、SHARPEN、GaussianBlur、RankFilter等。
from PIL import Image
from PIL import ImageFilter
boat Image.open(lena.png)
boat_blur boat.filter(ImageFilter.BLUR) #模糊滤波
boat_blur.save(boat_blur.png)
boat_blur.show()输出为
boat_edge boat.filter(ImageFilter.FIND_EDGES) #边缘检测
boat_edge.save(boat_edge.png)
boat_edge.show()输出为
boat_contour boat.filter(ImageFilter.CONTOUR) #找轮廓
boat_contour.save(boat_contour.png)
boat_contour.show()输出为
boat_rank boat.filter(ImageFilter.RankFilter(9,3))
boat_rank.save(boat_rank.png) #每个像素取值为它的3*3邻域中第三大的像素值
boat_rank.show()输出为
ImageEnhance模块
PIL中更高级的图像增强可以借助ImageEnhance模块完成例如 ImageEnhance.Contrast()用于调整对比度 ImageEnhance.Sharpness()用于图像锐化 ImageEnhance.Color()用于图像颜色均衡 ImageEnhance.Brightness()用于调整图像亮度等等。
from PIL import Image,ImageEnhance
imImage.open(lena.png)
# ImageEnhance.Contrast()用于调整对比度
im_contrast ImageEnhance.Contrast(im)
im_contrast.enhance(0.3).show()输出为
for i in [0.3,1.5,3]:tempim_contrast.enhance(i)temp.save(boat_enhancestr(i).png)temp.show()# ImageEnhance.Sharpness()用于图像锐化
imImage.open(lena.png)
im_Sharpness ImageEnhance.Sharpness(im)
im_Sharpness.enhance(0.3).show()输出为
Numpy图像数据分析示例
PIL提供了大量基本的图像处理模块和方法但当我们需要完成一些高级图像处理任务或者自定义一组图像处理流程时还需要借助于其他模块。首先可以考虑的就是提供了向量、矩阵、方程组等操作方法的Numpy。 PIL模块读取的图像数据不能直接与整型、浮点型等数据类型进行运算我们可以通过array()方法将图像数据转换成Numpy的数组对象之后利用Numpy执行任意数学操作完成一些复杂的图像处理流程。Numpy处理后的数据想要调用PIL提供的方法时再利用Image对象的fromarray()方法创建图像实例。
from PIL import Image
from numpy import *
import numpy as np
boatarray(Image.open(lena.png))
#对图像像素值进行二次多项式变换
boat_new255.0*(boat/255.0)**2
#由boat_new创建图像实例
im_boat_newImage.fromarray(np.uint8(boat_new))
#调研Image对象的show()方法显示图像
im_boat_new.show()输出为
import matplotlib.pylab as pltimage plt.imread(lena.png)
plt.imshow(image)
# 依次表示数组的维度形状数组本身
print(image.ndim, image.shape, \n,image[0:1])
plt.show()输出为
# 裁剪图像
# 加载图像后我们可以对图像执行基本的裁剪操作。对于 NumPy可以通过数组的切片操作来执行裁剪操作。
import matplotlib.pylab as plt
image plt.imread(lena.png)
# 只是一个:表示这个维度保持不变410: 表示从0~1280这个轴的index410 处切一刀
crop_img image[:, 410:, :]
print(image.shape, crop_img.shape)
plt.imshow(crop_img)
plt.show()输出为
# 分离颜色# 因为我们知道每个图像都是由像素值组成的这些像素值代表三个整数或小数称为其颜色的 RGB 值。
# 为了将这些颜色的图像分开我们需要拉出图像数组的正确切片。import numpy as np
import matplotlib.pylab as pltimage plt.imread(lena.png)
# 使用plot创建一个1行3列的尺寸为(12,8)的绘图区相当每个是6英寸宽4英寸高。
fig, axs plt.subplots(nrows1, ncols3, figsize(12, 8))
for c, ax in zip(range(3), axs):# 造一个与image数组一样结构初始值为0的数组# 如果你图片数据值是0~255,类型设为unit8,如果是0~1,设置为float64rgb_img np.zeros(image.shape, dtypefloat64)# 读取image某一通道的值# RGB只拷贝C位按循环依次取值为0,1,2rgb_img[:, :, c] image[:, :, c]ax.imshow(rgb_img)ax.set_axis_off()
plt.show()输出为
# 转换# 在此步骤中我们将执行颜色转换。为此我们可以将图像像素视为空间中的一个点。以这种方式处理图像像素使我们能够对色点进行转换。
# 旋转色点可以是上述语句的一个例子。
# 在这里我们应用了 Numpy 的爱因斯坦符号函数这是一种将旋转矩阵逐像素应用于图像的方法。
import numpy as np
import matplotlib.pylab as pltdef rotation_matrix(theta):return np.c_[[1, 0, 0],[0, np.cos(theta), -np.sin(theta)],[0, np.sin(theta), np.cos(theta)]]image plt.imread(lena.png)
img_rot np.einsum(ijk,lk-ijl, image, rotation_matrix(np.pi*0.5))
plt.imshow(img_rot)
plt.show()输出为
NumPy 中的 np.einsum 函数是一个强大的工具它允许我们使用爱因斯坦求和约定来表达矩阵的乘法和其他数学操作。在 NumPy 中爱因斯坦求和约定是通过简化多个索引的重复来简化张量的操作。 在 np.einsum 的调用 ijk,lk-ijl 中我们有以下含义
ijk 表示输入张量 image 的维度其中 i、j 和 k 是索引分别代表图像的高度、宽度和颜色通道数。lk 表示第二个操作数 rotation_matrix(np.pi) 的维度其中 l 和 k 是索引l 代表旋转矩阵的行数这里是 3k 代表旋转矩阵的列数这里是 3。ijl 表示输出张量的维度其中 i 和 j 与输入图像的 ijk 相同代表旋转后图像的高度和宽度而 l 代表旋转矩阵的行数这里是 3因为输出图像的颜色通道数与输入图像相同。 因此np.einsum(ijk,lk-ijl, image, rotation_matrix(np.pi*2)) 这行代码的意义是将 image 中的每个像素由 ijk 索引与一个旋转矩阵由 lk 索引相乘并生成一个新的图像其中每个像素的颜色值是通过应用旋转矩阵得到的。这个操作在图像处理中称为像素级的矩阵乘法它对应于图像的每个像素点在旋转后的空间位置上的颜色值。 简而言之这段代码将每个像素的颜色值乘以一个旋转矩阵从而实现图像的旋转效果。
# 灰度转换# 我们还可以使用 NumPy 将图像转换为灰度图像。通过取图像RGB值的加权平均值我们可以执行此操作。
# 灰度值 0.2989 * R 0.5870 * G 0.1140 * Bimport numpy as np
import matplotlib.pylab as plt
fig,ax plt.subplots(1,2)image plt.imread(lena.png)
# plt.imshow(image)
rgb_weights [0.1140, 0.5870,0.2989]
# image.shape # (759, 753, 3)
# 0.0876 0.22 0.10
# print(image[0:10])
grayscale_image np.dot(image[..., :3], rgb_weights)
print(grayscale_image.shape)
print(grayscale_image[0:10])ax[0].imshow(grayscale_image,cmapGreys)
ax[1].imshow(grayscale_image)
plt.show()输出为
修改下权重系数
# 灰度转换# 我们还可以使用 NumPy 将图像转换为灰度图像。通过取图像RGB值的加权平均值我们可以执行此操作。
# 灰度值 0.2989 * R 0.5870 * G 0.1140 * Bimport numpy as np
import matplotlib.pylab as plt
fig,ax plt.subplots(1,2)image plt.imread(lena.png)
# plt.imshow(image)
rgb_weights [0.2989, 0.5870,0.1140]
# image.shape # (759, 753, 3)
# 0.0876 0.22 0.10
# print(image[0:10])
grayscale_image np.dot(image[..., :3], rgb_weights)
print(grayscale_image.shape)
print(grayscale_image[0:10])ax[0].imshow(grayscale_image,cmapGreys)
ax[1].imshow(grayscale_image)
plt.show()输出为 # 图像分割# 这是我们分割图像不同区域的最常用的图像处理步骤之一。
#有多种方法可以做到这一点例如前景和背景。
#例如在本文中我们将了解如何通过将图像转换为灰度并找到阈值来执行分割。
# 图像中高于阈值的像素位于一个区域中而其他像素位于另一个区域中import numpy as np
import matplotlib.pylab as pltimage plt.imread(lena.png)
image image*255def simple_threshold(img, threshold128):return ((img threshold) * 255).astype(uint8)thresholds [100, 120, 128, 138, 150]fig, axs plt.subplots(nrows1, ncolslen(thresholds), figsize(20, 5))rgb_weights [0.2989, 0.5870, 0.1140]
gray_im np.dot(image[..., :3], rgb_weights)# gray_im to_grayscale(image)for t, ax in zip(thresholds, axs):ax.imshow(simple_threshold(gray_im, t), cmapGreys)ax.set_title(Threshold: {}.format(t), fontsize20)ax.set_axis_off()
plt.show()
输出为
OpenCV
OpenCV 的全称是 Open Source Computer Vision Library 是一个跨平台的计算机视觉库。OpenCV 是由英特尔公司发起并参与开发 以 BSD 许可证授权发行 可以在商业和研究领域中免费使用。 OpenCV 可用于开发实时的图像处理、 计算机视觉以及模式识别程序。 该程序库也可以使用英特尔公司的 IPP 进行加速处理。
# pip install opencv-python4.9.0.80一、图像处理基础知识
1、读取、显示、保存图像
img cv2.imread(文件名,[,参数])其中参数 参数(1) cv2.IMREAD_UNCHANGED (图像不可变) 参数(2) cv2.IMREAD_GRAYSCALE (灰度图像) 参数(3) cv2.IMREAD_COLOR (读入彩色图像)这是默认参数不填的话默认为这个 参数(4) cv2.COLOR_BGR2RGB (图像通道BGR转成RGB)
综合实例
# 1读取照片OpenCV读取图像# 导包
import cv2
# 读取照片
img cv2.imread(lena.png) # 路径中不能有中文
# 显示图片
cv2.imshow(read_img, img)
# 输入毫秒值传0就是无限等待
cv2.waitKey(3000)
# 释放内存,由于OpenCV底层是C写的
cv2.destroyAllWindows()输出为
# 3OpenCV画图对图片进行编辑
# OpenCV 的强大之处的一个体现就是其可以对图片进行任意编辑处理。下面的这个函数最后一个参数指定的就是画笔的大小。OpenCV画图对图片进行编辑# 导包
import cv2
img cv2.imread(lena.png)
# 左上角的坐标是(x,y),矩形的宽度和高度是(w,h)
x, y, w, h 100, 100, 100, 100
# 绘制矩形
cv2.rectangle(img, (x, y, x w, y h), color(255, 0, 0), thickness2)
# 绘制圆
x, y, r 200, 200, 100
cv2.circle(img, center(x, y), radiusr, color(255, 0, 0), thickness2)
# 显示图片
cv2.imshow(rectangle_img, img)
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
2、获取图像属性
2.1形状- img.shape 通过shape关键字获取图像的形状返回包含行数、列数、通道数的元祖。其中 1灰度图像返回行数和列数 2彩色图像返回行数、列数 和 通道数。
2.2像素数目- img.size 通过size关键字获取图像的像素数目其中
1灰度图像返回 [行数 * 列数] 2彩色图像返回 [行数 * 列数 * 通道数] 。 2.3图像类型- img.dtype 通过 dtype 关键字获取图像的数据类型通常返回uint8。 通过像素矩阵可以直接获取ROI区域如img[200:400, 200:400]。
3、图像的通道拆分与合并
3.1 通道拆分- split()
OpenCV读取的彩色图像由B、G、R三原色组成可以通过下面代码获取不同的通道。
方法一
# -*- coding:utf-8 -*-
b img[:, :, 0]
g img[:, :, 1]
r img[:, :, 2]import cv2
import numpy as np# 读取图片
img cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)# 拆分通道
b, g, r cv2.split(img)# 显示原始图像
cv2.imshow(B, b)
cv2.imshow(G, g)
cv2.imshow(R, r)# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()
#注意不要点击显示图像窗口右上角的X关闭那样会导致图片关闭了程序还在运行。
#直接按任意键就可输出为
3.2 通道合并- merge()
图像通道合并主要使用 merge() 函数实现。例如
m cv2.merge([b, g, r])# -*- coding:utf-8 -*-
import cv2
import numpy as np# 读取图片
img cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)# 拆分通道
b, g, r cv2.split(img)# 合并通道
m cv2.merge([b, g, r])
cv2.imshow(Merge, m)# 等待显示
cv2.waitKey(3000)
cv2.destroyAllWindows()输出为
4、图像加法与融合运算 和 图像类型转换
4.1图像加法运算 1使用Numpy 2使用OpenCV—add() 对比试验
1 两个彩色图像相加 代码如下所示
# encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图片
img cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)
# img cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #取消注释就为转换为灰度图
# result
img cv2.resize(img, None, fx0.5, fy0.5) # 缩放
test img # 方法一Numpy加法运算
result1 img test# 方法二OpenCV加法运算
result2 cv2.add(img, test)# 显示图像
cv2.imshow(original, img)
cv2.imshow(result1_Numpy, result1)
cv2.imshow(result2_OpenCv, result2)# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
灰度图加法
4.2图像融合运算- addWeighted()
图像融合通常是指将2张或2张以上的图像信息融合到1张图像上融合的图像含有更多的信息能够更方便人们观察或计算机处理。如下图所示将两张不清晰的图像融合得到更清晰的图。 主要调用的函数是 addWeighted() 函数方法如下
dst cv2.addWeighter(scr1, alpha, src2, beta, gamma)
dst src1*alpha src2*beta gamma其中参数gamma不能省略。 注两张融合的图像像素大小需要一致
# encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图片
src1 cv2.imread(lena.png)
src2 cv2.imread(shuji.jpg)src1 cv2.resize(src1, None, fx0.5, fy0.5) # 缩放
src2 cv2.resize(src2, (src1.shape[1],src1.shape[0]), interpolationcv2.INTER_LINEAR) # 缩放print(type(src1),type(src2))
print(src1.shape,src2.shape)
# # 图像融合
result cv2.addWeighted(src1, 1, src2, 1, 0)# 显示图像
cv2.imshow(src1, src1)
cv2.imshow(src2, src2)
cv2.imshow(result, result)# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
1设置参数1
# 图像融合
# result cv2.addWeighted(src1, 1, src2, 1, 0)
result cv2.addWeighted(src1, 0.8, src2, 0.2, 10)运行结果如下
2设置参数2
# 图像融合
# result cv2.addWeighted(src1, 1, src2, 1, 0)
#result cv2.addWeighted(src1, 0.8, src2, 0.2, 10)
result cv2.addWeighted(src1, 0.2, src2, 0.8, 10)运行结果如下 4.3图像类型转换- cvtColor() 图像类型转换是指将一种类型转换为另一种类型比如彩色图像转换为灰度图像、BGR图像转换为RGB图像。OPenCV提供了200多种不同类型之间的转换其中最常用的包括3类如下
result cv2.cvtColor(图像, 参数) 其中参数有以下三种 cv2.COLOR_BGR2GRAY #彩色转灰度 类似于Matlab 中的 rgb2gray() cv2.COLOR_BGR2RGB cv2.COLOR_GRAY2BGR 图片灰度转换 OpenCV 中有数百种关于在不同色彩空间之间转换的方法。 当前 在计算机视觉中有三种常用的色彩空间灰度、BGR以及 HSVHue Saturation Value。 灰度转换的作用就是 转换成灰度的图片的计算强度得以降低。 灰度色彩空间是通过去除彩色信息来将其转换成灰阶 灰度色彩空间对中间处理特别有效 比如人脸识别。 BGR 及蓝、 绿、 红色彩空间 每一个像素点都由一个三元数组来表示 分别代表蓝、 绿、 红三种颜色。 网页开发者可能熟悉另一个与之相似的颜色空间 RGB 它们只是颜色顺序上不同。 HSV HHue 是色调 SSaturation 是饱和度 VValue 表示黑暗的程度或光谱另一端的明亮程度。 OpenCV图片灰度转换 OpenCV进行灰度转换import cv2
img cv2.imread(lena.png)
cv2.imshow(BGR_IMG, img)
# 将图片转化为灰度
gray_img cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 展示图片
cv2.imshow(gray_img, gray_img)
# 设置展示时间
cv2.waitKey(3000)
# 保存图片
cv2.imwrite(./gray_lena.jpg, gray_img)
# 释放内存
cv2.destroyAllWindows()输出为
BRG通道转RGB通道
代码如下 OpenCV进行BGR2RGBimport cv2
img cv2.imread(lena.png)
cv2.imshow(BGR_IMG, img)
# 将图片转化为灰度
rgb_img cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 展示图片
cv2.imshow(BGR_img, img)
cv2.imshow(rgb_img, rgb_img)
# 设置展示时间
cv2.waitKey(5000)
# 保存图片
# cv2.imwrite(./rgb_lena.jpg, rgb_img)
# 释放内存
cv2.destroyAllWindows()输出为
5、图像缩放、图像旋转、图像翻转 和 图像平移
5.1图像缩放- resize() 图像缩放主要调用 resize() 函数实现具体如下
result cv2.resize(src, dsize[, result[. fx[, fy[, interpolation]]]])其中参数
src 表示原始图像
dsize 表示缩放大小
fx和fy 也可以表示缩放大小倍数他们两个dsize或fx/fy设置一个即可实现图像缩放。例如
1result cv2.resize(src, (160,160))
2result cv2.resize(src, None, fx0.5, fy0.5)1 cv2.resize(src, (200,100)) 设置的dsize是列数为200行数为100
result cv2.resize(src, (200,100))代码如下
import cv2
import numpy as np# 读取图片
src cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)# 图像缩放
# cv2.resize(src, (200,100)) 设置的dsize是列数为200行数为100
result cv2.resize(src, (200,100))
print (result.shape)# 显示图像
cv2.imshow(src, src)
cv2.imshow(result, result)# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
2可以获取 原始图像像素\times乘以缩放系数 进行图像变换
result cv2.resize(src, (int(cols * 0.6), int(rows * 1.2)))代码如下所示
import cv2
import numpy as np# 读取图片
src cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)
rows, cols src.shape[:2]
print(rows, cols)# 图像缩放 dsize(列,行)
result cv2.resize(src, (int(cols * 0.6), int(rows * 1.2)))# 显示图像
cv2.imshow(src, src)
cv2.imshow(result, result)# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
3(fx,fy) 缩放倍数的方法对图像进行放大或缩小。
result cv2.resize(src, None, fx0.3, fy0.3)代码如下所示
# encoding:utf-8
import cv2
import numpy as np# 读取图片
src cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)
rows, cols src.shape[:2]
print(rows, cols)# 图像缩放
result cv2.resize(src, None, fx0.3, fy0.3)# 显示图像
cv2.imshow(src, src)
cv2.imshow(result, result)# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()输出为 5.2 图像旋转- getRotationMatrix2D(), warpAffine() 图像旋转主要调用getRotationMatrix2D() 函数和 warpAffine() 函数实现绕图像的中心旋转具体如下
M cv2.getRotationMatrix2D((cols/2, rows/2), 30, 1)其中参数分别为旋转中心、旋转度数、scale缩放比例
rotated cv2.warpAffine(src, M, (cols, rows))其中参数分别为原始图像、旋转参数 和 原始图像宽高
1旋转30度
代码如下
import cv2
import numpy as np# 读取图片
src cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)# 原图的高、宽 以及通道数
rows, cols, channel src.shape# 绕图像的中心旋转
# 参数旋转中心 旋转度数 scale
M cv2.getRotationMatrix2D((cols / 2, rows / 2), 30, 1)
# M cv2.getRotationMatrix2D((cols / 2, rows / 2), 90, 1)
# 参数原始图像 旋转参数 元素图像宽高
rotated cv2.warpAffine(src, M, (cols, rows))# 显示图像
cv2.imshow(src, src)
cv2.imshow(rotated, rotated)
# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
5.3 图像翻转- flip()
图像翻转在OpenCV中调用函数 flip() 实现函数用法如下
dst cv2.flip(src, flipCode)其中参数
src 表示原始图像
flipCode 表示翻转方向如果flipCode为0则以X轴为对称轴翻转如果fliipCode0则以Y轴为对称轴翻转如果flipCode0则在X轴、Y轴方向同时翻转。代码如下注意一个窗口多张图像的用法
import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图片
img cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)
src cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 图像翻转
# 0以X轴为对称轴翻转 0以Y轴为对称轴翻转 0X轴Y轴翻转
img1 cv2.flip(src, 0)
img2 cv2.flip(src, 1)
img3 cv2.flip(src, -1)# 显示图形 注意一个窗口多张图像的用法
titles [Source, Image1, Image2, Image3]
images [src, img1, img2, img3]
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()# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
5.4 图像平移- warpAffine() 图像平移首先定义平移矩阵M再调用 warpAffine() 函数实现平移函数用法如下
M np.float32([[1, 0, x], [0, 1, y]])
shifted cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))代码如下
# encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图片
img cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)
image cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 图像平移 下、上、右、左平移
M np.float32([[1, 0, 0], [0, 1, 100]])
img1 cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))M np.float32([[1, 0, 0], [0, 1, -100]])
img2 cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))M np.float32([[1, 0, 100], [0, 1, 0]])
img3 cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))M np.float32([[1, 0, -100], [0, 1, 0]])
img4 cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))# 显示图形
titles [Image1, Image2, Image3, Image4]
images [img1, img2, img3, img4]
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()输出为
二、图像处理进阶
1、图像阈值化-threshold()
灰度转换处理后的图像中每个像素都只有一个灰度值其大小表示明暗程度。二值化处理可以将图像中的像素划分为两类颜色 其中当灰度Gray小于阈值T时其像素设置为0表示黑色 当灰度Gray大于或等于阈值T时其Y值为255表示白色。 Python OpenCV中提供了阈值函数 threshold() 实现二值化处理其函数形式及参数如下图所示
retval, dst cv2.threshold(src, thresh, maxval, type)其中参数
retval阈值
dst 处理结果
src,原图像
thresh阈值
maxval最大值
type类对应OpenCV提供的五张图如下所示第一张为原图后面依次为 二进制阈值化、反二进制阈值化、截断阈值化、反阈值化为0 和 阈值化为0 。 二值化处理广泛应用于各行各业比如生物学中的细胞图分割、交通领域的车牌设别等。在文化应用领域中通过二值化处理将所需民族文物图像转换为黑白两色图从而为后面的图像识别提供更好的支撑作用。下图表示图像经过各种二值化处理算法后的结果其中“BINARY”是最常见的黑白两色处理。
指定一个阈值thresh 1二进制阈值化–cv2.THRESH_BINARY 像素灰度值thresh设为最大灰度值如8位灰度值最大为255以下都以8位灰度图为例 像素灰度值thresh设为0 2反二进制阈值化–cv2.THRESH_BINARY_INV 与二进制阈值化相反thresh设为0 thresh设为255 3截断阈值化–cv2.THRESH_TRUNC 像素灰度值thresh设为thresh 像素灰度值thresh不变 4阈值化为0–cv2.THRESH_TOZERO 像素灰度值thresh不变 像素灰度值thresh设为0 5反阈值化为0–cv2.THRESH_TOZERO_INV 与阈值化为0正相反 thresh设为0 thresh不变 总代码
import cv2
import numpy as np
import matplotlib.pyplot as plt#读取图像
img cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)
lenna_img cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
GrayImagecv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#阈值化处理
ret,thresh1cv2.threshold(GrayImage,127,255,cv2.THRESH_BINARY)
ret,thresh2cv2.threshold(GrayImage,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3cv2.threshold(GrayImage,127,255,cv2.THRESH_TRUNC)
ret,thresh4cv2.threshold(GrayImage,127,255,cv2.THRESH_TOZERO)
ret,thresh5cv2.threshold(GrayImage,127,255,cv2.THRESH_TOZERO_INV)#显示结果
titles [Gray Image,BINARY,BINARY_INV,TRUNC,TOZERO,TOZERO_INV]
images [GrayImage, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):plt.subplot(2,3,i1),plt.imshow(images[i],gray)plt.title(titles[i])plt.xticks([]),plt.yticks([])
plt.show()输出为
2、图像平滑均值滤波、中值滤波、高斯滤波—空域滤波
图像增强是对图像进行处理使其比原始图像更适合于特定的应用它需要与实际应用相结合。对于图像的某些特征如边缘、轮廓、对比度等图像增强是进行强调或锐化以便于显示、观察或进一步分析与处理。图像增强主要是一个主观过程而图像复原大部分是一个客观过程。图像增强的方法是因应用不同而不同的研究内容包括
图像平滑是一种区域增强的算法平滑算法有邻域平均法、中指滤波、边界保持类滤波等。在图像产生、传输和复制过程中常常会因为多方面原因而被噪声干扰或出现数据丢失降低了图像的质量某一像素如果它与周围像素点相比有明显的不同则该点被噪声所感染。这就需要对图像进行一定的增强处理以减小这些缺陷带来的影响。 1均值滤波–cv2.blur(原始图像,核大小) 指任意一点的像素值都是周围 N * M 个像素值的均值 注 1随着核大小逐渐变大会让图像变得更加模糊 2如果设置为核大小为11则结果就是原始图像。 2中值滤波–cv2.medianBlur(src, ksize) 这里的核大小ksize必须是奇数 将该点周围的像素点包括本身按次序排列取中位数作为点的像素值 注 1随着核大小逐渐变大会让图像变得更加模糊 2核必须是大于1的奇数如3、5、7等 3在代码 dst cv2.medianBlur(src, ksize) 中 填写核大小时只需填写一个数即可如3、5、7等对比均值滤波函数用法。 3高斯滤波–cv2.GaussianBlur(src, ksize, sigmaX) 为了克服简单局部平均法的弊端(图像模糊)目前已提出许多保持边缘、细节的局部平滑算法。它们的出发点都集中在如何选择邻域的大小、形状和方向、参数加平均及邻域各店的权重系数等。 图像高斯平滑也是邻域平均的思想对图像进行平滑的一种方法在图像高斯平滑中对图像进行平均时不同位置的像素被赋予了不同的权重。高斯平滑与简单平滑不同它在对邻域内像素进行平均时给予不同位置的像素不同的权值下图的所示的 3x3 和 5x5 邻域的高斯模板。 生成椒盐噪声
# encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图片
image cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)#设置添加椒盐噪声的数目比例
s_vs_p 0.01
#设置添加噪声图像像素的数目
amount 0.01
noisy_img np.copy(image)
#添加salt噪声
num_salt np.ceil(amount * image.size * s_vs_p)
#设置添加噪声的坐标位置
coords [np.random.randint(0,i - 1, int(num_salt)) for i in image.shape]
noisy_img[coords[0],coords[1],:] [255,255,255]
#添加pepper噪声
# num_pepper np.ceil(amount * image.size * (1. - s_vs_p))
#设置添加噪声的坐标位置
# coords [np.random.randint(0,i - 1, int(num_pepper)) for i in image.shape]
# noisy_img[coords[0],coords[1],:] [0,0,0]
# 如果去掉上面注释可以添加更多噪声#保存图片
cv2.imwrite(noisy_lena.png,noisy_img)# 显示图像
cv2.imshow(noisy_lena, noisy_img)
# 等待显示
cv2.waitKey(5000)
cv2.destroyAllWindows()
输出为 去掉注释的更多噪声点
import cv2
import numpy as np
import matplotlib.pyplot as plt# 读取图片
img cv2.imread(lena.png)
noisy_img cv2.imread(noisy_lena.png)
source cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
noisy_img cv2.cvtColor(noisy_img, cv2.COLOR_BGR2RGB)# 高斯滤波
result cv2.GaussianBlur(noisy_img, (3, 3), 0) #可以更改核大小
# result cv2.cvtColor(result, cv2.COLOR_BGR2RGB)# 显示图形
titles [Source Image, noisy_img,GaussianBlur Image (3, 3)]
images [source, noisy_img,result]plt.figure(figsize(30,10),dpi300)
for i in range(3):plt.subplot(1, 3, i 1)plt.imshow(images[i], gray)plt.title(titles[i])plt.xticks([]), plt.yticks([])
plt.show()输出为 注 1随着核大小逐渐变大会让图像变得更加模糊 2核大小N, N必须是大于1的奇数如3、5、7等 3、形态学处理–腐蚀、膨胀、开运算、闭运算、顶帽运算、黑帽运算
形态学运算主要针对的二值图像 1腐蚀 卷积核中心逐个遍历图像像素当卷积核范围内全是原图像时不改变原像素值当卷积核范围内有除了原图像以外的区域时将此范围内的原图像像素值置为0即腐蚀这个像素点。 2膨胀 卷积核中心逐个遍历图像像素当卷积核范围内有一个原图像的像素点时将卷积核范围内设为1即将该像素点膨胀为卷积核大小的区域 3开运算–先腐蚀再膨胀 开运算一般会平滑物体的轮廓、断开较窄的狭颈并消除细的突出物。 4闭运算–先膨胀再腐蚀 闭运算同样也会平滑轮廓的一部分。但与开操作相反它通常会弥合较窄的间断和细长的沟壑消除小的孔洞填补轮廓线中的断裂。 5顶帽运算–原始减去开运算 6黑帽运算–闭运算减去原始 总结 腐蚀cv2.erode(src, kernel, iterations) #iterations表示腐蚀几次 膨胀cv2.dilate(src, kernel, iterations) 开运算cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel) 闭运算cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel) import cv2
import numpy as np#读取图片
src cv2.imread(lena.png, cv2.IMREAD_UNCHANGED)srccv2.cvtColor(src,cv2.COLOR_BGR2GRAY)#阈值化处理 ret为127 为二值化的结果
ret,src_1cv2.threshold(src,127,255,cv2.THRESH_BINARY)#设置卷积核
kernel np.ones((7,7), np.uint8)
# kernel cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))形态学6种操作#腐蚀
fushi cv2.erode(src_1, kernel)
#膨胀
pengzhang cv2.dilate(src_1, kernel)
#开运算
kai cv2.morphologyEx(src_1, cv2.MORPH_OPEN, kernel)
#闭运算
bi cv2.morphologyEx(src_1, cv2.MORPH_CLOSE, kernel)
#顶帽运算
tophat cv2.morphologyEx(src_1, cv2.MORPH_TOPHAT, kernel)
#黑帽运算
blackhat cv2.morphologyEx(src_1, cv2.MORPH_BLACKHAT, kernel)# 显示图形
titles [Source Image,threshold Image, fushi,pengzhang,kai,bi,tophat,blackhat]
images [src,src_1, fushi,pengzhang,kai,bi,tophat,blackhat]plt.figure(figsize(20,10),dpi300)
for i in range(8):plt.subplot(2, 4, i 1)plt.imshow(images[i], gray)plt.title(titles[i])plt.xticks([])plt.yticks([])
plt.show()输出为
卷积核的设置 1用numpy生成 np.ones((3,3), np.uint8) #一般用这个也够了 np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]) 2用opencv自带函数–getStructuringElement element cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5)) #十字型 element cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) #矩形 element cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) #椭圆形 4、灰度直方图
4.1 绘制灰度直方图 1matplotlib—hist()函数 使用matplotlib的子库pyplot实现它提供了类似于Matlab的绘图框架matplotlib是非常强大基础的一个Python绘图包。其中绘制直方图主要调用 hist() 函数实现它根据数据源和像素级绘制直方图。 hist()函数形式如下 hist(数据源, 像素级)其中参数
数据源必须是一维数组通常需要通过函数 ravel() 拉直图像
像素级一般是256表示[0, 255]
函数 ravel() 将多维数组降为一维数组其格式为
一维数组 多维数组.ravel()import cv2
import numpy as np
import matplotlib.pyplot as pltsrc cv2.imread(lena.png)
cv2.imshow(src, src)plt.hist(src.ravel(), 256)
plt.show()cv2.waitKey(0)
cv2.destroyAllWindows()输出为 2 opencv----calcHist()函数 使用OpenCV库 中的 calcHist() 函数 计算B、G、R通道的灰度级并绘制图形 hist cv2.calcHist(images, channels, mask, histSize, ranges, accumulate)其中参数hist 表示直方图返回的是一个二维数组images 表示原始图像channels 表示指定通道通道编号需要用中括号括起输入图像是灰度图像时它的值为[0]彩色图像则为[0]、[1]、[2]分别表示B、G、Rmask 表示掩码图像统计整副图像的直方图设为None统计图像的某一部分直方图时需要掩码图像histSize 表示BINS的数量参数子集的数目bins3表示三个灰度级ranges 表示像素值范围例如[0, 255]accumulate 表示累计叠加标识默认为false如果被设置为true则直方图在开始分配时不会被清零该参数允许从多个对象中计算单个直方图或者用于实时更新直方图多个直方图的累积结果用于对一组图像的直方图计算。import cv2
import numpy as np
import matplotlib.pyplot as pltsrc cv2.imread(lena.png)cv2.imshow(src, src)histb cv2.calcHist([src], [0], None, [256], [0,255]) #掩摸处理求的是掩摸区域的直方图
histg cv2.calcHist([src], [1], None, [256], [0,255]) #不做掩膜处理直接求整幅图G分量灰度图的直方图
histr cv2.calcHist([src], [2], None, [256], [0,255])
# print(histr)plt.plot(histb, colorb)
plt.plot(histg, colorg)
plt.plot(histr, colorr)
plt.show()cv2.waitKey(0)
cv2.destroyAllWindows()输出为
调整亮度和对比度 代码如下
import cv2
import numpy as np
import matplotlib.pyplot as pltsrc_old cv2.imread(lena.png)
cv2.imshow(src_old, src_old)#定义alpha和beta
alpha 1.5 #对比度控制
beta 10 #亮度控制#调用convertScaleAbs函数
src cv2.convertScaleAbs(src_old, alphaalpha, betabeta)
cv2.imshow(src, src)histb cv2.calcHist([src], [0], None, [256], [0,255]) #掩摸处理求的是掩摸区域的直方图
histg cv2.calcHist([src], [1], None, [256], [0,255]) #不做掩膜处理直接求整幅图G分量灰度图的直方图
histr cv2.calcHist([src], [2], None, [256], [0,255])
# print(histr)plt.plot(histb, colorb)
plt.plot(histg, colorg)
plt.plot(histr, colorr)
plt.show()cv2.waitKey(0)
cv2.destroyAllWindows()输出为:
4.2直方图均衡化-equalizeHist() (1) 直方图均衡化概念 直方图均衡化 (Histogram Equalization) 就是把一个已知灰度概率密度分布的图像经过一种变换使之演变为一幅具有均匀灰度概率密度分布的新图像。 如下图所示过暗和过亮的图像 经过直方图均衡化使得图像变得清晰。 直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸重新分配图像像素值使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。 2直方图均衡化的理论基础 前提如果一幅图像占有全部可能的灰度级并且均匀分布。 结论该图像具有高对比度和多变的灰色色调。 外观图像细节丰富质量更高。 3直方图均衡化的步骤 a计算累计直方图 b将累计直方图进行区间转换 c在累计直方图中概率相近的原始值会被处理为相同的值。 具体的例子如下 如下图所示已知一幅图像的像素分布为 7*7根据像素值则可以计算出统计直方图 根据统计直方图可以算出归一化直方图(即纵坐标转换为概率)和累计直方图如下图所示 将累计直方图进行区间转换如下图所示 由上图的结果可知原先8个灰度级转变成6个灰度级那么原始直方图和均衡直方图为 上面的灰度级是8那灰度级转变成256计算方法类似如下图所示 由上图可以看出虽然二者相似但右侧均衡化后的直方图分布更均匀相邻像素级概率和与高概率近似相等。如果将两张图的灰度级放在同一区间可以看出差别更大如下图所示 4直方图均衡化应用场景 a医学图像处理 b车牌照识别 c人脸识别 5函数实现-equalizeHist() OpenCV库下直方图均衡化使用 equalizeHist() 函数函数用法如下所示: dstcv2.equalizeHist(src)其中参数dst 表示处理结果src 表示原始图像代码如下
#encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
img cv2.imread(lena.png, cv2.IMREAD_GRAYSCALE)
equ cv2.equalizeHist(img)cv2.imshow(src, img)
cv2.imshow(result, equ)plt.figure(figsize(20,8))
fig,ax plt.subplots(1,2)ax[0].hist(img.ravel(), 256)
ax[0].set_xlim(0,255)
# plt.figure()
ax[1].hist(equ.ravel(), 256)
ax[1].set_xlim(0,255)
plt.show()cv2.waitKey(0)
cv2.destroyAllWindows()输出为 matplotlib.pyplot.subplot() 函数 matplotlib.pyplot.subplot() 函数可以将多张图像放在一个窗口内Pyhton下需要导入 matplotlib.pyplot 绘图包其用法和Matlab中的subplot()函数用法类似。matplotlib 是一个强大的绘图包。subplot() 函数用法如下所示 代码如下
#encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
img cv2.imread(zxp.jpg, cv2.IMREAD_GRAYSCALE)
equ cv2.equalizeHist(img)plt.subplot(221),plt.imshow(img, gray),plt.title(img), plt.xticks([]),plt.yticks([])
plt.subplot(222),plt.imshow(equ, gray),plt.title(equ), plt.xticks([]),plt.yticks([])
plt.subplot(223),plt.hist(img.ravel(),256),plt.title(img_hist)
plt.subplot(224),plt.hist(equ.ravel(),256),plt.title(equ_hist)plt.show()cv2.waitKey(0)
cv2.destroyAllWindows()输出为
matplotlib.pyplot.imshow() 函数 imshow() 函数用法如下所示同样的Pyhton下需要导入 matplotlib.pyplot 绘图包。
imshow(X, cmapNone)其中参数
X 表示要绘制的图像
cmap 表示colormap颜色图谱默认为RGB(A)颜色空间1对于灰度图像使用参数 “ cmapplt.cm.gray ”2对于彩色图像如果使用opencv读入的图像默认空间为BRG需要调整色彩空间为RGB。下面是分别使用函数读取灰度图像和彩色图像例子。
1灰度图像
import cv2
import numpy as np
import matplotlib.pyplot as plt
img cv2.imread(lena.png)
img_gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)plt.subplot(221),plt.imshow(img),plt.title(img), plt.axis(off) #坐标轴关闭
plt.subplot(222),plt.imshow(img, cmapplt.cm.gray),plt.title(img_cmap), plt.axis(off)plt.subplot(223),plt.imshow(img_gray),plt.title(img_gray), plt.axis(off)
plt.subplot(224),plt.imshow(img_gray, cmapplt.cm.gray),plt.title(img_gray_cmap),plt.axis(off)#正确用法plt.show()cv2.waitKey(0)
cv2.destroyAllWindows()输出为
2彩色图像
代码如下所示
import cv2
import numpy as np
import matplotlib.pyplot as plt
img cv2.imread(lena.png)
b,g,rcv2.split(img) #通道分割
img_RGBcv2.merge([r,g,b])#通道组合plt.subplot(121),plt.imshow(img),plt.title(img_BGR), plt.axis(off) #坐标轴关闭
plt.subplot(122),plt.imshow(img_RGB),plt.title(img_RGB), plt.axis(off)输出为
5、频域滤波—高通滤波、低通滤波
频率域图像增强首先通过傅里叶变换将图像从空间域转换为频率域然后在频率域对图像进行处理最后通过傅里叶反变换转换到空间域。频率域内的图像增强包括低通滤波、高通滤波、同态滤波等等。 5.1 傅里叶变换 傅里叶变换 5.2 傅里叶变换的实现 1numpy实现 f numpy.fft.fft2(img) 实现傅里叶变换返回一个复数数组complex ndarray fshift numpy.fft.fftshift(f) : 将低频分量移到频谱中心傅里叶变换后的低频是在频谱左上角为了观看方便移到中心 以上得到的是复数没法显示为图像要显示为图像需要将复数转换为灰度值[0-255]范围就可以观察频谱图像了 注意 1傅里叶得到低频、高频信息针对低频、高频能够实现不同的目的 2傅里叶过程是可逆的图像经过傅里叶变换、逆傅里叶变换能够恢复到原始图像 3在频域对图像进行处理在频域的处理会反应在逆变换图像上 逆傅里叶变换的实现–从频谱图像恢复到原始图像 numpy.fft.ifft2() 实现逆傅里叶变换返回一个复数数组 numpy.fft.ifftshift() fftshift的逆函数将低频信息由中心移到左上角 iimg np.abs(逆傅里叶变换的结果) : 将逆傅里叶变换的结果不能直接显示为图像需要变为灰度值显示为图像 代码如下
import cv2
import numpy as np
import matplotlib.pyplot as plt
img cv2.imread(lena.png)
img cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 实现傅里叶变换
f np.fft.fft2(img)
fshift np.fft.fftshift(f)
result 20*np.log(np.abs(fshift))
# 实现傅里叶逆变换fshift_r np.fft.ifftshift(fshift)
f_r np.fft.ifft2(fshift_r)
result_r np.abs(f_r)
# result 20*np.log(np.abs(fshift))plt.subplot(131)
plt.imshow(img, cmap gray)
plt.title(original)
plt.axis(off)
plt.subplot(132)
plt.imshow(result, cmap gray)
plt.title(result)
plt.axis(off)plt.subplot(133)
plt.imshow(result_r, cmap gray)
plt.title(result_r)
plt.axis(off)# numpy.fft.ifft2() 实现逆傅里叶变换返回一个复数数组
# numpy.fft.ifftshift() fftshift的逆函数将低频信息由中心移到左上角
# iimg np.abs(逆傅里叶变换的结果) : 将逆傅里叶变换的结果不能直接显示为图像需要变为灰度值显示为图像plt.show()输出为 高通滤波 低频和高频 低频对应图像内变化缓慢的灰度分量高频相反。 例如一幅大草原图像低频对应着颜色大体一致的绿色草原草原上的狮子边缘对应着高频。 滤波让低频通过的滤波器称为低通滤波器反之为高通滤波器。 低通滤波将模糊一幅图像丢失边缘高通滤波将增强尖锐的细节图像的边缘会被保留细节会丢失掉。但是会导致图像的对比度降低。 频域滤波修改傅里叶变换以达到特殊目的然后计算逆傅里叶变换IDFT返回到图像域空域。可以实现图像增强、图像去燥、边缘检测、特征提取、压缩、加密等等。 将低频的地方置为0 import cv2
import numpy as np
import matplotlib.pyplot as plt
img cv2.imread(lena.png, 0)rows, cols img.shape[:2]f np.fft.fft2(img) #傅里叶变换
fshift np.fft.fftshift(f) #将低频移到中心
rows,cols int(rows/2), int(cols/2) #获取图像中心点
fshift[rows-30:rows30, cols-30:cols30] 0 #将中心点周围30区域置为0即将低频信息去掉实现高通#滤波
ishift np.fft.ifftshift(fshift) #将低频移还原到左上角
iimg np.fft.ifft2(ishift) #逆傅里叶变换
iimg np.abs(iimg) #将逆傅里叶变换的结果转换为灰度值显示为图像
plt.subplot(121), plt.imshow(img, cmapgray)
plt.title(original), plt.axis(off)
plt.subplot(122), plt.imshow(iimg, cmapgray)
plt.title(iimg),plt.axis(off)
plt.show()输出为
2opencv实现–cv2.dft()
result cv2.dft(原始图像 转换标识)注意
1返回结果是双通道的第1个通道是结果的实数部分第2个通道是结果的虚数部分
2输入的图像首先要转化成np.float32格式 语法np.float32(img)
3转换标识flags cv2.DFT_COMPLEX_OUTPUT 输出是一个复数阵列
numpy.fft.fftshift()将低频分量转移到频谱中心
返回值 cv2.magnitude(参数1 参数2) 将傅里叶变换结果转换为灰度值进行显示
参数1浮点型X坐标值也就是实部
参数2浮点型Y坐标值也就是虚部代码示例
import numpy as np
import cv2
import matplotlib.pyplot as plt
img cv2.imread(lena.png, 0)
dft cv2.dft(np.float32(img), flags cv2.DFT_COMPLEX_OUTPUT) #傅里叶变换
dftShift np.fft.fftshift(dft) #低频移到中心位置
result 20*np.log(cv2.magnitude(dftShift[:,:,0], dftShift[:,:,1])) #转换为灰度值显示
plt.subplot(121), plt.imshow(img, cmapgray)
plt.title(original), plt.axis(off)
plt.subplot(122),plt.imshow(result, cmapgray)
plt.title(result), plt.axis(off)
plt.show()输出为 opencv进行逆傅里叶变换 将经过傅里叶变换并处理的频域图像进行逆傅里叶变换为原图
返回结果cv2.idft(原始数据)返回结果取决于原始数据的类型和大小
原始数据实数或者复数均可代码如下
import cv2
import numpy as np
import matplotlib.pyplot as plt
o cv2.imread(lena.png, 0)# 傅里叶结果
dft cv2.dft(np.float32(o), flagscv2.DFT_COMPLEX_OUTPUT) #傅里叶变换,flags不能省
dshift np.fft.fftshift(dft) #低频从左上角移到中心
result 20*np.log(cv2.magnitude(dftShift[:,:,0], dftShift[:,:,1])) #转换为灰度值显示
# 傅里叶逆变换
ishift np.fft.ifftshift(dshift) #从中心移到左上角还原
io cv2.idft(ishift) #逆傅里叶变换
io cv2.magnitude(io[:,:,0], io[:,:,1]) #转换为灰度值, [0-255]plt.subplot(131)
plt.imshow(o, cmapgray)
plt.axis(off)
plt.title(original)plt.subplot(132)
plt.imshow(result, cmapgray)
plt.axis(off)
plt.title(fly)plt.subplot(133)
plt.imshow(io, cmapgray)
plt.axis(off)
plt.title(inverse)
plt.show() 输出为
6、图像梯度 6.1 sobel算子 函数实现
dst cv2.Sobel(src, ddepth, dx, dy, [ksize])dst计算结果
src原始图像
ddepth 处理结果图像深度
dxx轴方向
dyy轴方向
ksize核大小
ddepth参数说明
一般通常直接设置为-1表示让处理结果与原始图像保持一致
但是此处需要注意不能直接置为-1举例说明 在256色位图中白色点像素值为255黑色点像素值为0 A右边减去左边为0-255-255是负数会直接截断处理为0所以这个边界显示不出来 B右边为255-0255可以显示出来 说明直接计算只能得到一个边界 故需要取绝对值才行 因此在写ddepth参数的时候不能让它为-1需要设置成cv2.CV_64F 表示如果出现负数先保留负数的值而不是直接将它截断置为0那样就找不到边界了 现在怎么处理这个负数呢 dst cv2.converScaleAbs(src, [, alpha[, beta]])作用把负数的值取绝对值无论边界是正负都能获取
dx dy参数说明
计算x方向梯度 dx1,dy0
计算y方向梯度dx0dy16.2 scharr算子 --比sobel算子效果更好 使用3*3的sobel算子时可能不太清楚吗使用scharr算子效果更好。 函数实现
dst Scharr(src, ddpeth, dx, dy)src原始图像
ddepth处理结果图像深度
dxx轴方向
dyy轴方向
注意
ddepth参数一般在别的图像处理函数中直接置为-1表示处理成与原图像一样深度的图像但是由于此函数处理过程中会出现负数故与sobel算子一样将它赋值为cv2.CV_64F
然后再转为unit8正数dst Scharrsrc, cv2.CV_64F, dx, dy
dst cv2.convertScaleAbs(dst)sobel和 scharr算子的比较 1大小是一样的说明计算起来的工作量是一样的 但是scharr精确度更高给了临近像素更高的权重
6.3 laplacian算子
拉普拉斯算子类似于二阶sobel导数。实际上在OpenCV中通过调用sobel算子来计算拉普拉斯算子。
函数实现
dst cv2.Laplacian(src, ddepth)注意通常情况下可以将图像深度ddepth的值设置为-1让处理结果与原始图像保持一致 但是该函数在计算过程中也会出现负数故 代码 import cv2
import numpy as np
o cv2.imread(lena.png, cv2.IMREAD_GRAYSCALE)laplacian cv2.Laplacian(o, cv2.CV_64F)
laplacian cv2.convertScaleAbs(laplacian) #转回uint8cv2.imshow(original, o)
cv2.imshow(laplacian, laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
7、边缘检测
canny边缘检测
函数实现
edges cv2.Canny(image, threshold1, threshold2)image 原始图像
threshold1 阈值1 minVal
threshold2 阈值2 maxValthreshold值越小细节越丰富
import cv2
import numpy as np
o cv2.imread(lena.png, cv2.IMREAD_GRAYSCALE)
o cv2.resize(o,None,fx0.5,fy0.5)r cv2.Canny(o,100,200)
# 下面是不同阈值处理结果可以看出阈值越小细节越丰富
r1 cv2.Canny(o,64,128)
# laplacian cv2.Laplacian(o, cv2.CV_64F)
# laplacian cv2.convertScaleAbs(laplacian) #转回uint8cv2.imshow(original, o)
cv2.imshow(c, r)
cv2.imshow(c1, r1)
cv2.waitKey(0)
cv2.destroyAllWindows()输出为
8、图像金字塔 8.1 向下采样 代码为
import cv2
import numpy as np
o cv2.imread(lena.png)
# 依次变为原来的四分之一
r1 cv2.pyrDown(o)
r2 cv2.pyrDown(r1)
r3 cv2.pyrDown(r2)cv2.imshow(original, o)
cv2.imshow(PyrDown1, r1)
cv2.imshow(PyrDown2, r2)
cv2.imshow(PyrDown3, r3)cv2.waitKey(0)
cv2.destoryAllWindows()输出为
8.2 向上采样 代码为
import cv2
import numpy as np
o cv2.imread(lena.png)
o cv2.resize(o,None,fx0.1,fy0.1)
r1 cv2.pyrUp(o)
r2 cv2.pyrUp(r1)
r3 cv2.pyrUp(r2)cv2.imshow(original, o)
cv2.imshow(PyrUp1, r1)
cv2.imshow(PyrUp2, r2)
cv2.imshow(PyrUp3, r3)cv2.waitKey(0)
cv2.destoryAllWindows()输出为
车牌识别
前面博客介绍了OpenCV图像处理的基础知识本篇博客利用前面知识完成一个小项目——车牌号码识别。 简洁易懂的车牌号识别Python实现“超详解”含代码 1、整体思路 2、代码详解 2.1提取车牌位置 2.2车牌字符的分割 2.3模板匹配识别字符 3、总结 4、参考 1、整体思路
首先附上本次识别的图片
基于OpenCV车牌号识别总体分为四个步骤 1提取车牌位置将车牌从图中分割出来 2车牌字符的分割 3通过模版匹配识别字符 4将结果绘制在图片上显示出来。 与深度学习相比传统图像处理的识别有好处又有坏处 好处不需要大量的数据集训练模型通过形态学、边缘检测等操作提取特征 坏处基于传统图像处理的图像识别代码的泛化性较低当图像的角度光照不同时识别效果有时会不尽人意。
2、代码详解
为了方便观察每一步图片的变化本次代码在Jupyter Notebook上编写全部代码以上传可直接运行。 本次项目中会多次使用到图片显示和图片去噪灰度处理所以首先定义了显示函数和高斯滤波灰度处理函数方便后面的调用
# 导入所需模块
import cv2
from matplotlib import pyplot as plt
import os
import numpy as np
# plt显示彩色图片
def plt_show0(img):
#cv2与plt的图像通道不同cv2为[b,g,r];plt为[r, g, b]b,g,r cv2.split(img)img cv2.merge([r, g, b])plt.imshow(img)plt.show()# plt显示灰度图片
def plt_show(img):plt.imshow(img,cmapgray)plt.show()# 图像去噪灰度处理
def gray_guss(image):image cv2.GaussianBlur(image, (3, 3), 0)gray_image cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)return gray_image2.1提取车牌位置
对图片进行阈值化处理、边缘检测及形态学操作根据得到的轮廓特征识别车牌的具体位置将车牌分割出来。直接上代码及代码详解
# 读取待检测图片
origin_image cv2.imread(./refer1/icar.jpg)
# 复制一张图片在复制图上进行图像操作保留原图
image origin_image.copy()
# 图像去噪灰度处理
gray_image gray_guss(image)
# x方向上的边缘检测增强边缘信息
Sobel_x cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
absX cv2.convertScaleAbs(Sobel_x)
image absX# 图像阈值化操作——获得二值化图
ret, image cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)
# 显示灰度图像
plt_show(image)
# 形态学从图像中提取对表达和描绘区域形状有意义的图像分量——闭操作
kernelX cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10))
image cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations 1)
# 显示灰度图像
plt_show(image)二值化图以及闭操作闭合细小的连接抑制暗细节的结果如图所示 输出为
# 腐蚀erode和膨胀dilate
kernelX cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
kernelY cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20))
#x方向进行闭操作抑制暗细节
image cv2.dilate(image, kernelX)
image cv2.erode(image, kernelX)
#y方向的开操作
image cv2.erode(image, kernelY)
image cv2.dilate(image, kernelY)
# 中值滤波去噪
image cv2.medianBlur(image, 21)
# 显示灰度图像
plt_show(image)
# 获得轮廓
contours, hierarchy cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)for item in contours:rect cv2.boundingRect(item)x rect[0]y rect[1]weight rect[2]height rect[3]# 根据轮廓的形状特点确定车牌的轮廓位置并截取图像if (weight (height * 3.5)) and (weight (height * 4)):image origin_image[y:y height, x:x weight]plt_show0(image)
输出为
2.2车牌字符的分割
#车牌字符分割
# 图像去噪灰度处理
gray_image gray_guss(image)
# 图像阈值化操作——获得二值化图
ret, image cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU)
plt_show(image)#膨胀操作使“苏”字膨胀为一个近似的整体为分割做准备
kernel cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
image cv2.dilate(image, kernel)
plt_show(image)
输出为
# 查找轮廓
contours, hierarchy cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
words []
word_images []
#对所有轮廓逐一操作
for item in contours:word []rect cv2.boundingRect(item)x rect[0]y rect[1]weight rect[2]height rect[3]word.append(x)word.append(y)word.append(weight)word.append(height)words.append(word)
# 排序车牌号有顺序。words是一个嵌套列表
words sorted(words,keylambda s:s[0],reverseFalse)
i 0
#word中存放轮廓的起始点和宽高
for word in words:# 筛选字符的轮廓if (word[3] (word[2] * 1.5)) and (word[3] (word[2] * 3.5)) and (word[2] 25):i i1splite_image image[word[1]:word[1] word[3], word[0]:word[0] word[2]]word_images.append(splite_image)print(i)
print(words)for i,j in enumerate(word_images): plt.subplot(1,7,i1)plt.imshow(word_images[i],cmapgray)
plt.show()
输出为
2.3模板匹配识别字符
模板匹配是一个机械性的流程所以把机械性的操作设定为函数。
#模版匹配
# 准备模板(template[0-9]为数字模板)
template [0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,U,V,W,X,Y,Z,藏,川,鄂,甘,赣,贵,桂,黑,沪,吉,冀,津,晋,京,辽,鲁,蒙,闽,宁,青,琼,陕,苏,皖,湘,新,渝,豫,粤,云,浙]# 读取一个文件夹下的所有图片输入参数是文件名返回模板文件地址列表
def read_directory(directory_name):referImg_list []for filename in os.listdir(directory_name):referImg_list.append(directory_name / filename)return referImg_list# 获得中文模板列表只匹配车牌的第一个字符
def get_chinese_words_list():chinese_words_list []for i in range(34,64):#将模板存放在字典中c_word read_directory(./refer1/ template[i])chinese_words_list.append(c_word)return chinese_words_list
chinese_words_list get_chinese_words_list()# 获得英文模板列表只匹配车牌的第二个字符
def get_eng_words_list():eng_words_list []for i in range(10,34):e_word read_directory(./refer1/ template[i])eng_words_list.append(e_word)return eng_words_list
eng_words_list get_eng_words_list()# 获得英文和数字模板列表匹配车牌后面的字符
def get_eng_num_words_list():eng_num_words_list []for i in range(0,34):word read_directory(./refer1/ template[i])eng_num_words_list.append(word)return eng_num_words_list
eng_num_words_list get_eng_num_words_list()# 读取一个模板地址与图片进行匹配返回得分
def template_score(template,image):#将模板进行格式转换template_imgcv2.imdecode(np.fromfile(template,dtypenp.uint8),1)template_img cv2.cvtColor(template_img, cv2.COLOR_RGB2GRAY)#模板图像阈值化处理——获得黑白图ret, template_img cv2.threshold(template_img, 0, 255, cv2.THRESH_OTSU)
# height, width template_img.shape
# image_ image.copy()
# image_ cv2.resize(image_, (width, height))image_ image.copy()#获得待检测图片的尺寸height, width image_.shape# 将模板resize至与图像一样大小template_img cv2.resize(template_img, (width, height))# 模板匹配返回匹配得分result cv2.matchTemplate(image_, template_img, cv2.TM_CCOEFF)return result[0][0]# 对分割得到的字符逐一匹配
def template_matching(word_images):results []for index,word_image in enumerate(word_images):if index0:best_score []for chinese_words in chinese_words_list:score []for chinese_word in chinese_words:result template_score(chinese_word,word_image)score.append(result)best_score.append(max(score))i best_score.index(max(best_score))# print(template[34i])r template[34i]results.append(r)continueif index1:best_score []for eng_word_list in eng_words_list:score []for eng_word in eng_word_list:result template_score(eng_word,word_image)score.append(result)best_score.append(max(score))i best_score.index(max(best_score))# print(template[10i])r template[10i]results.append(r)continueelse:best_score []for eng_num_word_list in eng_num_words_list:score []for eng_num_word in eng_num_word_list:result template_score(eng_num_word,word_image)score.append(result)best_score.append(max(score))i best_score.index(max(best_score))# print(template[i])r template[i]results.append(r)continuereturn resultsword_images_ word_images.copy()
# 调用函数获得结果
result template_matching(word_images_)
print(result)
# .join(result)函数将列表转换为拼接好的字符串方便结果显示
print( .join(result))
输出为 最后利用PIL库将结果绘制在原图上
from PIL import ImageFont, ImageDraw, Imageheight,weight origin_image.shape[0:2]
print(height)
print(weight)image_1 origin_image.copy()
cv2.rectangle(image_1, (int(0.2*weight), int(0.75*height)), (int(weight*0.9), int(height*0.95)), (0, 255, 0), 5)#设置需要显示的字体
fontpath ./refer1/simhei.ttf
font ImageFont.truetype(fontpath,64)
img_pil Image.fromarray(image_1)
draw ImageDraw.Draw(img_pil)
#绘制文字信息
draw.text((int(0.2*weight)25, int(0.75*height)), .join(result), font font, fill (255, 255, 0))
# draw.text((int(0.2*weight)25, int(0.75*height)), .join(result),fill (255, 255, 0))
bk_img np.array(img_pil)
print(result)
print( .join(result))
plt_show0(bk_img)获得的最终输出图片如下
大功告成
3、总结
一 、OpenCV的车牌号码识别一共分为四步走 1–提取车牌位置将车牌从图中分割出来 2–车牌字符的分割 3–通过模版匹配识别字符 4–将结果绘制在图片上显示出来。 二、图像处理的识别泛化性较低对图片的角度光照有要求所以要理解图像处理每一步的作用根据自己图像的特点调整参数更改操作顺序等等以达到最好的效果。 三、车牌号识别的模板连接如下需要的可以下载有了模板就可以识别自己的图片了 链接https://pan.baidu.com/s/1QBjy7c0klv_PBUwJjA8ynA 提取码v53d 四、完整代码已上传SCDN点击查看
针对完全没有基础的同学们 1.确定机器学习的应用领域有哪些 2.查找机器学习的算法应用有哪些 3.确定想要研究的领域极其对应的算法 4.通过招聘网站和论文等确定具体的技术 5.了解业务流程查找数据 6.复现经典算法 7.持续优化并尝试与对应企业人员沟通心得 8.企业给出反馈