OpenCV 官网:https://opencv.org/
OpenCV 中文网站:http://wiki.opencv.org.cn/index.php
# 引入OpenCV
import cv2
# 读取图片-与python文件相同目录
img = cv2.imread("image.png")
# 显示窗口命名
cv2.namedWindow("demo")
# 显示加载的图像
cv2.imshow("demo", img)
# 窗口保持显示(回车键可关闭窗口)
cv2.waitKey(0)
# 销毁所有窗口
cv2.destroyAllWindows()
1)读取图像
显示控制参数:
- http://www.emgu.com/wiki/files/3.2.0/document/html/880eb761-0ba1-c412-13db-93d6f11aea3b.htm
- cv2.IMREAD_UNCHANGED:不改变,原始图像
- cv2.IMREAD_GRAYSCALE:灰度
- cv2.IMREAD_COLOR:彩色
2)显示图像
delay 说明:
delay > 0 :等待 delay 毫秒
delay < 0 :等待键盘单击
delay = 0 :无限等待
销毁所有窗口,清除内存的缓存
3)保存图像
# 导入 OpenCV
import cv2
# 读取图片-与python文件相同目录
img = cv2.imread("image.png", cv2.IMREAD_GRAYSCALE)
# 显示窗口命名
cv2.namedWindow("demo")
# 显示加载的图像
cv2.imshow("demo", img)
# 窗口保持显示(回车键可关闭窗口)
cv2.waitKey(0)
# 销毁所有窗口
cv2.destroyAllWindows()
# 保存图像
cv2.imwrite("D:\\demo.png", img)
1)图像是由像素构成的
2)图像分类
二值图像:图像只有两个值,任何一个点非黑即白
灰度图像:图像有黑白灰三种颜色,并分为 256 个颜色,0 为黑色,255 为白色,1 - 254 为不同程度的灰色
RGB 图像:
彩色图像,三原色 R [red 红色]、G [green 绿色]、B[blue 蓝色] ;
每个颜色都有 0 - 255 的数值,表示颜色的深浅;通过三种颜色,不同比例的混合,生成新的颜色
OpenCV 中的通道顺序为:B G R,如某个像素用 OpenCV 读取为 (122, 87, 23) ,即 B = 122,G = 87,R = 23
RGB 图像 转 灰度图像:
灰度图像 转 二值图像
1)读取像素
灰度图像,返回灰度值;
BGR 图像,返回 B,G,R 的值;例如
2)修改像素值
# 导入 OpenCV
import cv2
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image.png", cv2.IMREAD_GRAYSCALE)
# 读取 11行 - 22列 的值
print(img[11, 22])
# 修改 11行 - 22列 的值
img[11, 22] = 233
print(img[11, 22])
print("========================================")
# 读取图片-与python文件相同目录, 原图-彩色图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 读取 11行 - 22列 的值
print(img[11, 22])
# 修改 11行 - 22列 的 BGRA 值
img[11, 22] = [233, 233, 233, 233]
print(img[11, 22])
print("========================================")
# 读取图片-与python文件相同目录, 原图-彩色图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 读取 第 0 个通道 - 11行 - 22列 的值
print(img[11, 22, 0])
# 修改 第 0 个通道 - 11行 - 22列 的 BGRA 值
img[11, 22, 0] = 233
print(img[11, 22])
print("========================================")
# 读取图片-与python文件相同目录, 原图-彩色图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 显示原图
cv2.imshow("original", img)
# 修改 11行至16行 - 22列至28列 的 BGRA 值
img[11:16, 22:28] = [233, 233, 233, 233]
# 显示修改图
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
1)读取像素
灰度图像,返回灰度值
例如:img.item(11, 22) 表示读取 11 行、22 列的值
BGR 图像,返回值 B,G,R 的值
例如:blue = img.item(11, 22, 0) 表示读取第 0 个通道,11行、22 列的值
2)修改显示
灰度图像
例如:img.itemset((11, 22), 233) 表示给 11 行、22 列赋值为 233
BRG 图像、
例如:img.itemset((11, 22, 0), 233) 表示给第 0 个通道、11 行、22 列赋值为 233
# 导入 OpenCV
import cv2
# 导入 numpy
import numpy as np
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image.png", cv2.IMREAD_GRAYSCALE)
# 读取 11行 - 22列 的值
print(img.item(11, 22))
# 修改 11行 - 22列 的值
img.itemset((11, 22), 233)
print(img.item(11, 22))
print("========================================")
# 读取图片-与python文件相同目录, 原图-彩色图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 读取 第 0 个通道 - 11行 - 22列 的值
print(img.item(11, 22, 0))
# 修改 第 0 个通道 - 11行 - 22列 的值
img.itemset((11, 22, 0), 233)
print(img.item(11, 22, 0))
1)形状:行、列、通道数
灰度图像,返回行数,列数
例如:img.shape 获取图像形状的元组,(600, 200) 表示图像有 600 行、200 列
彩色图像,返回行数,列数,通道数
例如:img.shape 获取图像形状的元组和通道数,(600, 200, 3) 表示图像有 600 行、200 列、有 3 个通道
**2)像素数目 **
灰度图像,返回行数 * 列数
例如:img.size 获取像素数目
彩色图像,返回行数 * 列数 * 通道数
3)图像的数据类型
dtype 可以获取每一个图像点的数据类型
例如:img.dtype 返回 uint8 数据类型
# 导入 OpenCV
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 形状
print(img.shape)
# 像素数数目
print(img.size)
# 像素点的数据类型
print(img.dtype)
print("========================================")
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image.png", cv2.IMREAD_GRAYSCALE)
# 形状
print(img.shape)
# 像素数数目
print(img.size)
# 像素点的数据类型
print(img.dtype)
1)通过像素数位置,获取感兴趣的区域
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 显示图像
cv2.imshow("result-original", img)
# 获取区域
roi = img[11:33, 22:44]
# 显示图像
cv2.imshow("result-roi", roi)
# numpy 创建图像
roi = np.ones((22, 22, 3))
# 获取 ROI 图像
roi = img[11:33, 22:44]
# 显示图像
cv2.imshow("result-roi2", roi)
# 将 ROI 图像显示在原图的左上角中
img[0:22, 0:22] = roi
# 显示图像
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
1)拆分通道
将彩色图像分为B,G,R
例如:b, g, r = cv2.split(img)
2)合并通道
将B,G,R 通道合并为彩色图像
例如:cv2.merge([b, g, r])
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 拆分图像
b,g,r,a = cv2.split(img)
# 显示图像(可通过 shape 属性查看通道数)
cv2.imshow("B", b)
cv2.imshow("G", g)
cv2.imshow("R", r)
cv2.imshow("A", a)
# 可获取单通道图像
b = cv2.split(img)[0]
g = cv2.split(img)[1]
r = cv2.split(img)[2]
# numpy 创建零值通道
rows, cols, chn = img.shape
zero = np.zeros((rows, cols), dtype=img.dtype)
# 合并绿色通道和零值通道
mg = cv2.merge([zero, g, zero])
cv2.imshow("merge-g", mg)
# 合并通道
mbgr = cv2.merge([b, g, r])
cv2.imshow("merge-bgr", mbgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
参与运算的图像大小、类型必须一致
1)取模加法
numpy 运算方式:结果 = 图像1 + 图像2
像素值在十进制的情况下,最大值为 255,像素值相加后,有可能出现大于 255 的情况
(1) 像素值 <= 255,直接使用结果
(2) 像素值 > 255,需要结果对 255 取模,即【结果 % 255 = 最终结果】
2)饱和运算
opencv 运算方式:结果 = cv2.add(图像1, 图像2)
(1) 像素值 <= 255,直接使用结果
(2) 像素值 > 255,取最大值 255
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
img2 = img
# numpy 加法(取模加法)
numpy_img = img + img2
# opencv 加法(饱和运算)
cv_img = cv2.add(img, img2)
# 显示图像
cv2.imshow("numpy_img", numpy_img)
cv2.imshow("cv_img", cv_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
将 2 张或 2 张以上的 图像融合为 1 张图像上
融合的图像含有更多的信息,能够更方便人的观察和计算机处理
例如:两张相同的图像,每张图片都在不同的位置出现模糊的情况,但是两张图像融合之后,还原出一张清晰的图像
图像加法中,图像时按照 1:1 进行相加,而融合是需要调整系数后再相加
1)numpy 图像融合
结果图像 = 图像1 * 系数1 + 图像2 + 系数2 + 亮度调节量
img = img1 * 0.3 + img2 * 0.7 + 18
2)opencv 图像融合
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
img2 = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# numpy 融合
numpy_img = img * 0.3 + img2 * 0.7 + 10
# opencv 融合
cv_img = cv2.addWeighted(img, 0.3,img2, 0.7, 10)
# 显示图像
cv2.imshow("numpy_img", numpy_img)
cv2.imshow("cv_img", cv_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
opencv 中提供了 200 多种不同类型直接的转换
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 读取图片-与python文件相同目录, 灰度图
img2 = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 图像转换
b2g = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
b2r = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
g2b = cv2.cvtColor(img2, cv2.COLOR_GRAY2BGR)
# 输出形状信息
print(b2g.shape)
print(b2r.shape)
print(g2b.shape)
# 显示图像
cv2.imshow("b2g", b2g)
cv2.imshow("b2r", b2r)
cv2.imshow("g2b", g2b)
cv2.waitKey(0)
cv2.destroyAllWindows()
resize 函数
语法格式:dst = cv2.resize(img, dsize) 参数为图像和缩放大小(列, 行)
例如:dst = cv2.resize(img, (122, 122))
语法格式:dst = cv2.resize(img, dsize, fx, fy) 参数 fx 表示水平缩放倍数,fy 表示垂直缩放倍数
例如:dst = cv2.resize(img, None, fx=0.3, fy=0.6)
dsize 和 fx,xy 设置一个即可,dsize 优先
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 图像缩放(列,行)
rezie = cv2.resize(img, (100, 100))
# 图像缩放-倍数(行,列)
rezie2 = cv2.resize(img, None, fx=0.7, fy=0.7)
# 图像缩放-比例(列,行)
rows,cols = img.shape[:2]
rezie3 = cv2.resize(img, (round(cols * 0.8), round(rows * 0.8)))
# 显示图像
cv2.imshow("rezie", rezie)
cv2.imshow("rezie2", rezie2)
cv2.imshow("rezie3", rezie2)
cv2.waitKey(0)
cv2.destroyAllWindows()
flip 函数
语法:dst = cv2.flip(img, filipCode) 参数为图像 和翻转模式
翻转模式:
等于 0 表示以 X 轴进行对称翻转(上下翻转)
大于 0 表示以 Y 轴进行对称轴翻转(左右翻转)
小于 0 表示 在 X 轴和 Y 轴方向同时翻转(先上下,后左右)
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 上下翻转
x = cv2.flip(img, 0)
# 左右翻转
y = cv2.flip(img, 1)
# 上下、左右同时翻转
xy = cv2.flip(img, -1)
# 显示图像
cv2.imshow("x", x)
cv2.imshow("y", y)
cv2.imshow("xy", xy)
cv2.waitKey(0)
cv2.destroyAllWindows()
1)Value and Threshold Level 原始图像
2)Threshold Binary 二进制阈值化
3)Threshold Binary, Inverted 反二进制阈值化
4)Truncate 截断阈值化
5)Threshold Zero,Inverted 反阈值化为 0
6)Threshold to Zero 阈值化为0
语法:retval, dst = cv2.threshod(img, thresh, maxval, type)
参数:retval=阈值,dst=处理结果,img=源图像,thresh=阈值,maxval=最大值,type=类型
type 类型 | 说明 | 简要 |
---|---|---|
cv2.THRESH_BINARY | 二进制阈值化 | 较亮的更亮,较暗的更暗 |
cv2.THRESH_BINARY_INV | 反二进制阈值化 | 亮的变暗,暗的变亮 |
cv2.THRESH_TRUNC | 截断阈值化 | 降低亮度 |
cv2.THRESH_TOZERO_INV | 反阈值化为 0 | 亮的变黑 |
cv2.THRESH_TOZERO | 阈值化为 0 | 暗的变黑 |
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 二进制二值化
th,binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 反二进制二值化
th,binary_inv = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
# 截断阈值化
th,trunc = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
# 反二值化为 0
th,tozero_inv = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
# 二值化为 0
th,tozero = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
# 显示图像
cv2.imshow("binary", binary)
cv2.imshow("binary_inv", binary_inv)
cv2.imshow("trunc", trunc)
cv2.imshow("tozero_inv", tozero_inv)
cv2.imshow("tozero", tozero)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像上,任意一点的像素值,都是周围 N*N 个像素值的均值
例如:下图中,对红色点进行均值滤波处理,会由周围 5*5 的所有像数值相加(包括红点的像数值),然后除以25,最终得到红色点的均值
周围的 N*N 个像素称为 核
红点周围的 5*5 个点,每个点的像素值乘以 1/25,然后所有值相加,得到红点的均值
blur 函数
语法:reval = cv2.blur(img, ksize)
参数:img 表示图像;ksize 表示核大小,以元组表示 (宽度, 高度)
效果:可将带雪花白点干扰的图像,处理为平滑无干扰的图像
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 均值滤波
bval = cv2.blur(img, (5, 5))
# 显示图像
cv2.imshow("bval", bval)
cv2.waitKey(0)
cv2.destroyAllWindows()
boxFilter 函数
语法:reval = cv2.boxFilter(img, depth, ksize, normalize)
参数:reval 表示处理结果,img 表示图像,depth 表示目标图像的深度( -1 表示与原始图像一致),ksize 表示核大小,normalize 表示归一化属性
normalize = 1 表示与均值滤波的处理相同,normalize = 0 表示核内的像素值相加(255 白色),可以控制核大小,避免图像空白
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 方框滤波,不做归一化处理
bval0 = cv2.boxFilter(img, -1, (2, 2), normalize = 0)
# 方框滤波,归一化处理
bval1 = cv2.boxFilter(img, -1, (5, 5), normalize = 1)
# 显示图像
cv2.imshow("bval0", bval0)
cv2.imshow("bval1", bval1)
cv2.waitKey(0)
cv2.destroyAllWindows()
让临近的像素具有更高的重要度,图像上某一点,对周围像素计算加权平均值,距离点较近的像素具有较大的权重值
例如:对红点进行高斯滤波处理,在 3*3 的核中,距离红点最近的像素是上下左右的像素,所以权重值最大,其它像素较远,所以权重值会减少,最终红点值为核内所有的像素值乘以权重值之和
GaussianBlur 函数
语法:reval = cv2.GaussianBlur(img, ksize, sigmaX)
参数:img 表示图像,ksize 表示核大小,必须为奇数,sigmaX 表示X方向方差,控制权重【sigmaX=0 时,sigmaX = 0.3 * ((ksize-1) * 0.5 - 1) + 0.8】,Y方向方差默认与X方向方差一致
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 高斯滤波
reval = cv2.GaussianBlur(img, (5, 5), 0)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
对核内的像素值进行排序,去排序中间位置的像数值作为中值滤波的像数值
medianBlur 函数
语法: reval = cv2.medianBlur(img, ksize)
参数:img 表示图像;ksize 表示核大小,必须是比 1 大的奇数
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 高斯滤波
reval = cv2.medianBlur(img, 5)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
二值图像
图像中,以卷积核的中心点为中心,个像素扫描原始图像,如果卷积核覆盖的区域全都是 1(白色),则保留 1,如果卷积核覆盖的区域有 0(黑色),则将和中心点的像素设为 0
效果:将粗线条处理为细线条,或者去除毛边
erode 函数
语法:reval = cv2.erode(img, kernel, iterations)
参数:img 表示图像;kernel 表示卷积核;iterations 表示迭代次数,默认 1 次腐蚀
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 创建 5*5 值为 1 的卷积核
kernel = np.ones((5, 5), np.uint8)
# 腐蚀处理
reval = cv2.erode(img, kernel)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像中,以卷积核的中心点为中心,个像素扫描原始图像,如果卷积核覆盖的区域有 1(白色),则设置为 1,如果卷积核覆盖的区域全都是 0(黑色),则将和中心点的像素保留为 0
dilate 函数
语法:reval = cv2.dilate(img, kernel, iterations)
参数:img 表示图像;kernel 表示卷积核;iterations 表示迭代次数
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image3.png", cv2.IMREAD_UNCHANGED)
# 创建 5*5 值为 1 的卷积核
kernel = np.ones((5, 5), np.uint8)
# 膨胀处理
reval = cv2.dilate(img, kernel)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
morphologyEx 函数
知识点:在形态学处理中,除了腐蚀和膨胀,其它的处理方法均为形态学扩展,统一使用 morphologyEx 函数实现
语法:opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
参数:img 表示图像;cv2.MORPH_OPEN 表示开运算常量;kernel 表示卷积核
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image3.png", cv2.IMREAD_UNCHANGED)
# 创建 5*5 值为 1 的卷积核
kernel = np.ones((5, 5), np.uint8)
# 开运算处理
reval = cv2.morphologyEx(img, cv2.MORPH_OPEN,kernel)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
morphologyEx 函数
语法:opening = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
参数:img 表示图像;cv2.MORPH_CLOSE 表示闭运算常量;kernel 表示卷积核
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image3.png", cv2.IMREAD_UNCHANGED)
# 创建 5*5 值为 1 的卷积核
kernel = np.ones((5, 5), np.uint8)
# 闭运算处理
reval = cv2.morphologyEx(img, cv2.MORPH_CLOSE,kernel)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
morphologyEx 函数
语法:opening = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
参数:img 表示图像;cv2.MORPH_GRADIENT 表示梯度运算常量;kernel 表示卷积核
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image3.png", cv2.IMREAD_UNCHANGED)
# 创建 5*5 值为 1 的卷积核
kernel = np.ones((5, 5), np.uint8)
# 梯度运算处理
reval = cv2.morphologyEx(img, cv2.MORPH_GRADIENT,kernel)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
morphologyEx 函数
语法:opening = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
参数:img 表示图像;cv2.MORPH_TOPHAT 表示礼帽运算常量;kernel 表示卷积核
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image3.png", cv2.IMREAD_UNCHANGED)
# 创建 5*5 值为 1 的卷积核
kernel = np.ones((5, 5), np.uint8)
# 礼帽运算处理
reval = cv2.morphologyEx(img, cv2.MORPH_TOPHAT,kernel)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
morphologyEx 函数
语法:opening = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
参数:img 表示图像;cv2.MORPH_BLACKHAT 表示黑帽运算常量;kernel 表示卷积核
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image3.png", cv2.IMREAD_UNCHANGED)
# 创建 5*5 值为 1 的卷积核
kernel = np.ones((5, 5), np.uint8)
# 黑帽运算处理
reval = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT,kernel)
# 显示图像
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
X 轴方向的梯度,计算水平方向有没有边界,梯度值大说明存在边界,否则不存在
例如:P5 点的 X 轴方向的梯度值,使用右边值减去左边值;由于 X 轴方向上,P4 和 P6 距离 P5 最近,对应权重最大为 2,其它为 1;如果两边的值差别比较大,P5 相应的会比较大,说明边界存在,否则边界不存在(比如值为 0)
Y 轴方向的梯度,计算垂直方向有没有边界,梯度值大说明存在边界,否则不存在
例如:P5 点的 Y 轴方向的梯度值,使用下边值减去上边值;由于Y 轴方向上,P2 和 P8 距离 P5 最近,对应权重最大为 2,其它为 1;如果两边的值差别比较大,P5 相应的会比较大,说明边界存在,否则边界不存在(比如值为 0)
Sobel 函数
语法:reval = cv2.Sobel(img, ddepth, dx, dy, [ksize])
参数:img 表示图像;ddepth 表示处理结果图像的深度(设置为 -1 表示让结果与原始图像保持一致);dx 表示 X 轴方向(如果只计算 X 轴:dx=1,dy=0);dy 表示 Y 轴方向(如果只计算 Y 轴:dx=0,dy=1);ksize 表示核大小
实际操作中,计算梯度值可能会出现负数,通常处理的图像是 np.uint8
类型,如果结果为该类型,所有的负数会自动截取为 0,发现信息丢失(例如:两个边界,却只获得一个边界),所以,在计算时需要使用 cv2.CV_64F
,取绝对值后,在转换为 np.uint8
(cv2.CV_8U) 类型
convertScaleAbs 函数
语法:reval = cv2.convertScaleAbs(img, [, alpha[, beta]])
参数:img 表示图像;alpha 表示系数;beta 表示修正值
作用:将图像转为 256 色位图
内部逻辑:结果图像 = 调整(原始图像 * alpha + beta)
在 sobel 计算中,同时计算梯度值的方式有两种
第一种:dx=1,dy=1 ;即 reval = cv2.Sobel(img, ddepth, 1, 1)
第二种(推荐):分别计算 dx 和 dy,然后相加
X 轴梯度值:dx = cv2.Sobel(img, ddepth, 1, 0)
Y 轴梯度值:dy = cv2.Sobel(img, ddepth, 0, 1)
最终梯度值:reval = dx + dy ;也可加入系数:reval = dx * 系数1 + dy * 系数2
addWeighted 函数
语法:reval = cv2.addWeighted(img1, alpha, img2, beta, gamma)
参数:img1 表示图像1;alpha 表示图像1的系数;img2 表示图像2;beta 表示图像2的系数;gamma 表示修正值
效果:计算两幅图像的权重和
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image4.png", cv2.IMREAD_UNCHANGED)
# (第一种方式) 计算图像梯度值
sobelxy1 = cv2.Sobel(img, cv2.CV_64F, 1, 1)
sobelxy1 = cv2.convertScaleAbs(sobelxy1)
# (第二种方式) 计算图像梯度值
# X轴梯度值
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0)
# 将 cv2.CV_64F 转回 uint8
sobelx = cv2.convertScaleAbs(sobelx)
# Y轴梯度值
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1)
# 将 cv2.CV_64F 转回 uint8
sobely = cv2.convertScaleAbs(sobely)
# 图像梯度值
sobelxy2 = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
# 显示图像
cv2.imshow("original", img)
cv2.imshow("sobelxy1", sobelxy1)
cv2.imshow("sobelx", sobelx)
cv2.imshow("sobely", sobely)
cv2.imshow("sobelxy2", sobelxy2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Scharr 函数
语法:reval = cv2.Scharr(img, ddpeth, dx, dy)
参数:img 表示图像;ddepth 表示处理结果图像的深度(设置为 -1 表示让结果与原始图像保持一致;但是为了处理负数问题,需要将深度设置为 cv2.CV_64F
,然后在转换为 uint8 类型 ,详情查看 sobel 算子笔记);dx 表示 X 轴方向;dy 表示 Y 轴方向
注意:dx >=0 && dy >=0 && dx+dy == 1 ,即 dx 和 dy 不能同时设置为 1
两个方向的梯度计算方式
dx = cv2.Scharr(img, ddpeth, 1, 0)
dy = cv2.Scharr(img, ddpeth, 0, 1)
dxy = dx + dy --> cv2.addWeighted(dx, alpha, dy, beta, gamma)
如果将 Sobel 函数的 ksize 设置 -1 ,表示使用 Sobel 算子的升级版 Scharr 算子,即 ksize = -1 的 Sobel 算子等于 Scharr 算子
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image4.png", cv2.IMREAD_UNCHANGED)
# 计算图像梯度值
# X轴梯度值
scharrx = cv2.Scharr(img, cv2.CV_64F, 1, 0)
# 将 cv2.CV_64F 转回 uint8
scharrx = cv2.convertScaleAbs(scharrx)
# Y轴梯度值
scharry = cv2.Scharr(img, cv2.CV_64F, 0, 1)
# 将 cv2.CV_64F 转回 uint8
scharry = cv2.convertScaleAbs(scharry)
# 图像梯度值
sobelxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)
# 显示图像
cv2.imshow("original", img)
cv2.imshow("sobelx", scharrx)
cv2.imshow("sobely", scharry)
cv2.imshow("sobelxy", sobelxy)
cv2.waitKey(0)
cv2.destroyAllWindows()
Laplacian 函数
语法:reval = cv2.Laplacian(img, ddepth)
参数:img 表示图像;ddepth 表示处理图像的深度(设置为 -1 表示让结果与原始图像保持一致;但是为了处理负数问题,需要将深度设置为 cv2.CV_64F
,然后在转换为 uint8 类型 ,详情查看 sobel 算子笔记)
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image4.png", cv2.IMREAD_UNCHANGED)
# 计算图像梯度值
reval = cv2.Laplacian(img, cv2.CV_64F)
# 将 cv2.CV_64F 转回 uint8
reval = cv2.convertScaleAbs(reval)
# 显示图像
cv2.imshow("original", img)
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
Canny 边缘检测步骤:
去噪 --> 梯度(大小和方向) --> 非极大值抑制 --> 滞后阈值
第一步:去噪
第二步:梯度
第三步:非极大值抑制
在获得梯度和方向后,遍历图像,去除不是边界的像素点
去除方法:逐个遍历像素点,判断当前像素点是否是周围像素点中具有相同方向梯度的最大值
例如:图中黄色部分,第一列方向向上中,7 最大;第一列方向向上中,8 最大,以此类推,得到边界;其它值被抑制为 0
第四步:滞后阈值
在计算梯度值时,获取到滞后阈值1为极小值(minVal)和滞后阈值2为极大值(maxVal)
例如:梯度值 > maxVal 保留边界;梯度值 < minVal 剔除边界;minVal < 梯度值 < maxVal 如果点与边界相连,则保留,否则剔除,如 C 与 A 相连则保留,B 则剔除
Canny 函数
语法:reval = cv2.Canny(img, threshold1, threshold2)
参数:reval 表示边界图像;img 表示图像;threshold1 表示阈值1;threshold2 表示阈值2;阈值越小,图像边界越多
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# Canny边缘检测
reval = cv2.Canny(img, 20, 50)
# 显示图像
cv2.imshow("original", img)
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
像素减少,缩小图像
实现步骤:
(1)对图像进行高斯核卷积(高斯滤波中使用下图卷积核)
(2)删除所有的偶数行和列
像素增多,放大图像
实现步骤:
(1)在每个方向上扩大为原来的 2 倍,新增的行和列以 0 填充
(2)使用与 向下采样 一样的卷积核乘以4,作为新增像素的的新值
pyrDown 函数
语法:reval = cv2.pyrDown(img)
参数:reval 表示向下取样结果;img 表示图像
效果:图像缩小为原图的 1/ 4
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 向下取样
reval = cv2.pyrDown(img)
reval2 = cv2.pyrDown(reval)
# 显示图像
cv2.imshow("original", img)
cv2.imshow("reval", reval)
cv2.imshow("reval2", reval2)
cv2.waitKey(0)
cv2.destroyAllWindows()
pyrUp 函数
语法:reval = cv2.pyrUp(img)
参数:reval 表示向上取样结果;img 表示图像
效果:图像放大为原图的 4 倍,清晰度降低
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image.png", cv2.IMREAD_UNCHANGED)
# 向上取样
reval = cv2.pyrUp(img)
reval2 = cv2.pyrUp(reval)
# 显示图像
cv2.imshow("original", img)
cv2.imshow("reval", reval)
cv2.imshow("reval2", reval2)
cv2.waitKey(0)
cv2.destroyAllWindows()
在高斯金字塔的基础上构建
拉普拉斯金字塔处理的图像可进行复原操作
公式:Li = Gi - PyrUp( PyrDown( Gi ) )
参数:Gi 表示原始图像;Li 表示拉普拉斯金字塔图像 ;其中 Gi 和 Li 中的 i 表示层数
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 第 0 层拉普拉斯金字塔
imgd = cv2.pyrDown(img)
imgdu = cv2.pyrUp(imgd)
reval = img - imgdu
# 第 1 层拉普拉斯金字塔
imgd1 = imgd
img1d = cv2.pyrDown(imgd1)
img1du = cv2.pyrUp(img1d)
reval1 = imgd1 - img1du;
# 显示图像
cv2.imshow("original", img)
cv2.imshow("reval", reval)
cv2.imshow("reval1", reval1)
cv2.waitKey(0)
cv2.destroyAllWindows()
findContours() 函数
作用:查找图像轮廓
语法:image, contours,hierarchy = cv2.findContours(img, mode, method)
参数 | 说明 |
---|---|
image | 修改后的图像(二值化图像) |
contours | 图像轮廓 |
hierarchy | 图像的拓扑信息(轮廓层次) |
img | 原始图像 |
mode | 轮廓检索模式(详情查看下方表格) |
method | 轮廓的近似方法(详情查看下方表格) |
mode 检索轮廓模式:
常量 | 说明 |
---|---|
cv2.RETR_EXTERNAL | 只检测外轮廓 |
cv2.ERTR_LIST | 检测的轮廓不建立等级关系 |
cv2.RETR_CCOMP | 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内部哎呦一个连通物体,这个物体的边界,也在顶层 |
cv2.RETR_TREE | 建立一个等级树结构的轮廓 |
method 轮廓的近似方法:
常量 | 说明 |
---|---|
cv2.CHAIN_APPROX_NONE | 存储所有轮廓点,相邻的两个点的像素位置差不超过1,即 max(abs(x1-x2) , abs(y2-y1)) == 1 |
cv2.CHAIN_APPROX_SIMPLE | 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形只需要4个点来保持轮廓信息 |
cv2.CHAIN_APPROX_TC89_L1 | 使用 tehChinl chain 近似算法 |
cv2.CHAIN_APPROX_TC89_KCOS | 使用 teh-Chinl chain 近似算法 |
drawContours() 函数
作用:将查找到的轮廓,绘制到图像上
语法:reval = cv2.drawContours(img, contours, contourIdx, color [, thickness])
参数 | 说明 |
---|---|
reval | 绘制了轮廓的结果图像 |
img | 原始图像 |
contours | 需要绘制的边缘数组(轮廓) |
contourIdx | 需要绘制阿边缘索引,如果全部绘制则为 -1 |
color | 绘制的颜色,为 BGR 格式的 Scalar |
thickness | (可选)表示绘制的密度,即绘制轮廓时所使用的画笔粗细 |
import cv2
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image4.png", cv2.IMREAD_UNCHANGED)
# 彩色图像转为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 使用二进制阈值化处理,将灰度图像转为二值图像
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 查找轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
tmp = img.copy()
reval = cv2.drawContours(tmp, contours, -1, (0, 0, 255), 1)
# 显示图像
cv2.imshow("original", img)
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
灰度直方图中,横坐标表示图像中各个像素点的 灰度级 ,纵坐标表示具有该灰度级的像素 个数 ,例如 8 位位图中,灰度级是 0 至 255 ,即 256 个灰度级
归一化直方图中,横坐标表示图像中各个像素点的 灰度级 ,纵坐标表示出现这个灰度级的 概率
DIMS:使用参数的数量
dims=1 :灰度直方图,仅考虑灰度的情况(其它的可能是亮度等)
BINS:参数子集的数量
灰度级的数量,bins=256
也可是整合像素值之后的数量,如 0-15 为一组,16-31 为一组,即 bins=16
RANGE:统计灰度值的范围,一般为8位位图 [0, 255]
import matplot.pyplot as plt
hist 函数
功能:根据数据源和像素级绘制直方图
语法:hist(数据源, 像素级}
参数:数据源:图像,必须是一维数组;像素级:一般是 256,即 [0, 255]
ravel 函数
功能:将二维图像数据转换为一维图像数据
语法:reval = img.ravel()
import cv2
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 绘制直方图
plt.hist(img.ravel(), 256)
plt.show()
calcHist 函数
功能:计算默认横坐标为 [0, 255] 的灰度级,直接计算纵坐标灰度级的像素个数
语法:reval = cv2.calcHist(imgs, channels, mask, histSize, ranges, accumulate)
参数 | 说明 |
---|---|
reval | 直方图,二维数组(256行 1 列) |
imgs | 图像 |
channels | 指定通道;灰度图像 = [0],彩色图像=[0],[1],[2] 分别对应B,G,R |
mask | 掩码图像(仅计算某一部分图像);统计整幅图像的直方图,设为None;统计图像某一部分的直方图时,需要掩码图像 |
histSize | BINS的数量,如:[265] |
ranges | 像素值范围,如:[0, 255] |
accumulate | 累计标识;默认值为 false,如果为 true,则可计算多幅图像的直方图 |
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 统计直方图
reval = cv2.calcHist([img], [0], None, [256], [0, 255])
print(type(reval)) # 类型
print(reval.size) # 大小
print(reval.shape) # 形状
print(reval) # 直方图
import numpy as np
import matplotlib.pyplot as plt
# 创建范围为 0 - 5(不包括5),步长为 0.1
x = np.arange(0, 5, 0.1)
y = np.sin(x)
plt.plot(x, y)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
# X 轴数据
x = [0, 1, 2, 3, 4, 5]
# Y 轴数据
y = [2, 10, 30, 25, 10, 20]
# plt.plot(x, y) # 正常使用 X 轴和Y 轴的数据
# plt.plot(y) # 省略 X 轴数据
plt.plot(y, color='r') # 指定颜色
plt.show()
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录, 原图
img = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# 统计直方图
revalB = cv2.calcHist([img], [0], None, [256], [0, 255])
revalG = cv2.calcHist([img], [1], None, [256], [0, 255])
revalR = cv2.calcHist([img], [2], None, [256], [0, 255])
# 绘制直方图
plt.plot(revalB, color='b')
plt.plot(revalG, color='g')
plt.plot(revalR, color='r')
plt.show()
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 创建掩膜图像
# 值为 0 的全黑图像
mask = np.zeros(img.shape, np.uint8)
# 设置 200- 400 行,200 - 400 列为白色
mask[200:400, 200:400] = 255
# 统计直方图
revalM = cv2.calcHist([img], [0], mask, [256], [0, 255])
reval = cv2.calcHist([img], [0], None, [256], [0, 255])
#绘制直方图
plt.plot(revalM)
plt.plot(reval)
plt.show()
bitwise_and 函数
语法:reval = cv2.bitwise_and(img1, img2)
参数:reval 表示结果图像;img1 表示原始图像;img2 表示掩膜图像
import cv2
import numpy as np
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 创建掩膜图像
# 值为 0 的全黑图像
mask = np.zeros(img.shape, np.uint8)
# 设置 200- 400 行,200 - 400 列为白色
mask[200:400, 200:400] = 255
# 被掩膜后的图像
reval = cv2.bitwise_and(img, mask)
# cv2.imshow("mask", mask)
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
基础理论
前提:如果一副图像占有全部的灰度级,并且均匀分布
结论:该图像具有高对比度和多变的灰度色调
图像表现:图像细节丰富,质量更高
算法
下图中,为 3 位位图,灰度级位 1 - 7,首先进行统计直方图
equalizeHist 函数
语法:reval = cv2.equalizeHist(img)
参数:reval 表示结果图像;img 表示原始图像
import cv2
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 直方图均衡化
ravel = cv2.equalizeHist(img)
# 绘制直方图
plt.hist(img.ravel(), 256)
plt.show()
# plt.figure() # 创建新的图像
plt.hist(ravel.ravel(), 256)
plt.show()
import cv2
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 直方图均衡化
reval = cv2.equalizeHist(img)
cv2.imshow("img", img)
cv2.imshow("reval", reval)
cv2.waitKey(0)
cv2.destroyAllWindows()
subplot 函数
功能:同时显示多个窗口
语法:plt.subplot(nrows, ncols, plot_nuber)
参数:nrows 表示行数;ncols 表示列数;plot_number 表示窗口序号
特例:每个参数小于 10 时,可省略逗号,如:plt.subplot(234)
import cv2
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录, 灰度图
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 直方图均衡化
reval = cv2.equalizeHist(img)
# 1 行 2 列 序号 1
plt.subplot(121)
plt.hist(img.ravel(), 256)
# 1 行 2 列 序号 2
plt.subplot(122)
plt.hist(reval.ravel(), 256)
plt.show()
matplot.pyplot.imshow 函数
语法:plt.imshow(img, cmap=None)
参数:img 表示绘制的图像;cmap 表示 colormap;颜色图谱,默认RGB(A)
显示:灰度图像:cmap 默认通道为 RGB(A) ,需要使用参数 cmap=plt.cm.gray
;彩色图像:如果使用 opencv 读取图像,默认通道为 BGR,所以需要调整通道为 RGB(A)
import cv2
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
imgA = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
imgB = cv2.imread("image2.png", cv2.IMREAD_UNCHANGED)
# BGR to RGB
new_imgB = cv2.cvtColor(imgB, cv2.COLOR_BGR2RGB)
# 1 行 2 列 序号 1
plt.subplot(121)
plt.imshow(imgA, cmap=plt.cm.gray) # 灰度图
plt.axis('off') # 关闭坐标轴
# 1 行 2 列 序号 2
plt.subplot(122)
plt.imshow(new_imgB)
plt.axis('off') # 关闭坐标轴
plt.show()
import cv2
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 直方图均衡化
equ = cv2.equalizeHist(img)
# 2 行 2 列 序号 1
plt.subplot(221)
plt.imshow(img, cmap=plt.cm.gray)
plt.axis('off') # 关闭坐标轴
# 2 行 2 列 序号 2
plt.subplot(222)
plt.imshow(equ, cmap=plt.cm.gray)
plt.axis('off') # 关闭坐标轴
# 2 行 2 列 序号 3
plt.subplot(223)
plt.hist(img.ravel(), 256)
# 2 行 2 列 序号 4
plt.subplot(224)
plt.hist(equ.ravel(), 256)
plt.show()
**任何连续周期信号,可以由一组适当的正弦曲线组合而成。— 傅里叶 **
时间:动态
频率:静态
相位:时间差,不是同时开始的一组余弦函数,在叠加时要体现开始的时间
下图中,将复杂的时间角度正弦函数图像,转换为简洁的频率角度的图像,相互可逆
numpy.fft.fft2 函数
功能:实现傅里叶变换,返回一个复数数值(Complex ndarray)
numpy.fft.fftshift 函数
功能:将零频率分量移到频谱中心;将傅里叶变换后的结果(频谱)中左上角的低频移动到中心点
np.log 函数
功能:设置频谱的范围,如将傅里叶变换的结果映射到 [0, 255] 区间,使得频谱图像可以显示
语法:20 * np.log( np.abs(fshift) )
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 计算傅里叶变换
fnum = np.fft.fft2(img)
# 移动低频到中心点
fshift = np.fft.fftshift(fnum)
# 频谱映射区间
reval = 20 * np.log(np.abs(fshift))
# 1 行 2 列 序号 1
plt.subplot(121)
plt.imshow(img, cmap=plt.cm.gray)
plt.title('original')
plt.axis('off') # 关闭坐标轴
# 1 行 2 列 序号 2
plt.subplot(122)
plt.imshow(reval, cmap=plt.cm.gray)
plt.title('reval')
plt.axis('off') # 关闭坐标轴
plt.show()
完整过程:原始图像 --> 得到图像频谱 --> 处理最高频、最低频信息 --> 还原图像
如果只保留低频信息,即为低通滤波,去除边界;如果只保留高频信息,即为高通滤波,保留边界,细节模糊
numpy.fft.ifft2 函数
功能:实现逆傅里叶变换,返回一个复数数组(complex ndarray)
numpy.fft.ifftshift 函数
功能:fftshift 函数的逆函数
np.abs(ifftshift)
功能:设置值的范围,如 [0, 255]
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 计算傅里叶变换
fnum = np.fft.fft2(img)
# 移动低频到中心点
fshift = np.fft.fftshift(fnum)
# 移动低频到左上角
ishift = np.fft.ifftshift(fshift)
# 逆傅里叶变换
img2 = np.fft.ifft2(ishift)
# 频谱映射区间 (绝对值)
reval = np.abs(img2)
# 1 行 2 列 序号 1
plt.subplot(121)
plt.imshow(img, cmap=plt.cm.gray)
plt.title('original')
plt.axis('off') # 关闭坐标轴
# 1 行 2 列 序号 2
plt.subplot(122)
plt.imshow(reval, cmap=plt.cm.gray)
plt.title('reval')
plt.axis('off') # 关闭坐标轴
plt.show()
低频对应图像内变化缓慢的灰度分量,颜色趋于一致
高频对应图像内变化越来越快的灰度分量,由灰度的尖锐过渡造成
滤波:接受(通过)或拒绝一定频率的分量
低通滤波器:通过低频的滤波器;即衰减高频而通过低频,将模糊一幅图像
高通滤波器:通过高频的滤波器;即衰减低频而通过高频,将增强尖锐的细节,导致图像对比度减低
频域滤波
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 计算傅里叶变换
fnum = np.fft.fft2(img)
# 移动低频到中心点
fshift = np.fft.fftshift(fnum)
# 高频滤波器:将低频信息设置为 0
rows,cols = img.shape # 形状
crows, ccols = int(rows/2),int(cols/2) # 中心点
fshift[crows-10:crows+10, ccols-10:ccols+10] = 0 # 中心点+10 的正方形范围的频率设置为 0
# 移动低频到左上角
ishift = np.fft.ifftshift(fshift)
# 逆傅里叶变换
img2 = np.fft.ifft2(ishift)
# 频谱映射区间 (绝对值)
reval = np.abs(img2)
# 1 行 2 列 序号 1
plt.subplot(121)
plt.imshow(img, cmap=plt.cm.gray)
plt.title('original')
plt.axis('off') # 关闭坐标轴
# 1 行 2 列 序号 2
plt.subplot(122)
plt.imshow(reval, cmap=plt.cm.gray)
plt.title('reval')
plt.axis('off') # 关闭坐标轴
plt.show()
dft 函数
语法:reval = cv2.dtf(img, flags)
参数 | 说明 |
---|---|
reval | 返回结果,双通道,第一个通道是实数部分,第二个通道是虚数部分 |
img | 图像,需要转换为 np.float32 格式 |
flags | 转换标识; flags=cv2.DFT_COMPLEX_OUTPUT,输出一个复数阵列(振幅、频率) |
magnitude 函数
功能:计算幅值
语法:reval = cv2.magnitude(p1, p2)
参数:p1 表示浮点型 X 坐标值,实数部分;p2 表示浮点型 Y 坐标值,虚数部分
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 计算傅里叶变换
fnum = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
# 移动低频到中心点
fshift = np.fft.fftshift(fnum)
# 计算幅值 # 0 通道,1 通道
reval = 20 * np.log(cv2.magnitude(fshift[:,:,0], fshift[:,:,1]))
# 1 行 2 列 序号 1
plt.subplot(121)
plt.imshow(img, cmap=plt.cm.gray)
plt.title('original')
plt.axis('off') # 关闭坐标轴
# 1 行 2 列 序号 2
plt.subplot(122)
plt.imshow(reval, cmap=plt.cm.gray)
plt.title('reval')
plt.axis('off') # 关闭坐标轴
plt.show()
idft 函数:
功能:逆傅里叶变换
语法:reval = cv2.idft(idata)
参数:reval 表示返回结果,取决于原始数据的类型和大小;idata 表示原始数据,实数或虚数均可
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 计算傅里叶变换
fnum = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
# 移动低频到中心点
fshift = np.fft.fftshift(fnum)
# 移动低频到左上角
ishift = np.fft.ifftshift(fshift)
# 逆傅里叶变换
img2 = cv2.idft(ishift)
# 计算幅值 # 0 通道,1 通道
reval = cv2.magnitude(img2[:,:,0], fshift[:,:,1])
# 1 行 2 列 序号 1
plt.subplot(121)
plt.imshow(img, cmap=plt.cm.gray)
plt.title('original')
plt.axis('off') # 关闭坐标轴
# 1 行 2 列 序号 2
plt.subplot(122)
plt.imshow(reval, cmap=plt.cm.gray)
plt.title('reval')
plt.axis('off') # 关闭坐标轴
plt.show()
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图片-与python文件相同目录
img = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
# 计算傅里叶变换
fnum = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
# 移动低频到中心点
fshift = np.fft.fftshift(fnum)
# 构建低通滤波图像
rows, cols = img.shape
crows, ccols = int(rows/2),int(cols/2) # 中心点
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crows-10:crows+10, ccols-10:ccols+10] = 1
fshift = fshift * mask
# 移动低频到左上角
ishift = np.fft.ifftshift(fshift)
# 逆傅里叶变换
img2 = cv2.idft(ishift)
# 计算幅值 # 0 通道,1 通道
reval = cv2.magnitude(img2[:,:,0], fshift[:,:,1])
# 1 行 2 列 序号 1
plt.subplot(121)
plt.imshow(img, cmap=plt.cm.gray)
plt.title('original')
plt.axis('off') # 关闭坐标轴
# 1 行 2 列 序号 2
plt.subplot(122)
plt.imshow(reval, cmap=plt.cm.gray)
plt.title('reval')
plt.axis('off') # 关闭坐标轴
plt.show()
问题:PyCharm 编辑器中无法使用 Ctrl+C 和 Ctrl+V 进行复制和粘贴的快捷键操作
原因:安装和正在使用 vim 插件
解决方法:关闭 vim 插件
File – Settings… – Plugins – Installed 选项卡 – 取消 Idea Vim 的勾选 – 点击 Apply 按钮
重启编辑器