OpenCV笔记

OpenCV笔记(入门基础版本)

强力安利:李老师openCV 教程 不枯燥 很基础 很易懂(无恰饭!!!!)
课程 https://edu.csdn.net/course/detail/10552

# -*- coding:utf-8 -*-

import cv2
import numpy as np
import matplotlib.pyplot as plt


#---------------------------------- 入门基础 ----------------------------------#
#导入图像
img = cv2.imread("位置", cv2.IMREAD_UNCHANGED)        #cv2.IMREAD_UNCHANGED 不改变读取
img1 = cv2.imread("位置", cv2.IMREAD_COLOR)           #cv2.IMREAD_COLOR  彩色读取
img2 = cv2.imread("位置", cv2.IMREAD_GRAYSCALE)       #cv2.IMREAD_GRAYSCALE 灰色读取

#显示图像
cv2.imshow("窗口名", img)
#显示时间
cv2.waitKey('参数')  #参数>0:等待多少毫秒 参数<0:等待键盘单击 参数=0:无线等待 也可以不填
#删除所有窗口(内存释放)
cv2.destroyAllWindows()
#保存图像
cv2.imwrite('位置+文件名', img)


#---------------------------------- 图像处理基础 ----------------------------------#
#openCV读取灰度图像88行,142列的像素
print(img[88, 142])
#openCV读取BGR图像88行,142列,Blue通道的值
print(img[88, 142, 0])
#openCV读取BGR图像88行,142列的像素值
print(img[88, 142])
#openCV灰度图像100到120行,90到240列部分 像素赋值为255
img[100:120, 90:240] = 255
#openCV BGR图像100到120行,90到240列部分 像素赋值为BGR[255, 255, 255]
img[100:120, 90:240] = [255, 255, 255]
#openCV BGR图像100到120行,90到240列部分 blue通道为140
img[100:120, 90:240, 0] = 140
#numpy读取灰度图像88行,142列的像素
print(img.item(88, 142))
#numpy读取BGR图像88行,142列,Blue通道的值
print(img.item(88, 142, 0))
#numpy 灰度图像88行,142列修改为255
img.itemset((88, 142), 255)
#numpy BGR图像88行,142列B通道修改为255
img.itemset((88, 142, 0), 255)
#获取像素大小
print(img.shape) #灰度图像得到一个元组类型的(512, 512)
                 #彩色图像得到一个一个元组类型(512, 234, 3)  有三个通道
#计算图像像素点
print(img.size)
#查看图像数据类型
print(img.dtype)
#openCV 读取图像200:400 行, 300:500列区域
face = img[200:400, 300:500]
#numpy创建一个BGR图像
roi = np.ones((100, 200, 3))
#拆分通道   每个通道单独显示的时候,显示出来是个灰度图
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
b, g, r = cv2.split(img)
b = cv2.split(img)[0]
g = cv2.split(img)[1]
r = cv2.split(img)[2]
#通道合并
img_merge = cv2.merge([b, g, r])    #记得顺序!!BGR, 拆分与合并顺序相同


#---------------------------------- 图像运算 ----------------------------------#
#numpy加法            取模加法
img = img1 + img2
#opencv加法           饱和运算
img = cv2.add(img1, img2)
#图像融合
result = cv2.addWeighted(img1, 0.3, img2, 0.8, 56)   #img1权重0.3, img2权重0.8 合成后图像调节亮度为56


#---------------------------------- 类型转换 ----------------------------------#
#BGR变成灰度
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#BGR变成RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#BGR变成HSV
img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
#灰度变成BGR
img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)


#---------------------------------- 几何变换 ----------------------------------#
#图像缩放
dst = cv2.resize(img, (122, 233))   #缩放成233行*122列行图像!!!
dst = cv2.resize(img, None, fx=0.5, fy=1.8)   #水平为以前0.5倍,竖着方向为1.8倍, 这种写法必须要写None替代上一种写法的位置
#图像翻转
flipCode = 0 #整个图像旋转180度
flipCode > 0 #左右对称翻转
flipCode < 0 #关于原点翻转
dst = cv2.flip(img, flipCode)


