Opencv_100问_第四章 (16-20)

16. Prewitt 滤波器

Previtt滤波器是一种一阶微分滤波器,它和Sobel滤波器的区别是,Sobel滤波器主轴方向上的系数是2和-2,而Prewitt滤波器所有的系数都是-1和1,不管是纵向(Y轴方向)还是横向(X轴方向)

纵向(Y轴方向):

还有一点区别是Sobel算子是前面的像素值减去后面的,而Prewitt滤波器是后面的像素值减去前面的

横向(X轴方向):

代码实现:

# @Time   : 2022/6/10 15:40
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *


def BGR_to_GRAY(image):
    b = image[..., 0].copy()
    g = image[..., 1].copy()
    r = image[..., 2].copy()

    out = 0.2126 * r + 0.7152 * g + 0.0722 * b
    out = np.clip(out, 0, 255)
    return out


def prewitt_filter(image):
    kSize = 3
    if len(image.shape) == 3:
        image = BGR_to_GRAY(image)

    # zero Padding
    H, W = image.shape
    pad = kSize // 2
    out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float32)
    out[pad:pad + H, pad:pad + W] = image.copy().astype(np.float32)
    temp = out.copy()
    outX = out.copy()
    outY = out.copy()
    kernelX = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]])
    kernelY = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]])

    for y in range(H):
        for x in range(W):
            outY[pad + y, pad + x] = np.sum(kernelY * (temp[y:y + kSize, x:x + kSize]))
            outX[pad + y, pad + x] = np.sum(kernelX * (temp[y:y + kSize, x:x + kSize]))

    outX = np.clip(outX, 0, 255)
    outY = np.clip(outY, 0, 255)

    outX = outX[pad:pad + H, pad:pad + W].astype(np.uint8)
    outY = outY[pad:pad + H, pad:pad + W].astype(np.uint8)
    return outX, outY


if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH,"gray_01.bmp")
    imageOriginal = cv.imread(imagePath,cv.IMREAD_GRAYSCALE)
    prewittX,prewittY = prewitt_filter(imageOriginal)
    cv.imshow("Origial",imageOriginal)
    cv.imshow("PrewittX",prewittX)
    cv.imshow("PrevittY",prewittY)
    cv.waitKey(0)

17. Laplacian 滤波器

拉普拉斯滤波器也叫调和滤波器,是对图像亮度进行二次微分从而检测边缘的滤波器,由于数字图像是离散的,x方向和y方向的一次微分分别按照以下的式子进行计算:


因此二次微分按照以下的式子进行计算:


特此,Laplician表达式如下:

把这个式子表示为卷积核是这样的:


感觉拉普拉斯算子可以这么理解,使用它的四邻域的像素和中心点像素做差值,最后得到的结果就是拉普拉斯滤波得到的效果.不同于Sobel算子,他们是分纵向和横向的,拉普拉斯算子不分方向,直接得到结果.

代码实现:

# @Time   : 2022/6/10 16:02
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *


def BGR_to_GRAY(image):
    b = image[..., 0].copy()
    g = image[..., 1].copy()
    r = image[..., 2].copy()

    out = r * 0.2126 + g * 0.7152 + b * 0.0722
    out = np.clip(out, 0, 255)
    return out


def laplacian_filter(image):
    kSize = 3
    if len(image.shape) == 3:
        image = BGR_to_GRAY(image)
    H, W = image.shape

    # zero padding
    pad = int(kSize / 2)
    out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float32)
    out[pad:pad + H, pad:pad + W] = image.copy().astype(np.float32)
    laplacianKernel = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])

    temp = out.copy()

    for y in range(H):
        for x in range(W):
            out[pad + y, pad + x] = np.sum(laplacianKernel * temp[y:y + kSize, x:x + kSize])
    out = np.clip(out, 0, 255)
    out = out[pad:pad + H, pad:pad + W].astype(np.uint8)
    return out


if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH, "gray_01.bmp")
    imageOriginal = cv.imread(imagePath, cv.IMREAD_GRAYSCALE)
    laplacianFilter = laplacian_filter(imageOriginal)
    cv.imshow("Original", imageOriginal)
    cv.imshow("LaplacianFilter", laplacianFilter)
    cv.waitKey(0)

18. Emboss 滤波器

使用Emboss滤波器来进行滤波的时候可以使得物体的轮廓更加的清晰;

Emboss滤波核为:


这个滤波器如何去理解呢?其实就是右下角和左上角的差值,然后再和原来的像素值相加.
其中最远角的系数是2,其他都是1.
这种滤波的意义是什么呢? 如果这个中心的位置是边缘,那么这个差值肯定是存在的,就可以让整个边缘增强了.

# @Time   : 2022/6/10 16:17
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *


def BGR_to_GRAY(image):
    b = image[..., 0]
    g = image[..., 1]
    r = image[..., 2]

    out = 0.2126 * r + 0.7152 * g + 0.0722 * b
    out = np.clip(out, 0, 255)
    return out


