专栏首页贾志刚-OpenCV学堂图形图像算法中必须要了解的设计模式(1)

图形图像算法中必须要了解的设计模式(1)

图形图像算法中必须要了解的设计模式(1)

随着信息的多元化,信息的概念不仅仅指的是文字,它还包含图片、声音、视频等其它丰富的信息。文字信息越来越多地被图片、声音、视频信息所替代,而视频又是由一针一针的图像组成的,因此图形图像的处理变得越来越热门和重要,众多的专家、学者、工程师投入到这个领域。

作为一个图像算法的研究者,写出一手高级算法当然是令人兴奋的一件事!但你是否有时会有这种感觉:

  1. 写的算法很难通用于所有的数据类型!每来一个新类型的数据,又得改一下算法,或新加一个方法来支持这种类型。
  2. 有时候多个算法需要灵活组合,甚至每个算法的顺序不一样都会产生不一样的效果;每一种组合都要为其构建一个新算法,即累又麻烦。
  3. 算法越来越多,自建的算法库也越来越庞大而难于管理;

这个时候,让你的算法具有更好通用性、拓展性就显得极为重要!因此,你必须要掌握几个重要的设计模式来解决这些问题。今天介绍其中一个最重要的设计模式——装饰模式

装饰模式

装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。

  • 装饰模式可以动态地给一个对象附加更多的功能。
  • 用不同的算法作为装饰器进行多重装饰,可以达到不同算法的灵活组合;装饰的顺序不同,可能产生不同的效果。

应用案例

静态图像其实就是一个二维的像素数组,对图像的处理其实就是对一个二维坐标像素数据的处理。在图像处理中,图像的灰度化、梯度化(锐化)、边缘化、二值化都是图像处理的基本算法,在进行真正的核心算法之前,经常需要进行这些预处理。

如我曾经在开发的一个用于医疗影像领域的细胞检测和识别项目时,就用到这样的一些处理过程:

  1. 将图像规格化(将所有图片缩放到 800*600)
  2. 平滑去噪处理
  3. 图像的灰度化
  4. 图像的梯度化
  5. 图像的二值化
  6. 真正的识别处理,进行ORI区域识别。

这些预处理算法的顺序不同,将对结果产生很大的影响。

下面我们将以图像的边缘提取算法为例演示整个处理过程,为简单起见,假设有两个预处理过程(灰度化、梯度化)和一个核心算法(二值化边缘提取)。有两种处理顺序,分别如下:

  • 灰度化 --> 梯度化 --> 核心算法:边缘提取算法:
  • 梯度化 --> 灰度化 --> 核心算法:边缘提取算法:

如果你来实现,代码会怎么实现呢? ... ... 也许你会说那还不简单!立马就能想到针对两个处理顺序分别写两个方法:

def imageProcessing1():
    print("算法逻辑")
    # todo Something

def imageProcessing2():
    print("算法逻辑")
    # todo Something

那问题来了,如果预处理的过程不止2种,而是有5种;那就会有5! = 120种排列,难道你要写120个方法?想想都可怕!

如果你用装饰模式,那上面这个问题只要两行代码就能搞定:

resultImg1 = GrayProcessor(GradientProcessor(EdgeExtractionProcessor())).processing(img)
resultImg2 = GradientProcessor(GrayProcessor(EdgeExtractionProcessor())).processing(img)

两种处理顺序的图片预览效果如下: 原图

处理顺序1:灰度化 --> 梯度化 --> 核心算法:边缘提取算法

灰度化:

梯度化:

边缘提取

处理顺序2:梯度化 --> 灰度化 --> 核心算法:边缘提取算法

梯度化:

灰度化:

边缘提取:

这里两种不同的预处理顺序,结果是有略微不同的。想知道我是如何将这个代码精简到两行的吗?这都得归功于装饰模式,下面就一起看看装饰模式的实现方式吧!(下面这段代码用OpenCv for Python实现,Python 3.6.3,opencv-3.4.1,numpy-1.14.5)

from abc import ABCMeta, abstractmethod
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法