#---------------------------------- 阈值分割 ----------------------------------#
#retval, dst = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
#阈值, 处理后结果 = cv2.threshold(灰色源图像, 阈值, 最大值"图像在大于这个值,会使其变为这个值", 处理类型)
#二进制阈值化     亮的处理为白色,暗的处理为黑色
ret, dst = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
#反二进制阈值化    亮的处理为黑色,暗的处理为白色
ret, dst = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
#截断阈值化      小于的不管他 把太亮的处理我阈值
ret, dst = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
#阈值化为0       比较暗的直接变为0, 亮一点的不变
ret, dst = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
#反阈值化为0     比较亮的直接变为0, 暗一点的像素不变
ret, dst = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)


#---------------------------------- 图像平滑处理 ----------------------------------#
#均值滤波(去椒盐, 也可以把图像变模糊)   被计算的那个像素 = 周围"核大小"个像素的平均值
#结果 = cv2.blur(灰色源图像, 核)
dst = cv2.blur(img, (5, 5))
#方框滤波(特殊的均值滤波,关键在于是否需要平均值)
#结果 = cv2.boxFilter(灰色源图像, 图像深度, 核, normalize=?)
dst = cv2.boxFilter(img, -1, (5, 5), normalize=1)   #-1表示图像深度与原图相同
                                                    #normalize = 1的时候归一化处理的(均值滤波一样)
                                                    #normalize=0 不进行归一化处理(不取平均值,直接加起来) 可能像素会溢出
                                                    #变成全255,全白
#高斯滤波(加权不归一化的均值滤波, 但核要奇数!!!)
#结果 = cv2.GaussianBlur(灰色源图像, 核, X方向方差"为0时自动计算,Y方向其实也有方差 与X方向一致")
dst = cv2.GaussianBlur(img, (5, 5), 0)
#中值滤波(滤波效果相对较好,处理离奇的点非常好, 但核要大于1的奇数!!)     被计算的那个像素 = 周围"核大小"排序中间那个值
#结果 = cv2.medianBlur(灰色源图像, 核大小)
dst = cv2.medianBlur(img, 5)


#---------------------------------- 形态学处理 ----------------------------------#
#形态学操作 全是 二值图像
#图像腐蚀(被腐蚀部分(白色部分)边沿变小) 核中心那个点 = 核覆盖有黑即黑 全白即白
#结果 = cv2.erode(灰色源图像, 核(一般正方形), 迭代次数(效果不好可以多加, 默认为1,可不写))
kernel = np.ones((5, 5), np.uint8)
dst = cv2.erode(img, kernel, iterations=1)
#图像膨胀(被膨胀部分(白色部分)边沿边大) 核中心那个点 = 核覆盖有白即白 全黑即黑
#结果 = cv2.dilate(灰色源图像, 核, 迭代次数)
dst = cv2.dilate(img, kernel, iterations=1)
#开运算(先腐蚀,再膨胀,去黑色内白色噪)
#结果 = cv2.morphologyEx(灰度图像, cv2.MORPH_OPEN, 核)
dst = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
#闭运算(先膨胀,再腐蚀,去白色内小黑点)
dst = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
#梯度运算 结果 = 膨胀后-腐蚀后 ==>得到轮廓信息图像
dst = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
#顶帽运算  结果 = 原图 - 开运算图 ==>得到黑色内白色噪声的图像
dst = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
#黑帽运算 结果 = 闭运算 - 原图 ==>得到图像当中白色内部的小黑点
dst = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)


#---------------------------------- 图像梯度 ----------------------------------#
#Soble算子(121)计算边界、轮廓        若X方向Soble算子:P5new = p3-p1 + 2(p6-p4) + p9-p7
#结果 = cv2.Sobel(灰度原图像,图像深度,dx = ?(等于1要计算x方向), dy = ?(等于1 要计算y方向), 核大小(默认不写为 3)当
#                                                                       写 -1 时候 用了改进Soble算子 就是 Scharr算子)
dst = cv2.Sobel(img, cv2.CV_64F, 0, 1)
dst = cv2.convertScaleAbs(dst)          #注意:    图像深度要用这两步,因为方向 如果uint8(写-1)类型
                                        #只能得到一个边 那就是右边和下边 要用这种才完全,这种是绝对值算法
                                        #先类型变大 64位float 有+有- ,再转回uint8(第二个函数)
