图像处理学习路线总结 python

记录一下我的图像处理学习路线,后续有其他想法了再补充。

目录

1.图像处理基础知识

1.1 数字图像处理公开课

2.利用opencv进行实现

2.1 在pycharm里安装opencv库。 

2.2  图像处理基础操作

2.2.1 读取图片

2.2.2 将图片转换成自己想要的大小

2.2.3  输出图片矩阵

2.2.4 绘制灰度直方图

2.2.5 直方图均衡化

2.2.6 空间域增强&滤波

2.2.7 频域增强&滤波

2.2.8 图片复原与重建:给图片增加噪声

2.2.9 彩色图像处理:图像读取

2.2.10 彩色图像处理:伪彩色图像处理

2.2.11 小波变换

2.2.12 图像压缩

3. 图像形态学

3.1 腐蚀与膨胀

3.2 图像分割

3.2.1 阈值分割法:

3.2.2 边缘分割法:

3.2.3 霍夫变换Hough:

3.2.4 基于区域的图像分割法

4. 视频处理

4.1 视频基础知识

4.2 按帧读取视频并合成视频


1.图像处理基础知识

1.1 数字图像处理公开课

 https://www.bilibili.com/video/BV157411J7H8?from=search&seid=11616479247431589441 

https://www.bilibili.com/video/BV1Kh411X7Qv?p=1

看完上面的东西,了解基础概念,准备在之后真正操作时,再慢慢消化。

2.利用opencv进行实现

2.1 在pycharm里安装opencv库。 

参考这篇:https://blog.csdn.net/qq_38328871/article/details/84842381?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162159869616780255213928%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162159869616780255213928&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-84842381.first_rank_v2_pc_rank_v29&utm_term=pycharm+%E5%AE%89%E8%A3%85opencv&spm=1018.2226.3

2.2  图像处理基础操作

2.2.1 读取图片

import cv2

