title: 计算机视觉(三)-图像处理
date: 2020-03-12 22:34:33
categories:

  • 理论
  • 计算机视觉
    tags:
  • 理论
  • 计算机视觉
    mathjax: true
    copyright:

1. 概述

  • 本系列主要记录入门计算机视觉领域的基础知识

2. 点算子

  • 亮度、对比度的校正,彩色的校正和变换

2.1 像素变换

  • 一个或多个输入图像到一个输出图像的函数,在连续域中将其表示为

$g(x) = h(f(x))$或者$g(x) = h(f_0(x), \dots, f_n(x))$

  • 常用的两个点算子是乘以和加上一个常数

$g(x) = af(x) + b$.

  • 线性混合算子
    • 可以使两幅图像或者视频间的时间上的淡入和淡出

$g(x) = (1 - \alpha)f_0(x) + \alpha f_1(x)$.

  • 伽马校正算子

$g(x) = [f(x)]^{\frac{1}{\gamma}}$.

2.1 直方图均衡化

  • 当图像直方图完全均匀分布的时候,此时图像的熵是最大的(随机变量每个值的概率都相同时,概率最大),图像对比度是最大的。所以,理想情况下,图像经过变换函数f(x)f(x)f(x)变换后,直方图能够均匀分布,此时对比度是最大的
  • 提高图像对比度的变换函数f(x)f(x)f(x)需要满足以下条件
    • f(x)在0 <= x <= L−1上单调递增(不要求严格单调递增),其中L表示灰度级(L=256)
    • f(x)的范围是[0,L−1]
  • 在图像处理中,有一个函数,能够满足上面的条件

$y = f(x) = (L-1)\int_p^x p_x(t)dt$,

其中p(x)表示概率密度函数,在离散的图像中,表示直方图的每个灰度级的概率。f(x)其实就是连续型随机变量x的分布函数,表示的是函数下方的面积。

接下来证明经过该函数变换能够实现直方图均匀化。

由概率论知识,变换后的概率密度为

$p_y(y) = p_x(x)|(f^{-1}(y))’|$.

由变上限函数求导法则可知:

$f(x)’ = (L-1)p_x(x)$.

反函数的导数等于原函数导数的倒数:

$(f^{-1}(y))’ = \frac{1}{(L-1)p_x(x)}$.

所以,

$p_y(y) = \frac{1}{L-1}$.

变换后的概率密度函数是一个均匀分布,对于图像来说,就是每个灰度级概率都是相等的,达到了我们的目的。将这个变换函数转换为图像中的表达,图像中,我们可以知道,可以使用求和代替积分,差分代替微分,所以上述的变换函数为:

$y = f(x) = (L-1)\sum_{0}^{x_i}\frac{h(x_i)}{w\times h}$.

其中,$h(x_i)$表示直方图中每个灰度级像素的个数,$w$和$h$分别表示图像的宽和高。

  • 本质

    • 扩展了像素的动态范围
  • 算法

    • 输入:图像

    • 输出:均衡化后图像

    • 算法过程

      • 求出图像的恢复直方图,h(一个256维的向量)

      • 求出图像的总体像素个数机器所占百分比

        $N_f = m\times n$,

        $hs(i) = h(i) / N_f, i = 0, 1, \dots, 255$.

      • 计算图像各灰度级的累计分布hp

        $hp(i) = \sum_{k=0}^{i}h(k), i = 1, 2, \dots, 255$.

      • 计算新图像的灰度值

        $g = 255 * hp(i), i = 1, 2, \dots, 255$.

        $g = 0, i = 0$.

  • 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#coding:utf-8

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread('source.jpg')
im_gray = cv.cvtColor(img,cv.COLOR_RGB2GRAY)
cv.imshow('im_gray',im_gray)

w, h = im_gray.shape[0], im_gray.shape[1]

plt.figure()
p1 = plt.hist(im_gray.reshape(im_gray.size,1))

#创建直方图
n = np.zeros((256),dtype = np.float)
p = np.zeros((256),dtype = np.float)
c = np.zeros((256),dtype = np.float)

#遍历图像的每个像素,得到统计分布直方图
for x in range(0,im_gray.shape[0]):
for y in range(0,im_gray.shape[1]):
n[im_gray[x][y]] += 1
print(n)

#归一化
for i in range(0, 256):
p[i] = n[i] / float(im_gray.size)

#计算累积直方图
c[0] = p[0]
for i in range(1,256):
c[i] = c[i-1] + p[i]
print(c)

des = np.zeros((w, h), dtype=np.uint8)
for x in range(0, w):
for y in range(0, h):
des[x][y] = 255 * c[im_gray[x][y]]
print(des)

cv.imshow('des',des)
plt.figure()
p2 = plt.hist(des.reshape(des.size, 1))

plt.show()

2.2 连通量

  • 在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接。4邻接一共4个点,即上下左右;8邻接的点一共有8个,包括了对角线位置的点
  • 如果像素点A与B邻接,我们称A与B连通
  • 如果A与B连通,B与C连通,则A与C连通
  • 在视觉上看来,彼此连通的点形成了一个区域,而不连通的点形成了不同的区域。这样的一个所有的点彼此连通点构成的集合,我们称为一个连通区域
  • 常见算法
    • 第一种算法是现在matlab中连通区域标记函数bwlabel中使的算法,它一次遍历图像,并记下每一行(或列)中连续的团(run)和标记的等价对,然后通过等价对对原来的图像进行重新标记,这个算法是目前我尝试的几个中效率最高的一个,但是算法里用到了稀疏矩阵与Dulmage-Mendelsohn分解算法用来消除等价对,这部分原理比较麻烦
    • 第二种算法是现在开源库cvBlob中使用的标记算法,它通过定位连通区域的内外轮廓来标记整个图像,这个算法的核心是轮廓的搜索算法,这个我们将在文章中详细介绍。这个算法相比与第一种方法效率上要低一些,但是在连通区域个数在100以内时,两者几乎无差别,当连通区域个数到了103103数量级时,上面的算法会比该算法快10倍以上

参考