本文介绍: 滤波信号图像处理中的基本任务之一,其旨在有选择提取图像的某些特征可以用于给定应用程序上下文中传达重要信息例如,去除图像中的噪声、提取所需的视觉特征、图像重采样等。

1 图像滤波介绍

滤波信号和图像处理中的基本任务之一,其旨在有选择地提取图像的某些特征可以用于给定应用程序上下文中传达重要信息例如,去除图像中的噪声、提取所需的视觉特征、图像重采样等。

1.1 图像滤波理论

图像滤波即在尽量保留图像细节特征条件下对目标图像的噪声进行抑制,是图像预处理不可缺少的操作消除图像中的噪声又叫做图像滤波或平滑,滤波的目的有两个,一是突出特征以方便处理,二是抑制噪声。

空间域滤波就是在图像平面上对像素进行操作。空间域滤波大体分为两类:平滑锐化

空间域处理可由下式表示

g(x,y)=T[f(x,y)]

式中,f(x,y)是输入图像,g(x,y)是处理后的图像,T是在点(x,y)的邻域上定义的关于f的一种算子算子可应用于单幅图像或图像集合

1.2  频域分析

频域分析 (frequency domain analysis) :不同图像具有不同的灰度分布,可以用图像的灰度分布作为表征图像的一种方式,但同时,还存在另一种分析图像的观点。观察图像中的灰度变化,可以发现,某些图像包含强度几乎恒定的大面积区域(例如,蓝天),而某些图像上的灰度强度变化很快(例如,拥挤的街道)。因此,可以用图像中的变化频率作为表征图像的另一种方式,这种方式称为频域,而通过观察图像的灰度分布来表征图像的方式则被称为空间域。

频域分析将图像从最低频率到最高频分解为其频率内容,图像强度缓慢变化的区域包含低频,而高频是由强度的快速变化产生的。有多种用于计算图像的频率内容变换例如傅立叶变换或余弦变换需要注意的是,由于图像是二维平面,因此频率垂直频率(垂直方向的变化)和水平频率(水平方向的变化)组成。

在频域分析中,滤波器是一种放大图像某些频带同时减少其他频带的操作。因此,低通滤波器 (low-pass filters) 是消除图像高频成分的滤波器,而高通滤波器 (high-pass filters) 消除图像的低频成分

1.3 邻域滤波算子

一般来说,使用大小m×n的滤波器对大小为 M×N的图像进行线性空间滤波,可由下式表示:

 2 opencv图像滤波

2.1 opencv滤波概述

滤波处理分为两大类:线性滤波和非线性滤波。OpenCV里有这些滤波的函数使用起来非常方便。

2.1.1 线性滤波

平滑滤波:一般来说,图像具有局部连续的性质,即相邻像素的值相近,而噪声使得噪点处产生像素跳跃,所以通过平滑噪点可以减少噪声,去除图像中的不相关细节

方框滤波BoxBlur和均值滤波Blur都是对邻域内做平均值来滤波,属于平滑滤波。滤波的输出包含在滤波器模板邻域内的像素的平均值,方框滤波做归一化之后就变为均值滤波,这两个滤波器都是低通滤波器。

高斯滤波:高斯滤波对于图像来说就是一个通滤波,广泛用于消除高斯噪声,高速滤波就是一种加权滤波,只不过模板中的系数由高斯分布来确定的,高斯滤波器根据高斯函数形状选择滤波模板权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。

2.1.2 非线性滤波:

  • 中值滤波mediaBlur:去除椒盐噪声

  • 双边滤波BilateralFilter:保边去噪

中值滤波:中值滤波属于非线性滤波,其思想用滤波模板邻域内的像素的平均值来代替像素点的灰度值。中值滤波器是一种统计排序滤波器,图像上点(x,y),中值滤波以该点为中心领域内所有像素的统计排序中值作为此点的响应,中值滤波是非线性滤波。相比与均值滤波和高斯滤波,中值滤波可以有效的降低随机噪声,直接忽略掉噪声点,把噪声引起的模糊降到最低。线性滤波器在滤波的同时会造成图像细节模糊,中值滤波可以避免这个问题,其典型的应用就是中值滤波消除斑点噪声、椒盐噪声。

