数字图像处理笔记(二):使用OpenCV处理图像

1 - 傅里叶变换

傅里叶变换是图像处理的基础,Joseph Fourier(约瑟夫 \cdot 傅里叶)是一维18世纪的法国数学家,他发现并推广了不少数学概念,在数学上,他认为一切均可以用波形来描述。具体而言,他观察到全部的波形均可以由一系列简单且频率不一样的正弦曲线叠加获得html

也就是说,原始图像由许多频率组成,咱们能够分离这些频率来理解图像和提取感兴趣的数据,傅里叶变换的概念是许多常见的图像处理操做的基础,好比边缘检测或线段和形状检测web

下面咱们要先介绍两个概念:高通滤波器和低通滤波器,上面提到的那些操做都是以这两个概念和傅里叶变换为基础。网络

2 - 高通滤波器

高通滤波器(HPF)是检测图像的某个区域,而后根据像素与周围像素亮度差值来提高(Boost)该像素的亮度的滤波器app

对滤波操做,咱们首先要知道核(kernel)的概念框架

核是指一组权重的集合,它会应用在源图像的一个区域,并由今生成目标图像的一个像素。与卷积神经网络中的卷积核同样,经过选定核的权重与图像进行卷积达到对图像特征的提取
在这里插入图片描述ide

下面咱们就经过一段程序来实验一些高通滤波器的做用svg

import cv2
import numpy as np
from scipy import ndimage

kernel_3x3 = np.array([[-1,-1,-1],
                      [-1,8,-1],
                      [-1,-1,-1]])
kernel_5x5 = np.array([[-1,-1,-1,-1,-1],
                       [-1,1,2,1,-1],
                       [-1,2,4,2,-1],
                       [-1,1,2,1,-1],
                       [-1,-1,-1,-1,-1]])
img = cv2.imread('images/cat.jpg',0)

k3 = ndimage.convolve(img, kernel_3x3)
k5 = ndimage.convolve(img, kernel_5x5)
blurred = cv2.GaussianBlur(img, (11,11), 0)
g_hpf = img - blurred
cv2.imshow('3x3',k3)
cv2.imshow('5x5',k5)
cv2.imshow('g_hpf',g_hpf)
cv2.waitKey(0)

原始图像:
在这里插入图片描述
通过高通滤波器以后的图像:
在这里插入图片描述
能够看到咱们把图像的边缘给提取出来了,仍是能依稀的看到猫的轮廓工具

3 - 低通滤波器

高通滤波器是根据像素与邻近像素的亮度差值来提高该像素的亮度。低通滤波器(Low Pass Filter,LPF)则是在像素与周围像素的亮度差值小于一个特定值时,平滑该像素的亮度。它主要用于去噪和模糊化。
下面,咱们在以前Cameo框架中增长咱们的模块来增长一个低通滤波的功能ui

1 - 在filters.py文件中编写滤波器类

import cv2
import numpy
import utils

def strokeEdges(src, dst, blurKsize = 7, edgeKsize = 5):
    if blurKsize >= 3:
        blurredSrc = cv2.medianBlur(src, blurKsize)
        graySrc = cv2.cvtColor(blurredSrc,cv2.COLOR_BGR2GRAY)
    else:
        graySrc = cv2.cvtColor(src,cv2.COLOR_BGR2GRAY)
    cv2.Laplacian(graySrc,cv2.CV_8U,graySrc,ksize=edgeKsize)
    normalizedInverseAlpha = (1.0 / 255) * (255 - graySrc)
    channels = cv2.split(src)
    for channel in channels:
        channel[:] = channel * normalizedInverseAlpha
    cv2.merge(channels, dst)







class VConvolutionFilter(object):
    """
    对V进行卷积的滤波器
    """
    def __init__(self,kernel):
        self._kernel = kernel
    def apply(self,src,dst):
        """
        使用BGR或灰色源图像应用过滤器
        """
        cv2.filter2D(src,-1,self._kernel,dst)

class SharpenFilter(VConvolutionFilter):
    """
    具备1像素半径的锐化滤波器
    """
    def __init__(self):
        kernel = numpy.array([[-1,-1,-1],
                              [-1,9,-1],
                              [-1,-1,-1]])
        VConvolutionFilter.__init__(self,kernel)

class FindEdgesFilter(VConvolutionFilter):
    """
    一个半径为1像素的边缘检验滤波器
    """
    def __init__(self):
        kernel = numpy.array([[-1,-1,-1],
                              [-1,8,-1],
                              [-1,-1,-1]])
        VConvolutionFilter.__init__(self,kernel)

class BlurFilter(VConvolutionFilter):
    """
    一个2像素半径的模糊滤波器
    """
    def __init__(self):
        kernel = numpy.array([[0.04,0.04,0.04,0.04,0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04]])
        VConvolutionFilter.__init__(self,kernel)

