原创

基于python的OpenCV图像处理学习笔记


基于python的OpenCV图像处理学习笔记

打开.ipynb文件

  • 打开anaconda prompt
  • 输入jupyter notebook
  • 找到文件打开即可

1. 图像简介与图像的基本操作

  • 图像由很多的小方格组成(像素)
  • 彩色图像每个像素有三个通道RGB,每个通道对应一个值(0-255)
import cv2 #opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np


# 读取数据
img = cv2.imread('./image/cat.jpg')
# print(img)

# 图像的显示,也可以创建多个窗口
# cv2.imshow('image', img)
# # 等待时间,毫秒级,0表示任意键终止
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 图形的大小(像素)和通道
# print(img.shape)

# 灰度处理
# img=cv2.imread('./image/cat.jpg', cv2.IMREAD_GRAYSCALE)
# cv2.imshow('cat',img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# print(img.shape)
#
# # 图像保存
# cv2.imwrite('./image/gray_cat.jpg', img)
#
# # 图像信息
# print(type(img)) # <class 'numpy.ndarray'>
# print(img.size) # (398, 600) = 238800
# print(img.dtype) # uint8

# 读取视频
# vc = cv2.VideoCapture('./image/test.mp4')
# # 检查是否打开正确
# if vc.isOpened():
#     open, frame = vc.read()
# else:
#     open = False
#
# # 能正常打开
# while open:
#     ret, frame = vc.read()
#     if frame is None:
#         break
#     if ret == True:
#         gray = cv2.cvtColor(frame,  cv2.COLOR_BGR2GRAY)
#         cv2.imshow('result', gray)
#         if cv2.waitKey(100) & 0xFF == 27: # 每隔0.1s刷新一次(越小播放越快) 退出键Esc退出
#             break
# # 释放资源
# vc.release()
# cv2.destroyAllWindows()

# 截取部分图像数据
# 声明图形显示方法
def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 只取到了50*200的图像部分
# cat=img[0:50,0:200]
# cv_show('cat',cat)

# 颜色通道提取
# b,g,r=cv2.split(img)
# print(b)
# print(b.shape)

# 合并图像
# img=cv2.merge((b,g,r))
# print(img.shape)

# 只保留R
# cur_img = img.copy()
# print(img)
#
# # bgr分别对应0,1,2 cur_img[:,:,0]的意思为任意行,任意行内的任意像素点(列),的第一个值(B)为0
# cur_img[:,:,0] = 0 #B
# cur_img[:,:,1] = 0 #G
# print(cur_img)
# cv_show('R',cur_img)
#
# # 只保留G
# cur_img = img.copy()
# cur_img[:,:,0] = 0
# cur_img[:,:,2] = 0
# cv_show('G',cur_img)
#
# # 只保留B
# cur_img = img.copy()
# cur_img[:,:,1] = 0
# cur_img[:,:,2] = 0
# cv_show('B',cur_img)


# 边界填充

# BORDER_REPLICATE:复制法,也就是复制最边缘像素。
# BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb
# BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
# BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg
# BORDER_CONSTANT:常量法,常数值填充。

# 设置填充的值
# top_size,bottom_size,left_size,right_size = (50,50,50,50)
# # 填充的边界模糊的
# replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
# # 镜像填充
# reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_REFLECT)
# # 稍加模糊的镜像填充
# reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
# wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
# constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)


# 数值计算
# img_cat=cv2.imread('./image/cat.jpg')
# img_dog=cv2.imread('./image/dog.jpg')
#
# img_cat2= img_cat +10
# print(img_cat[:5,:,0]) # 只显示5行,和B的值
# print(img_cat2[:5,:,0])
#
# # 0-255越界,相当于% 256
# print((img_cat + img_cat2)[:5,:,0] )
#
# # add则不会越界,最大就为255
# print(cv2.add(img_cat,img_cat2)[:5,:,0])