img = cv2.imread("F:/picture/cat.jpg", cv2.IMREAD_GRAYSCALE)
cv2.namedWindow("mypicture")
cv2.imshow("mypicture", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

先要准备一张图片放在你的路径中,然后imread(“路径”,读取方式)根据自己需要来调整,pycharm自动补全的提示里也有,可以都试试。这里我后面写的_GRAYSCALE 是以灰度图的方式读取出来。

输出结果:

2.2.2 将图片转换成自己想要的大小

因为想要把图片转换成自己想要的标准格式,所以需要重新定义大小,这里我们要用到resize函数,将其转换成100*100 的格式。这里参考这一篇resize参数详解。https://blog.csdn.net/weixin_40922744/article/details/103395227

这里采用默认的双线性插值。

size = (100, 100)
myImg = cv2.resize(img, size, interpolation=cv2.INTER_LINEAR)
cv2.namedWindow("my resize picture")
cv2.imshow("my resize picture", myImg)
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果:

缩小后的图像

 

2.2.3  输出图片矩阵

可以直接print出来,因为将图片在imread时就已经是用灰度图的格式打开的,所以直接输出就是图片的灰度矩阵

 

size = (100, 100)
myImg = cv2.resize(img, size, interpolation=cv2.INTER_LINEAR)
cv2.namedWindow("my resize picture")
cv2.imshow("my resize picture", myImg)
print(myImg) # 添加的 输出图片灰度矩阵
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果:

[[ 88  82  83 ...  61  62  97]
 [ 82  82  75 ...  62  79 115]
 [ 85  85  84 ...  79 109 134]
 ...
 [238 220 233 ...  89  87  90]
 [227 210 234 ... 120 135 124]
 [220 228 228 ... 120 107 110]]

2.2.4 绘制灰度直方图

如果看了图像处理的基础课程会知道,因为在进行图像分割时需要有一个灰度的阈值,所以我们需要通过绘制灰度直方图来找到这个阈值(即灰度直方图的波谷)。

import matplotlib.pyplot as plt #导入绘图工具

plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号


width = 100 #要转换的宽度
length = 100#要转换的长度
size = (width, length)
myImg = cv2.resize(img, size, interpolation=cv2.INTER_LINEAR) #将之前的图片转换成设置的大小
cv2.namedWindow("my resize picture")
cv2.imshow("my resize picture", myImg) #展示转换后的图像

# 绘制直方图
#1 准备数据
x = range(255)#横轴显示图像的灰度等级0-255
y = range(width*length)# y轴是灰度的个数 width*length
num = []  #num元组声明,每个灰度对应的个数
imgGray = myImg.flatten()#把图像灰度数据由矩阵拉平成一行的形式

for i in x:#从灰度0-255开始轮流查有多少个,每个灰度遍历
    t = 0 #每个灰度级像素个数统计用的临时变量,检测下一个灰度级时置零。
    for j in y: #每个像素遍历
        if imgGray[j] == i:#如果这个位置的灰度等于当前要检索的灰度级
            t = t+1 #那么当前灰度级的个数+1
    num.append(t) #将查出来的每个灰度级的个数添加到灰度统计数组中

#2 设置画布大小
plt.figure(figsize=(12, 8), dpi=80)
plt.plot(x, num)
#3 设置刻度及步长
z = range(300) #按照检测出的分布,设置图像能显示灰度级的最大值
plt.xticks(x[::20])
plt.yticks(z[::20])  #20是步长,根据自己需要调整
#4 添加网格信息
plt.grid(True, linestyle='--', alpha=0.5) #默认是True,风格设置为虚线,alpha为透明度
#5 添加标题(中文在plt中默认乱码,不乱码的方法就是导入包之后的那两行)
plt.xlabel('灰度级')
plt.ylabel('灰度个数')
plt.title('cat灰度直方图')
#6 保存图片,并展示
plt.savefig('C:/Users/Administrator/Desktop/pic/gray_zhifangtu.png')
plt.show()


cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果:

或者使用hinst函数可以直接绘制直方图,具体参考这篇:https://blog.csdn.net/weixin_37988176/article/details/109421535

imgGray = myImg.flatten()#把图像灰度数据拉平
plt.figure("简单方法绘制直方图") #设置直方图的名字
n, bins, patches = plt.hist(imgGray, bins=100, facecolor='green', alpha=0.75)
plt.show()

输出结果:

2.2.5 直方图均衡化

因为直方图是否均衡和视觉效果有着直接的关系,所以可以通过修正直方图来进行图像增强。我们所要做的直方图均衡化就是把直方图弄的平整一些。

我参考了这一篇:https://blog.csdn.net/missyougoon/article/details/81632166?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162168723916780255276528%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162168723916780255276528&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-81632166.first_rank_v2_pc_rank_v29&utm_term=%E7%9B%B4%E6%96%B9%E5%9B%BE%E5%9D%87%E8%A1%A1%E5%8C%96python&spm=1018.2226.3001.4187

#直方图均衡化
imgEqu = cv2.equalizeHist(myImg)
imgEquflat = imgEqu.flatten()#把图像灰度数据拉平
plt.figure("直方图均衡化") #设置直方图的名字
cv2.namedWindow("均衡过的图片")
cv2.imwrite("C:/Users/Administrator/Desktop/pic/imgEqu.png", imgEqu)
cv2.imshow("均衡过的图片", imgEqu)
n, bins, patches = plt.hist(imgEquflat, bins=100, facecolor='green', alpha=0.75)
plt.show()

这里跑完一遍发现直方图很怪,输出的图片中间有一块白的,然后我调查了一下发现,原来我在以100 100的大小来resize图片的时候,出了问题。所以我重新resize了一下。

print(img.shape) #打印出图片的尺寸

width, length = img.shape[0:2] #将图片尺寸给宽和长
size = (int(width/2), int(length/2))
myImg = cv2.resize(img, size, interpolation=cv2.INTER_LINEAR)

cv2.namedWindow("my resize picture")
cv2.imwrite("C:/Users/Administrator/Desktop/pic/myImg.png", myImg)
cv2.imshow("my resize picture", myImg)

然后resize后的图片和均衡过后的图片对比如下:左边是原始图像灰度化缩小后的,右边是直方图均衡后的图像。

均衡过后的直方图:

均衡过后的直方图

2.2.6 空间域增强&滤波

空间滤波器分为平滑滤波器(消除噪声&模糊图像)和锐化滤波器(反差增加,边缘明显)。

参考了这一篇:https://blog.csdn.net/Seven_WWW/article/details/108442513?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162177868716780255216992%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162177868716780255216992&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-2-108442513.first_rank_v2_pc_rank_v29&utm_term=python+opencv+%E7%A9%BA%E9%97%B4%E5%9F%9F%E6%BB%A4%E6%B3%A2&spm=1018.2226.3001.4187

 

这里试一下sobel算子滤波:

#空间域增强
x = cv2.Sobel(imgEqu,cv2.CV_16S,1,0)
y = cv2.Sobel(imgEqu,cv2.CV_16S,0,1)
# 转uint8
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
imgSobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示图形
titles = [u'原始图像', u'Sobel算子']
images = [imgEqu, imgSobel]
for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

输出结果:

2.2.7 频域增强&滤波

通过傅里叶变换,将图像由空间域函数转换成频率域函数,然后在频率域对不同频率进行滤波处理,在通过傅里叶逆变换转换成增强后的图像。

低通滤波起平滑图像、消除噪声的作用。

高通滤波起锐化图像、增强细节的作用。

参考这篇文章:https://blog.csdn.net/qq_40507857/article/details/107609844?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162178281016780271576997%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162178281016780271576997&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-107609844.first_rank_v2_pc_rank_v29&utm_term=python+%E9%A2%91%E5%9F%9F%E5%A2%9E%E5%BC%BA&spm=1018.2226.3001.4187

这里试一下butterworth高频增强滤波:

#频域增强
f = np.fft.fft2(imgEqu)
fshift = np.fft.fftshift(f)
# 取绝对值后将复数变化为实数
# 取对数的目的是将数据变换到0~255
s1 = np.log(np.abs(fshift))


def ButterworthPassFilter(image, d, n):
    """
    Butterworth 高通滤波器
    """
    f = np.fft.fft2(image)
    fshift = np.fft.fftshift(f)

    def make_transform_matrix(d):
        transform_matrix = np.zeros(image.shape)
        center_point = tuple(map(lambda x: (x - 1) / 2, s1.shape))
        for i in range(transform_matrix.shape[0]):
            for j in range(transform_matrix.shape[1]):
                def cal_distance(pa, pb):
                    from math import sqrt
                    dis = sqrt((pa[0] - pb[0]) ** 2 + (pa[1] - pb[1]) ** 2)
                    return dis

                dis = cal_distance(center_point, (i, j))
                transform_matrix[i, j] = 1 / (1 + (dis / d) ** (2 * n))
        return transform_matrix

    d_matrix = make_transform_matrix(d)
    d_matrix = d_matrix+0.5
    new_img = np.abs(np.fft.ifft2(np.fft.ifftshift(fshift * d_matrix)))
    return new_img


plt.subplot(221)
plt.axis('off')
plt.title('Original')
plt.imshow(imgEqu, cmap='gray')

plt.subplot(222)
plt.axis('off')
plt.title('Butter D=100 n=1')
butter_100_1 = ButterworthPassFilter(imgEqu, 100, 1)
plt.imshow(butter_100_1, cmap='gray')

plt.subplot(223)
plt.axis('off')
plt.title('Butter D=30 n=1')
butter_30_1 = ButterworthPassFilter(imgEqu, 30, 1)
plt.imshow(butter_30_1, cmap='gray')

plt.subplot(224)
plt.axis('off')
plt.title('Butter D=30 n=5')
butter_30_5 = ButterworthPassFilter(imgEqu, 30, 5)
plt.imshow(butter_30_5, cmap='gray')

plt.show()

输出结果:其中 d为截止频率,n为阶数,具体的参数调整效果在那篇文章里有。

2.2.8 图片复原与重建:给图片增加噪声

这里参考了这一篇:https://blog.csdn.net/qq_38395705/article/details/106311905?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162182736316780262527891%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162182736316780262527891&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-5-106311905.first_rank_v2_pc_rank_v29&utm_term=opencv+python+%E5%A2%9E%E5%8A%A0%E5%99%AA%E5%A3%B0&spm=1018.2226.3001.4187

试一下添加椒盐噪声:

# 增加噪声
#添加椒盐噪声


def sp_noise(image, prob):

    '''
    添加椒盐噪声
    prob:噪声比例
    '''

    output = np.zeros(image.shape, np.uint8)
    thres = 1 - prob

    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            rdn = np.random.random()
            if rdn < prob:
                output[i][j] = 0
            elif rdn > thres:
                output[i][j] = 255
            else:
                output[i][j] = image[i][j]

    return output


imgSp = sp_noise(imgEqu, 0.02)
cv2.namedWindow("imgSp")
cv2.imwrite("C:/Users/Administrator/Desktop/pic/imgSp.png", imgSp)
cv2.imshow("imgSp", imgSp)

输出结果为:

2.2.9 彩色图像处理:图像读取

参考了这一篇:https://blog.csdn.net/huanglu_thu13/article/details/52332695?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162183003516780274112204%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162183003516780274112204&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-52332695.first_rank_v2_pc_rank_v29&utm_term=python+opencv+%E5%BD%A9%E8%89%B2%E5%9B%BE%E5%83%8F&spm=1018.2226.3001.4187

先将图片读取成RGB格式,要注意需要转化一下:

#读取彩色图像
#首先读出来的是BGR图像
imgBgr = cv2.imread("F:/picture/cat.jpg", cv2.IMREAD_COLOR)
#转换成RGB
imgRgb = cv2.cvtColor(imgBgr, cv2.COLOR_BGR2RGB)

plt.subplot(121)# 一行 两列 第一个
plt.axis('off')
plt.title('IMG_BGR')
plt.imshow(imgBgr)

plt.subplot(122)
plt.axis('off')
plt.title('IMG_RGB')
plt.imshow(imgRgb)

plt.show()

输出结果:

文中说到还有一种方式是直接按照三通道进行读取,就省去了转化的步骤:

cat = cv2.imread("F:/picture/cat.jpg")

#直接按照通道读取
b, g, r = cv2.split(cat)
"""
cv2.imshow("Blue 1", b)
cv2.imshow("Green 1", g)
cv2.imshow("Red 1", r)
"""

plt.subplot(131)
plt.axis('off')
plt.title('IMG_R')
plt.imshow(r)

plt.subplot(132)
plt.axis('off')
plt.title('IMG_G')
plt.imshow(g)
plt.subplot(133)
plt.axis('off')
plt.title('IMG_B')
plt.imshow(b)

plt.show()

输出结果:

2.2.10 彩色图像处理:伪彩色图像处理

将图像中的一个或多个通道的数据用其他传感器的数据代替。

2.2.11 小波变换

也是一种滤波方法。

防止吉布斯效应: 一个很小的波动需要许多三角波来拟合。而用小波变换可以消除这种效果,减少了运算量。

小波变换原理参考了知乎这一篇:形象易懂讲解算法I——小波变换 - 咚懂咚懂咚的文章 - 知乎 https://zhuanlan.zhihu.com/p/22450818

2.2.12 图像压缩

霍夫曼编码:分级逐次合并概率最小的灰度级。

参考了这一篇:https://blog.csdn.net/wsp_1138886114/article/details/100761284?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162184043816780255283899%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=162184043816780255283899&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-1-100761284.first_rank_v2_pc_rank_v29&utm_term=opencv+%E5%9B%BE%E5%83%8F%E5%8E%8B%E7%BC%A9+python+&spm=1018.2226.3001.4187

最简单的就是resize函数。

3. 图像形态学

3.1 腐蚀与膨胀

腐蚀与膨胀:通过用一个n维矩阵扫描图片,来判断是该区域像素是该置0还是置255,通过调整filter矩阵参数,二者结合使用能起到滤波器的效果。

腐蚀(erode):用于消除小而无意义的物体。

膨胀(dilate):用于扩大目标像素。

参考:https://blog.csdn.net/LaoYuanPython/article/details/109441709?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162209027716780265430437%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162209027716780265430437&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-2-109441709.first_rank_v2_pc_rank_v29&utm_term=%E8%85%90%E8%9A%80%E4%B8%8E%E8%86%A8%E8%83%80+python&spm=1018.2226.3001.4187

3.2 图像分割

3.2.1 阈值分割法:

全局阈值:通过直方图的波谷进行图像分割。如果多个波峰波谷,可以使用多阈值分割(代表不同部位)。

最小误差阈值:有目标和背景的分布函数,对误差函数(阈值导致的错误分辨的部分(目标&背景)的概率和)再求极值,得到阈值。

最大方差阈值:利用直方图选取初始阈值,将像素分为两组,求两组像素的方差,方差最大点就是阈值点。(otsu 大津阈值法)

3.2.2 边缘分割法:

Canny算子:

1.采用滤波器平滑图像

2. 采用方向检测算子计算梯度

3.沿着梯度方向寻找局部极大值

4.采用双阈值检测跟踪边缘

3.2.3 霍夫变换Hough:

解决什么问题:在找到一堆边界点时,想要找到最符合这些边界点的直线方程。

方法:将位置xy平面,转换到对应方程y=ax+b 的参数ab平面,求 a=mb+n这些线的公共点。就是y与x对应关系最频繁的一个点,所以就能确定参数。

功能:通过变换极坐标方程,多维参数的形式,即可以检测直线,也可以检测圆等曲线。

优点与缺点:

优点:抗噪声能力强,解析直线与曲线。

缺点:需要先二值化以及边缘检测,损失原图很多信息。

3.2.4 基于区域的图像分割法

区域生长法:灰度差生长法,小于一定灰度阈值T的都归为一个区域。

分类和并法:将图像分成许多小份,根据相邻方差是否为0(或者是某个阈值)来判断是否属于同一区域。

4. 视频处理

4.1 视频基础知识

帧:frame,视频是由帧构成的,视频可以看做根据时间顺序依次播放的画面

fps:帧率,一秒播放多少帧

... ...待后续补充。

4.2 按帧读取视频并合成视频

将一个视频按照每一帧读取出来,并存为jpg文件,然后对其进行处理,处理后再将所有图片合成一个新的视频,最后将用到的图片删除,只保留视频。

下列代码生成的视频很大,具体怎么变小还在研究中,应该是将图片质量调低就好了。

import 包有些可能不用,不过我懒省事就都import了。可以自行删除。

import cv2
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
import os

video = cv2.VideoCapture("F:/PY_WORK/test/test01.avi") #打开原始视频
fps = video.get(cv2.CAP_PROP_FPS) #读取帧率
frameCount = video.get(cv2.CAP_PROP_FRAME_COUNT) #视频总帧数
size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))) #读取视频size

