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

1 - 傅里叶变换

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

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

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

2 - 高通滤波器

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

对滤波操作,我们首先要知道核(kernel)的概念

核是指一组权重的集合,它会应用在源图像的一个区域,并由此生成目标图像的一个像素。与卷积神经网络中的卷积核一样,通过选定核的权重与图像进行卷积达到对图像特征的提取
数字图像处理笔记(二):使用OpenCV处理图像_第1张图片

下面我们就通过一段程序来实验一些高通滤波器的作用

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)

原始图像:
数字图像处理笔记(二):使用OpenCV处理图像_第2张图片
经过高通滤波器之后的图像:
数字图像处理笔记(二):使用OpenCV处理图像_第3张图片
可以看到我们把图像的边缘给提取出来了,还是能依稀的看到猫的轮廓

3 - 低通滤波器

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

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)

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

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个文件编写好后,就可以实现我们的效果:描绘边缘并模拟肖像胶卷色彩,并且可以通过修改代码更换所需要的滤波器来实现不同的效果
数字图像处理笔记(二):使用OpenCV处理图像_第4张图片
感觉把现实风格转换成了美漫风格有木有。

你可能感兴趣的:(数字图像处理笔记)