# 图像融合
# 融合的前提 两张图像的shape要一致
# img_cat=cv2.imread('./image/cat.jpg')
# img_dog=cv2.imread('./image/dog.jpg')
# print(img_cat.shape)
# print(img_dog.shape)
#
# # 修改shape
# img_dog = cv2.resize(img_dog, (600, 398))
# print(img_dog.shape)
#
# # 按照权重融合(权重越大越明显)
# res = cv2.addWeighted(img_cat, 0.2, img_dog, 0.8, 0)
# cv_show('res',res)


# 设置图像宽高比例
# 正方形(默认总高或宽为2000)
res = cv2.resize(img, (0, 0), fx=4, fy=4)
cv_show('res',res)# 2000*2000

res = cv2.resize(img, (0, 0), fx=2, fy=1)
cv_show('res',res) # 1000*500

res = cv2.resize(img, (500, 250), fx=2, fy=1)
cv_show('res',res) # 500*250

2.图像处理

# 图像处理
import cv2
import numpy as np

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# 灰度图
img= cv2.imread('./image/cat.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
# print(img_gray.shape)
# cv_show('img_gray',img_gray)
#
# #HSV
# # H - 色调(主波长)
# # S - 饱和度(纯度/颜色的阴影)。
# # V值(强度)
#
# hsv = cv2.cvtColor(img,cv2.COLOR_RGB2HSV)
# cv_show('hsv',hsv)

# 图像阈值
# ret, dst = cv2.threshold(src, thresh, maxval, type)
# src: 输入图,只能输入单通道图像,通常来说为灰度图
# dst: 输出图
# thresh: 阈值
# maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
# type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
# cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
# cv2.THRESH_BINARY_INV THRESH_BINARY的反转
# cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
# cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
# cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
# 0为黑,255为白

# ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# cv_show('thresh1',thresh1)
# ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
# cv_show('thresh2',thresh2)
# ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
# cv_show('thresh3',thresh3)
# ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
# cv_show('thresh4',thresh4)
# ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
# cv_show('thresh5',thresh5)

# 图像滤波(平滑处理)
# 去除噪声
img = cv2.imread('./image/lenaNoise.png')
cv_show('noise',img)
# img = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
#
# # 均值滤波
# # 矩阵全部相加除以个数,求平均
# print(img)
blur = cv2.blur(img,(3,3))
# cv_show('blur',blur)
# print('===============')
# print(blur)


# 方框滤波
# 基本和均值一样,可以选择归一化, -1 得到的结果和原始通道数表示一致,normalize归一化(求平均)
# box = cv2.boxFilter(img,-1,(3,3), normalize=True)
# cv_show('box',box)
#
#
# # 不求平均,全部加起来,越界值如果大于255,就设置为255
# box = cv2.boxFilter(img,-1,(3,3), normalize=False)
# cv_show('box',box)

# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的(更重视相邻的(上下左右)),乘以权重
aussian = cv2.GaussianBlur(img, (3, 3), 1)
# cv_show('aussian',aussian)


# 中值滤波
# 相当于用中值代替
# 排序后取中间值,作为结果 5表示5*5
# 去噪声效果最好
median = cv2.medianBlur(img, 5)  # 中值滤波
# cv_show('median', median)


# 展示所有的
# np.hstack横向显示,np.stack纵向显示
res = np.hstack((blur,aussian,median))
#print (res)
cv_show('median vs average', res)


3. 形态学基本操作

import cv2
import numpy as np

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 形态学-腐蚀操作
# 腐蚀就是将白的边缘变黑一点,kernel数组越大,腐蚀面积越大
img = cv2.imread('./image/dige.png')
# cv_show('dige',img)
#
# kernel = np.ones((3,3), np.uint8) # ones返回一个全1的n维数组,这里返回3*3,np.uint8为数据类型
# erosion = cv2.erode(img,kernel,iterations = 1) # iterations = 1表示迭代一次
# cv_show('erosion',erosion)
#
#
pie = cv2.imread('./image/pie.png')
# cv_show('pie',pie)
# # 验证迭代次数,迭代次数越多,白色的圆圈越小,并且不在是园形了
# kernel = np.ones((30,30),np.uint8)
# erosion_1 = cv2.erode(pie,kernel,iterations = 1)
# erosion_2 = cv2.erode(pie,kernel,iterations = 2)
# erosion_3 = cv2.erode(pie,kernel,iterations = 3)
# res = np.hstack((erosion_1,erosion_2,erosion_3))
# cv_show('res',res)


# 形态学-膨胀操作
# kernel = np.ones((3,3), np.uint8)
# dige_erosion = cv2.erode(img,kernel,iterations = 1)
# cv_show('dige_erosion',dige_erosion)
# # 膨胀则为将白色边缘扩大
# kernel = np.ones((3,3),np.uint8)
# dige_dilate = cv2.dilate(dige_erosion,kernel,iterations = 1)
# cv_show('dilate', dige_dilate)
#
# kernel = np.ones((30,30),np.uint8)
# dilate_1 = cv2.dilate(pie,kernel,iterations = 1)
# dilate_2 = cv2.dilate(pie,kernel,iterations = 2)
# dilate_3 = cv2.dilate(pie,kernel,iterations = 3)
# res = np.hstack((dilate_1,dilate_2,dilate_3))
# cv_show('res', res)

# 开运算
# 先进行腐蚀,再进行膨胀
# kernel = np.ones((3,3),np.uint8)
# opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
# cv_show('opening', opening)
#
# # 闭运算
# # 先进行膨胀,再进行腐蚀
# kernel = np.ones((3,3),np.uint8)
# closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# cv_show('closing', closing)

# 梯度运算
# 梯度 = 膨胀 - 腐蚀
# kernel = np.ones((7,7),np.uint8)
# dilate = cv2.dilate(pie,kernel,iterations = 5)
# erosion = cv2.erode(pie,kernel,iterations = 5)
# res = np.hstack((dilate,erosion))
# cv_show('res', res)
# # 剩下膨胀出来的部分
# gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
# cv_show('gradient', gradient)


# 礼帽和黑帽
# 礼帽 = 顶帽 = 原始输入-开运算结果
kernel = np.ones((7,7),np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
cv_show('tophat', tophat)

# 黑帽 = 闭运算-原始输入
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv_show('blackhat', blackhat)


4. 梯度处理

import cv2
import numpy as np


def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# 图像梯度-Sobel算子
# dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
# ddepth:图像的深度(输入输出一样)
# dx和dy分别表示水平和竖直方向 dx :右边-左边,中间为0  dy:上边-下边,中间0
# ksize是Sobel算子的大小


# img = cv2.imread('./image/pie.png')
# cv_show('pie',img)
#
# sobelx = cv2.Sobel(img,cv2.CV_64F,1,0, ksize=3)
# sobelx = cv2.convertScaleAbs(sobelx)
# cv_show('sobelx',sobelx)
#
# sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
# cv_show('sobely',sobely)
#
# sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
# cv_show('sobelxy',sobelxy)

# 分开计算合并
# img = cv2.imread('./image/lena.jpg',cv2.IMREAD_GRAYSCALE)
# sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
# # 绝对值
# sobelx = cv2.convertScaleAbs(sobelx)
# sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
# sobely = cv2.convertScaleAbs(sobely)
# sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
# cv_show('sobelxy',sobelxy)
#
# # 直接计算效果更差
# sobelxy = cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
# sobelxy = cv2.convertScaleAbs(sobelxy)
# cv_show('sobelxy',sobelxy)

# scharr算子
# 核变大了,结果更敏感一些


# laplacian算子
#0 1 0
#1 -4 1
#0 1 0

# 中间点与中间的的四周


#不同算子的差异
img = cv2.imread('./image/lena.jpg',cv2.IMREAD_GRAYSCALE)

# 边界
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)

# 更加敏感,更细致
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0)


# 效果较差
laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)

res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show('res',res)
图像处理
  • 作者:曾强(联系作者)
  • 发表时间:2020-03-23 16:51
  • 版权声明:自由转载-非商用-非衍生-保持署名
  • 转载声明:转载时请注明出处:www.zengqiang.club
  • 注:如果文章有错误,望请评论指出,谢谢;如果看了文章还有不明白的地方,欢迎进群与我交流。
  • 评论