双边滤波:高斯滤波属于加权平均滤波,距离中心点越近的点越有较大权重,这种方法符合图像的平滑变化的特征,但是在边缘区域,像素值出现突变,这种方法反而会滤掉边缘轮廓损失掉有用的边缘信息。边缘保护滤波方法,双边滤波就是最常用的边缘保护滤波方法,就是为了处理这种情况而发明的。

双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息灰度相似性,达到保边去噪的目的。双边滤波将高斯滤波中通过各个点到中心点的空间临近度计算的各个权值进行优化,将其优化为空间临近度计算的权值和像素值相似度计算的权值的乘积优化后的权值再与图像作卷积运算,从而达到保边去噪的效果

2.2 opencv核心概念

3 opencv图像滤波实现

2.1 filter2D:图像卷积

函数原型

    dst = cv2.filter2D(src, ddepth, kernel, anchor, delta, borderType)
   

    src原图

    ddepth输出图像的尺寸默认为-1

    kernel:卷积核(是一个矩阵)

    anchor:锚点默认随卷积核变化

    delta:卷积后加一个值,默认为0

    borderType:有映射类型,加一个黑边,默认不设置

示例代码

import cv2
import numpy as np

# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank


original = cv2.imread('../data/girl03.jpeg')

# 创建一个5*5的卷积核
kernel = np.ones((5, 5), np.float32) / 25
filter2d = cv2.filter2D(original, -1, kernel)

img = show_multi_imgs(2, [original, filter2d], (1, 2))
cv2.namedWindow('origi&amp;filter2D', 0)
cv2.imshow('origi&amp;filter2D', img)
cv2.waitKey(0)

运行代码显示如下

 经过图像处理后,看着变模糊了,图像更平滑了

2.2 低通滤波boxFilter:方盒滤波

函数原型

dst = cv2.boxFilter(src, ddepth, ksize , anchor, normalize, borderType)

src输入图像
ddepth输出图像的尺寸,默认为-1
kernel:卷积核大小(x, y)
anchor:锚点,默认随卷积核变化
normalize:布尔类型默认为True;True:a为1/W*H(均值滤波),false:a=1

borderType:有映射类型,加一个黑边,默认不设置

示例代码

import cv2
import numpy as np


# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank

img = cv2.imread('../data/girl03.jpeg')

# 方盒滤波(当为True时)变成均值滤波,当为False时,就只加和不变化,超过255的结果设置为255
img2 = cv2.boxFilter(img, -1, (5, 5), normalize=True)
img3 = cv2.boxFilter(img, -1, (5, 5), normalize=False)
new_image = show_multi_imgs(4, [img, img2, img3], (1, 3))
cv2.namedWindow('img&amp;img2&amp;img3', 0)
cv2.imshow('img&amp;img2&amp;img3', new_image)
cv2.waitKey(0)

运行代码显示如下

blur():均值滤波

函数原型

    方盒滤波的参数为True时,就是均值滤波,所以这个API用的不多。
    dst = cv2.blur(scr, ksize, anchor, borderType)
   

    scr:源图像
    kernel:卷积核大小(x,y)
    anchor:锚点
    borderType:有映射类型,加一个黑边,默认不设置