class ImageProcessor(metaclass=ABCMeta):
    "图像处理的接口类"

    @abstractmethod
    def processing(self, img):
        "图像处理的抽象方法"
        pass

class EdgeExtractionProcessor(ImageProcessor):
    "边缘提取算法"

    def processing(self, img):
        super().processing(img)
        print("真正的核心算法:边缘提取算法")
        newImg = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5, 10)
        return newImg


class ImageDecorator(ImageProcessor):
    "图像装饰器"

    def __init__(self, processor):
        self._decorator = processor

    def processing(self, img):
        tmpImg = self.preProcessing(img)
        return self._decorator.processing(tmpImg)

    @abstractmethod
    def preProcessing(self, img):
        "预处理方法,由子类实现"
        pass


class GrayProcessor(ImageDecorator):
    "灰度化处理器"

    def __init__(self, processor):
        super().__init__(processor)

    def preProcessing(self, img):
        print("灰度化处理...")
        return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换了灰度化


class GradientProcessor(ImageDecorator):
    "梯度化处理器"

    def __init__(self, processor):
        super().__init__(processor)

    def preProcessing(self, img):
        print("梯度化处理...")
        x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
        y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
        absX = cv2.convertScaleAbs(x)  # 转回uint8
        absY = cv2.convertScaleAbs(y)
        return cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

测试代码如下:

def testImageProcessing():
    img = cv2.imread("E:\\TestImages\\bird.jpg")
    print("灰度化 --> 梯度化 --> 核心算法:边缘提取算法:")
    resultImg1 = GrayProcessor(GradientProcessor(EdgeExtractionProcessor())).processing(img)
    print()

    print("梯度化 --> 灰度化 --> 核心算法:边缘提取算法:")
    resultImg2 = GradientProcessor(GrayProcessor(EdgeExtractionProcessor())).processing(img)
    print()

    cv2.imshow("The result of image process1", resultImg1)
    cv2.imshow("The result of image process2", resultImg2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

结果如下:

灰度化 --> 梯度化 --> 核心算法:边缘提取算法:
灰度化处理...
梯度化处理...
真正的核心算法:边缘提取算法

梯度化 --> 灰度化 --> 核心算法:边缘提取算法:
梯度化处理...
灰度化处理...
真正的核心算法:边缘提取算法

Get到技能点了吗?

本文分享自微信公众号 - OpenCV学堂(CVSCHOOL)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-07-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 不用 ps 都可以获得双色调图片

    伪君子
  • 厉害!这还是我认识的Python吗!

    Python 可用的地方非常多。无论是从入门级选手到专业级数据挖掘、科学计算、图像处理、人工智能,Python 都可以胜任。或许是因为这种万能属性,周围好更多的...

    AI科技大本营
  • 自然语言处理之文本卷积

    自然语言处理之文本卷积 1.文本的向量表示 2.文本的1维卷积 3.池化

    我爱自然语言处理
  • 深度学习(5)——RBF算法简介

    DC童生
  • 视觉算法岗秋招总结分享——教你如何准备

    牛客网
  • 如何让摄像头变成“暗夜之眼”?英特尔开发了一套基于FCN的成像系统

    【AI科技大本营导读】手机拍照的重要性不必多说,不论是国外的苹果、三星,还是国内的华为、小米,都在提升拍照性能上下足了功夫,目前的手机摄像头已经逐渐从单摄走向双...

    AI科技大本营
  • YVU格式Y分量存储为灰度

     Image为Android 5.0以上提供的类,用于保存YUV420格式的集合。

    jerrypxiao
  • 不会PS的小白也可以轻松在线抠图的三个网站

    雨尘
  • 卷积神经网络CNN的意义

    郭耀华
  • Python截屏扩展库pyscreenshot安装与使用

    PIL是非常成熟的Python图像处理扩展库,但只支持Python 2.x,另一个同样功能的扩展库pillow完美支持Python 3.x。然而,这两个库的部分...

    Python小屋屋主

扫码关注云+社区

领取腾讯云代金券