def emboss_filter(image):
    if len(image.shape) == 3:
        image = BGR_to_GRAY(image)

    H, W = image.shape[:2]
    embossKernel = np.array([[-2, -1, 0], [-1, 1, 1], [0, 1, 2]])

    # zero padding
    kSize = 3
    pad = int(kSize / 2)
    out = np.zeros((H + 2 * pad, W + 2 * pad), dtype=np.float32)
    out[pad:pad + H, pad:pad + W] = image.copy().astype(np.float32)
    temp = out.copy()

    for y in range(H):
        for x in range(W):
            out[y + pad, x + pad] = np.sum(temp[y:(y + kSize), x:(x + kSize)] * embossKernel)

    out = np.clip(out, 0, 255)
    out = out[pad:pad + H, pad:pad + W].astype(np.uint8)
    return out


if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH, "gray_01.bmp")
    imageOriginal = cv.imread(imagePath, cv.IMREAD_GRAYSCALE)
    embossFilter = emboss_filter(imageOriginal)
    cv.imshow("Original", imageOriginal)
    cv.imshow("EmbossFilter", embossFilter)
    cv.waitKey(0)

19. LoG 滤波器

LoG即高斯-拉普拉斯(Laplacian of Gaussian)的缩写,使用高斯滤波器使图像平滑之后再使用拉普拉斯滤波器使得图像的轮廓更加清晰.为了防止拉普拉斯滤波器计算二次微分会使得图像噪声更加明显,所以我们首先使用高斯滤波器来抑制噪声.

定义的公式如下:

实现代码:

# @Time   : 2022/6/10 17:01
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *


def BGR_to_GRAY(image):
    b = image[..., 0]
    g = image[..., 1]
    r = image[..., 2]

    out = r * 0.2126 + g * 0.7152 + b * 0.0722
    out = out.astype(np.uint8)
    return out


def LoG_filter(image, kSize=5, sigma=3.0):
    if len(image.shape) == 3:
        image = BGR_to_GRAY(image)

    H, W = image.shape

    # zero padding
    pad = int(kSize / 2)
    out = np.zeros((H + 2 * pad, W + 2 * pad), dtype=np.float32)
    out[pad:pad + H, pad:pad + W] = image.copy().astype(np.float32)

    # LoG Kernel
    K = np.zeros((kSize, kSize), dtype=np.float32)
    for x in range(-pad, -pad + kSize):
        for y in range(-pad, -pad + kSize):
            K[y + pad, x + pad] = (x ** 2 + y ** 2 - sigma ** 2) * np.exp(-(x ** 2 + y ** 2) / (2 * (sigma ** 2)))

    K /= (2 * np.pi * (sigma * 6))
    K /= K.sum()

    temp = out.copy()

    # filtering
    for y in range(H):
        for x in range(W):
            out[pad + y, pad + x] = np.sum(K * temp[y:y + kSize, x:x + kSize])

    out = np.clip(out, 0, 255) 
    out = out[pad:pad + H, pad:pad + W].astype(np.uint8)
    return out

if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH,"gray_01.bmp")
    imageOriginal = cv.imread(imagePath,cv.IMREAD_GRAYSCALE)
    LoGFilter = LoG_filter(imageOriginal,5,1.5)

    cv.imshow("Original",imageOriginal)
    cv.imshow("LoGFilter",LoGFilter)
    cv.waitKey(0)

20. 直方图

通俗的来讲直方图要表达的是,横向要表现的是某个状态,而纵向要表现的是这个状态出现的次数.
直方图会将要展示的数据按照数值的范围切割为多个组/间隔,这些组/间隔在英文中称作bin,然后会统计出处在各个数据段中的数据个数并且以不同长度的长条展示出来.所以直方图本身也是一种条形图

plt.hist()函数绘制直方图

hist(x, bins=None, range=None, density=None, weights=None,
             cumulative=False, bottom=None, histtype='bar', align='mid',
             orientation='vertical', rwidth=None, log=False,
             color=None, label=None, stacked=False, normed=None,
             **kwargs):

参数解释:

  • x: (n,) array or sequence of (n,) arrays. 这个参数是指定每个bin(箱子)分布的数据,对应x轴.
  • bins: 这个参数执行bin(箱子)的个数,也就是总共有几条条状图
  • normed: 这个参数已经丢弃,使用density参数来代替了.
  • range: 元祖或者None. bin的上下限.如果没有提供,默认使用(x.min(),x.max())
  • density: 是否以密度的方式显示,默认是None,密度形式其实就是归一化.
  • align: 对齐方式 “left”:左,“mid”:中间,"right:"右
  • bottom: y轴的起始位置,数值类型
  • orientation: 方向, horizontal: 水平, vertical:垂直
# @Time   : 2022/6/10 17:27
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
import matplotlib.pyplot as plt

if __name__ == '__main__':
    imagePath = os.path.join(OPENCV_100_Q_PATH,"gray_01.bmp")
    imageOriginal = cv.imread(imagePath,cv.IMREAD_GRAYSCALE)

    plt.hist(imageOriginal.ravel(),bins=256,rwidth=0.8,range = (0,255))
    plt.show()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值