2.3  低通滤波GaussianBlur:高斯滤波(去高斯噪音

适用于有高斯噪点的图片函数原型

dst = cv2.GaussianBlur(img, ksize, sigmaX, sigmaY, …)

img:输入的图像
ksize:卷积核大小
sigmaX:表示高斯核函数在X方向的的标准偏差。
sigmaY:表示高斯核函数在Y方向的的标准偏差。

重点关注前三个参数

示例代码

import cv2
import numpy as np


# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank

img = cv2.imread('../data/gauss2.jpeg')

# 高斯去噪
img2 = cv2.GaussianBlur(img, (3, 3), 0)

new_image = show_multi_imgs(4, [img, img2], (1, 2))
cv2.namedWindow('img&amp;img2', 0)
cv2.imshow('img&amp;img2', new_image)
cv2.waitKey(0)

运行代码显示如下

2.4 低通滤波medianBlur:中值滤波(去胡椒噪音

函数原型:

对胡椒噪音去噪明显,取中间的值作为卷积结果

dst = cv2.medianBlur(img, ksize)

img:输入图像
ksize:卷积核大小一个数

示例代码:

import cv2
import numpy as np


# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank

img = cv2.imread('../data/girl01.jpg')

# 高斯去噪
img2 = cv2.medianBlur(img, 5)

new_image = show_multi_imgs(4, [img, img2], (1, 2))
cv2.namedWindow('img&amp;img2', 0)
cv2.imshow('img&amp;img2', new_image)
cv2.waitKey(0)

运行代码显示如下

2.5 低通滤波bilateralFilter:双边滤波

函数原型

双边滤波的主要应用场景视频美颜

cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace, …)

img:输入图像
d:直径,与卷积核中心点的距离,一般取5
sigmaColor:颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域
sigmaSpace:sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似颜色获取相同颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace
 

双边滤波的作用::图像去噪保边,对相关分析的结果有较大的影响,对于裂缝比较强,噪声比较少的图像来说,可以将去噪的程度放大,对以后的相关分析的结果就会有更少的噪声。对于噪声不是很集中的图像,并有较多细节的图像,增加保边的效果,让相关分析及后续进行进一步结构处理,去噪。

示例代码:

import cv2
import numpy as np

# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank

img = cv2.imread('../data/biteral.jpg')

# 双边滤波
img2 = cv2.bilateralFilter(img, 5, 20, 50)

new_image = show_multi_imgs(4, [img, img2], (1, 2))
cv2.namedWindow('img&amp;img2', 0)
cv2.imshow('img&amp;img2', new_image)
cv2.waitKey(0)

运行代码显示如下

2.6 高通滤波Sobel

只能一次在x方向上或者y方向上求导然后把结果相加

dst1 = cv2.Sobel(src, ddepth, dx, dy, ksize = 3, scale = 1, delta = 0, borderType = BORDER_DEFAULT )

src:输入原图像
ddepth:位深,默认为-1
dx,dy:只能选择一个方向要么0、1,要么1、0
ksize:卷积核大小,默认为3,当-1时为沙尔
scale:缩放大小,一般就用默认值
delta:偏移量,一般就用默认值
borderType:边界扩充类型,一般就用默认值
 

 示例代码:

import cv2
import numpy as np

# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank

img = cv2.imread('../data/biteral.jpg')

# Sobel
dx = cv2.Sobel(img, -1, 1, 0, ksize=3)
dy = cv2.Sobel(img, -1, 0, 1, ksize=3)

# dst = dx+dy
dst = cv2.add(dx, dy)

new_image = show_multi_imgs(4, [img, dx, dy, dst], (1, 4))
cv2.namedWindow('img1-4', 0)
cv2.imshow('img1-4', new_image)
cv2.waitKey(0)

运行代码显示如下

一幅图的边缘被很好的分割出来。

2.7 高通滤波Scharr

与Sobel类似,只不过使用的ksize值不同,Scharr不能改变卷积核的大小,只能是3*3的。同样只能求一个方向上的边缘。

cv2.Scharr(src, ddepth, dx, dy, scale = 1, delta = 0, borderType = BORDER_DEFAULT).
src:输入原图像
ddepth:位深,默认为-1
dx,dy:只能选择一个方向上要么0、1,要么1、0
scale:缩放大小,一般就用默认值
delta:偏移量,一般就用默认值
borderType:边界扩充类型,一般就用默认值

示例代码:

import cv2
import numpy as np


# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank


img = cv2.imread('../data/biteral.jpg')

# Sobel,当ksize=-1时,就是Scharr
# dx = cv2.Sobel(img, -1, 1, 0, ksize=-1)
# dy = cv2.Sobel(img, -1, 0, 1, ksize=-1)

dx = cv2.Scharr(img, -1, 1, 0)
dy = cv2.Scharr(img, -1, 0, 1)

# dst = dx+dy
dst = cv2.add(dx,dy)

new_image = show_multi_imgs(4, [img, dx, dy, dst], (1, 4))
cv2.namedWindow('img1-4', 0)
cv2.imshow('img1-4', new_image)
cv2.waitKey(0)

运行代码显示如下

2.8 高通滤波Laplacian(拉普拉斯)

Laplacian可以同时求两个方向上的边缘,但是对噪音比较敏感,一般需要先进行去噪再调用Laplacian。

dst = cv2.Laplacian(src, ddepth, ksize = 1 ,scale = 1, borderType = BORDER_DEFAULT)

src:输入原图像
ddepth:位深,默认为-1
ksize:卷积核大小,默认为1
scale:缩放大小,一般就用默认值
delta:偏移量,一般就用默认值
borderType:边界扩充类型,一般就用默认值

示例代码:

import cv2
import numpy as np

# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank

img = cv2.imread('../data/biteral.jpg')

dst = cv2.Laplacian(img, -1, ksize=5)
new_image = show_multi_imgs(4, [img, dst], (1, 2))
cv2.namedWindow('img&dst', 0)
cv2.imshow('img&dst', new_image)
cv2.waitKey(0)

卷积核大小为5*5的结果

运行代码结果显示:

2.8 高通滤波Canny

使用5*5高斯滤波消除噪声,可以计算图像的四个方向上的边缘(0,45,90,135),取局部最大值,多了一个阈值计算。高于阈值我们认为是边缘,低于阈值就不是边缘,显然A为边缘,如果,但是B和C介于最大值最小值之间,BC既不是边缘也是边缘,但是C与A在一条线上,所以C也是边缘。

dst = cv2.Canny(img, minVal, maxVal)

img:原图像
minVal:最小阈值
maxVal:最大阈值
低于最小阈值就不是边缘,高于最大阈值是边缘。 

示例代码:

import cv2
import numpy as np

# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):
    """
    :param scale: float 原图缩放的尺度
    :param imglist: list 待显示的图像序列
    :param order: list or tuple 显示顺序 行×列
    :param border: int 图像间隔距离
    :param border_color: tuple 间隔区域颜色
    :return: 返回拼接好的numpy数组
    """
    if order is None:
        order = [1, len(imglist)]
    allimgs = imglist.copy()
    ws , hs = [], []
    for i, img in enumerate(allimgs):
        if np.ndim(img) == 2:
            allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)
        ws.append(allimgs[i].shape[1])
        hs.append(allimgs[i].shape[0])
    w = max(ws)
    h = max(hs)

    # 将待显示图片拼接起来
    sub = int(order[0] * order[1] - len(imglist))

    # 判断输入的显示格式与待显示图像数量的大小关系
    if sub > 0:
        for s in range(sub):
            allimgs.append(np.zeros_like(allimgs[0]))
    elif sub < 0:
        allimgs = allimgs[:sub]
    imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_color
    imgblank = imgblank.astype(np.uint8)
    for i in range(order[0]):
        for j in range(order[1]):
            imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]
    return imgblank

img = cv2.imread('../data/biteral.jpg')

# canny
dst = cv2.Canny(img, 100, 200)
dst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)

new_image = show_multi_imgs(4, [img, dst], (1, 2))
cv2.namedWindow('img&dst', 0)
cv2.imshow('img&dst', new_image)
cv2.waitKey(0)

运行代码显示如下:

原文地址:https://blog.csdn.net/lsb2002/article/details/134646853

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_37850.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注