#Soble算子最好的写法:
dstx = cv2.sobel(img, cv2.CV_64F, 1, 0)   #注意       更好的提取边界 不是同时dx = 1, dy = 1,
dsty = cv2.sobel(img, cv2.CV_64F, 0, 1)   #而是分开算后来用cv2.addWeighted合并
dstx = cv2.convertScaleAbs(dstx)
dsty = cv2.convertScaleAbs(dsty)
result = cv2.addWeighted(dstx, 0.5, dsty, 0.5, 0)
#Scharr算子(3103) 与Soble算子 算子不一样其他一样       能够计算更小的梯度 更灵敏
#结果 = cv2.Scharr(灰度源图像, 图像深度, dx = ?, dy = ?) !!!! 必须dx + dy = 1,不然报错
dstx = cv2.Scharr(img, cv2.CV_64F, 0.5, 0.5)
#Scharr最好写法
dstx = cv2.Scharr(img, cv2.CV_64F, 1, 0)
dsty = cv2.Scharr(img, cv2.CV_64F, 0, 1)
dstx = cv2.convertScaleAbs(dstx)
dsty = cv2.convertScaleAbs(dsty)
dst = cv2.addWeighted(dstx, 0.5, dsty, 0.5, 0)
#Laplacian算子    P5new = p2+p4+p6+p8-4p5   ==>二阶算子 上面两个都是一阶
#结果 = cv2.Laplacian(灰度源图, 图像深度(默认-1))
dst = cv2.Laplacian(img, cv2.CV_64F)
dst = cv2.convertScaleAbs(dst)


#---------------------------------- Canny边缘检测 ----------------------------------#
#canny边缘检测 步骤:去噪(高斯kernel = 5x5)->
#                       梯度(Soble算子,但是xy不分开算,并且梯度算法不一样,)->
#                       非极大值抑制(同一个方向最大值被保留,成为边缘,其它为0)->
#                       滞后阈值如果大于大阈值,保留,小于小阈值 去掉
#                       在两个中间的点,与大阈值内的点相连的就保留,阈值越小,边缘越细腻
#边缘检测结果 = cv2.Canny(img, '小阈值', '大阈值')
dst = cv2.Canny(img, 100, 200)


#---------------------------------- 图像金字塔 ----------------------------------#
#向下取样:分辨率变小,5*5的核以一定权重先卷积(高斯法),再删除得到图像的偶数行偶数列
#向下取样不可逆
#结果 = cv2.pyrDown(源灰度图像)   这样取样一次得到原图1/4
dst = cv2.pyrDown(img)
#向上取样:分辨率变大,先像素新增一倍的行和列(全为0),再把每个像素乘以4,再5*5的核卷积
#结果 = cv2.pyrUp(源灰度图像)  这样取样一次得到原图的4倍
dst = cv2.pyrUp(img)
#向上取样不可逆
#拉普拉斯金字塔    拉普拉斯金字塔 = 原图 - 向上取样(向下取样)
#x层拉普拉斯金字塔 = 向下x层的图 - 向上取样(向下取样x+1层的图)
#算2层拉普拉斯金字塔         没有函数,只有手动
dst1 = cv2.pyrDown(img)
dst2 = cv2.pyrDown(dst1)
dst3 = cv2.pyrDown(dst2)
dst = cv2.pyrUp(dst3)
lplas2 = dst2 - dst