success, frame = video.read()
print(fps, frameCount, size)

#读取视频图片
i = 0 # 图片顺序编号
while success:
    success, frame = video.read()#读出一帧图片
    if success:
        filename = 'F:/PY_WORK/test/image' + str(i) + '.jpg'
        cv2.imwrite(filename, frame, [cv2.IMWRITE_JPEG_QUALITY, 100])  # 确定图片质量,100算是高的
        i = i+1
print('图片读取end!')


"""
在这里可以插入对img图片的处理,例如逐个图片边缘检测之类的。
"""


#图片写入视频
img = cv2.imread('F:/PY_WORK/test/image0.jpg')#读取第一个图片 看看大小
imginfo = img.shape
size = (imginfo[1], imginfo[0])  #与默认不同,opencv使用 height在前,width在后,所有需要自己重新排序
print(size)
#创建写入对象,包括 新建视频名称,每秒钟多少帧图片(fps张) ,size大小
#一般人眼最低分辨率为19帧/秒
transpath = 'F:/PY_WORK/test/test02.mp4' #输出视频位置
videoWriter = cv2.VideoWriter(transpath, cv2.VideoWriter_fourcc(*"mp4v"), fps, size)#fourcc参数如果报错的话,就直接用-1替换,它会自己选择。这个我也感觉很迷糊
for i in range(int(frameCount)):#将 总帧数 幅图片写入
    filename = 'F:/PY_WORK/test/image' + str(i) + '.jpg'
    img = cv2.imread(filename, 1)  # 1 表示彩图,0表示灰度图

    # 直接写入图片对应的数据
    videoWriter.write(img)

videoWriter.release()
print('视频生成end')

#生成完毕删除图片
for i in range(int(frameCount)):
    filename = 'F:/PY_WORK/test/image' + str(i) + '.jpg'
    os.remove("filename")
print("图片删除end!")

我中间插入Canny滤波后的输出结果:

视频用的bilibili下载的舞蹈区视频做(~ ̄▽ ̄)~https://www.bilibili.com/video/BV1Vb411C7wk?from=search&seid=11355300764444585028

视频下载可以再链接里的bilibili后面加上jj,用唧唧下载视频。

生成的视频就不传了,放个截图。

  • 22
    点赞
  • 213
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

擅长划水的小汪同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值