class EmbossFilter(VConvolutionFilter):
    """
    具备1像素半径的浮雕过滤器(锐化、边缘检测、模糊等滤波器都使用了高度对称的核,而不对称的核会获得一些有趣的效果,
    它同时具备模糊和锐化的做用,这会产生一种脊状或者浮雕的效果)
    """
    def __init__(self):
        kernel = numpy.array([[-2,-1,0],
                              [-1,-1,-1],
                              [0,1,2]])
        VConvolutionFilter.__init__(self,kernel)

class BGRFuncFilter(object):

    def __init__(self, vFunc=None, bFunc=None, gFunc=None, rFunc=None, dtype=numpy.uint8) :

        length = numpy.iinfo(dtype).max + 1
        self._bLookupArray = utils.createLookupArray(utils.createCompositeFunc(bFunc, vFunc), length)
        self._gLookupArray = utils.createLookupArray(utils.createCompositeFunc(gFunc, vFunc), length)
        self._rLookupArray = utils.createLookupArray(utils.createCompositeFunc(rFunc, vFunc), length)

    def apply(self, src, dst) :

        """应用滤波器在RGB图像上"""
        b, g, r = cv2.split(src)
        utils.applyLookupArray(self._bLookupArray, b, b)
        utils.applyLookupArray(self._gLookupArray, g, g)
        utils.applyLookupArray(self._rLookupArray, r, r)
        cv2.merge([ b, g, r ], dst)



class BGRCurveFilter(BGRFuncFilter):

    def __init__(self, vPoints=None, bPoints=None, gPoints=None, rPoints=None, dtype=numpy.uint8):
        BGRFuncFilter.__init__(self, utils.createCurveFunc(vPoints), utils.createCurveFunc(bPoints),
                               utils.createCurveFunc(gPoints), utils.createCurveFunc(rPoints), dtype)


class BGRPortraCurveFilter(BGRCurveFilter):
    def __init__(self, dtype = numpy.uint8):
        BGRCurveFilter.__init__(
            self,
            vPoints = [ (0, 0), (23, 20), (157, 173), (255, 255) ],
            bPoints = [ (0, 0), (41, 46), (231, 228), (255, 255) ],
            gPoints = [ (0, 0), (52, 47), (189, 196), (255, 255) ],
            rPoints = [ (0, 0), (69, 69), (213, 218), (255, 255) ],
            dtype = dtype)

定义完滤波器后编写一些框架所需的工具类spa

2 - 在utils.py编写经常使用的工具类

import cv2, numpy, scipy.interpolate


def createCurveFunc(points):
    """Return a function derived from control points."""
    if points is None:
        return None
    num_points = len(points)
    if num_points < 2:
        return None
    xs, ys = zip(*points)
    if num_points < 4:
        kind = 'linear'
        # 'quadratic' is not implemented.
    else:
        kind = 'cubic'
    return scipy.interpolate.interp1d(xs, ys, kind, bounds_error=False)


def createLookupArray(func, length = 256):
    """Return a lookup for whole-number inputs to a function. The lookup values are clamped to [0, length - 1]."""
    if func is None:
        return None
    lookup_array = numpy.empty(length)
    i = 0
    while i < length:
        func_i = func(i)
        lookup_array[i] = min(max(0, func_i), length - 1)
        i += 1
    return lookup_array


def applyLookupArray(lookup_array, src, dst):
    """Map a source to a destination using a lookup."""
    if lookup_array is None:
        return
    dst[:] = lookup_array[src]


def createCompositeFunc(func0, func1):
    """Return a composite of two functions."""
    if func0 is None:
        return func1
    if func1 is None:
        return func0
    return lambda x: func0(func1(x))


def createFlatView(array):
    """Return a 1D view of an array of any dimensionality."""
    flat_view = array.view()
    flat_view.shape = array.size
    return flat_view

3 - 相应的修改Cameo框架,增长滤波器显示

import cv2
import filters
from managers import WindowManager, CaptureManager
class Cameo(object):
    def __init__(self):
        self._windowManager = WindowManager('Cameo', self.onKeypress)
        self._captureManager = CaptureManager(cv2.VideoCapture(0), self._windowManager, True)
        self._curveFilter = filters.BGRPortraCurveFilter()

    def run(self):
        self._windowManager.createWindow()
        while self._windowManager.isWindowCreated:
            self._captureManager.enterFrame()
            frame = self._captureManager.frame
            filters.strokeEdges(frame,frame)
            self._curveFilter.apply(frame, frame)
            self._captureManager.exitFrame()
            self._windowManager.processEvents()
    def onKeypress(self,keycode):
        if keycode == 32:  # space
            self._captureManager.writeImage('cameo/screenshot.png')
        elif keycode == 9:  # tab
            if not self._captureManager.isWritingVideo:
                self._captureManager.startWritingVideo('cameo/screenshot.avi')
            else:
                self._captureManager.stopWritingVideo()
        elif keycode == 27:    # escape
            self._windowManager.destoryWindow()
        # 读帧

if __name__ == "__main__":
    Cameo().run()

4 - 实验效果

上面3个文件编写好后,就能够实现咱们的效果:描绘边缘并模拟肖像胶卷色彩,而且能够经过修改代码更换所须要的滤波器来实现不一样的效果
在这里插入图片描述 感受把现实风格转换成了美漫风格有木有。