#---------------------------------- 图像轮廓 ----------------------------------#
#轮廓 = 边缘连接成的一个整体
#轮廓连续 边缘不连续
#轮廓是!!!!!!二值图像 OpenCV是黑色为背景色 前景色为白色
#轮廓检测
#原始图像的二值化图像,轮廓图像,轮廓层次 = cv.findContours(灰度源图像, 轮廓检索模式, 轮廓近似方法)
img, cont, hier = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
#轮廓绘制
#结果 = cv2.drawContours(原图, 轮廓图像数组, 需要绘制的边缘索引(就是有好多个边沿)(从0开始,
#                       全部则写-1), 绘制的颜色元组), 绘制的密度(默认不写))
res = cv2.drawContours(img, cont, -1, (0, 0, 255), 1)
#图像轮廓最好写法
org = cv2.imread("E:\\desktop.Lena.jpg", cv2.IMREAD_UNCHANGED)
gray = cv2.cvtColor(org, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
img, cont, hier = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
orgcopy = org.copy()
res = cv2.drawContours(orgcopy, cont, -1, (0, 0, 255), 1)


#---------------------------------- 直方图 ----------------------------------#
#matplotlib绘制直方图    必须是先转一维数组图像
#二位灰度图转一维数组
org = img.ravel()
#画直方图
#plt.hist(一维数组, 灰度级)
plt.hist(org, 256)
plt.show()
#openCV统计直方图信息
#直方图y轴数组 = cv.calcHist([原图], [通道], 掩码(图像一部分), [灰度级], [像素值范围], 几个图的时候是否累计(一般不写,默认Flase))
hist = cv2.calcHist([img], [0], None, [256], [0,255])
#openCV绘直方图
hist = cv2.calcHist([img], [2], None, [256], [0,255])
plt.plot(hist, color='r')
plt.show()
#掩膜直方图 结果 = 原图 & 掩膜
#生成掩膜
#掩膜 = np.uint8(灰度图.shape, np.uint8)
mask = np.uint8(img.shape, np.uint8)
mask[200:400, 200:400] = 255
hist = cv2.calcHist([img], [0], mask, [256], [0, 255])
plt.hist(hist, color='r')
plt.show()
#掩膜操作
#结果 = cv2.bitwise_and(图像, 掩膜)
mask = np.zeros((500, 500), np.uint8)
mask[200:400, 200:400] = 255
res = cv2.bitwise_and(img, mask)
#直方图均值化(让色彩更均衡(来源于合并) 更自然 细节更丰富) 先直方图归一化 再累计直方图 再X灰度级 灰度级更少了(四舍五入的功劳)
#得到图像 = cv2.equalizeHist(源图像)
res = cv2.equalizeHist(img)
#subplot画图
#plt.subplot(多少行, 多少列, 第多少个窗口)
plt.subplot(1, 2, 1)
plt.hist(img.ravel(), 256)
plt.subplot(1, 2, 2)
plt.hist(gray.ravel(), 256)
plt.show()
#matplot.pyplot.imshow函数
#openCV读进来的图像是BGR 用这个显示的时候先要BGR2RGB
#plt.imshow('灰度图像', cmap =plt.cm.gray)  或者cmap = 'gray'
plt.title('img')
plt.imshow(img)
plt.axis('off')     #关闭坐标轴显示
plt.show()


#---------------------------------- 傅里叶变换 ----------------------------------#
#有     时域 频域    两个空间
#numpy实现傅里叶变换 得到频谱
#复数数组 = np.fft.fft2(灰度图像)
f = np.fft.fft2(img)
#低频到中心位置
#复数数组 = np.fft.fft2(上一步复数数组)
fshift = np.fft.fftshift(f)
#复数数组转成可显示的灰度图
result = 20*np.log(np.abs(fshift))
#numpy傅里叶!!!逆!!!变换
img = np.fft.ifft2(fshift)
img = np.abs(img)
#低频 图像内变换比较慢的灰度分量
#高频 图像内变化比较快的灰度分量
#numpy高通滤波:增强尖锐细节
f = np.fft.fft2(img)    #傅里叶变换
fshift = np.fft.fftshift(f)     #边缘移到中心
rows, cols = img.shape()
crows, ccols = int(rows/2), int(cols/2)
fshift[crows - 30:crows + 30, ccols - 30: ccols + 30] = 0
ifshift = np.fft.ifftshift(fshift)      #从中心移到边缘
res = np.fft.ifft2(ifshift)     #傅里叶逆变换
res = np.abs(res)   #绝对值变成可显示图像
#低通滤波:增强尖锐细节
#openCV傅里叶变换
#返回结果(双通道:1通道实数部分,2通道虚数部分) = cv2.dft(原始图像(np.float32),转换标识)
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
#复数列变成实数  分别平方再开根
#cv2.magnitude('实数', '虚数')
cv2.magnitude(dft[:, :, 0], dft[:, :, 1])
#傅里叶变换写法
org = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dft = cv2.dft(np.float32(org), flags=cv2.DFT_COMPLEX_OUTPUT)
dshift = np.fft.fftshift(dft)
result = 20*np.log(cv2.magnitude(dshift[:, :, 0], dshift[:, :, 1]))
cv2.imshow('result', result)
#openCV傅里叶逆变换
#返回结果 = cv2.idft(原始图像)
idft = cv2.idft(dft)
img = cv2.magnitude(idft[:, :, 0], idft[:, :, 1])
#openCV低通滤波:模糊图像
dst = cv2.dft(np.float(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dshift = np.fft.fftshift(dst)
rows , cols = img.shape()
crows, ccols = int(rows/2), int(cols/2)
mas = np.zeros((crows, ccols, 2), np.uint8)
mas[crows-30:crows+30, ccols-30:ccols+30] = 1
md = cv2.bitwise_and(dshift, mas)
imd = np.fft.ifft2(md)
res = cv2.idft(imd)
res = cv2.magnitude(res[:, :, 0], res[:, :, 1])

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值