【OCR学习笔记】3、OCR图像预处理之Python原生实现算法(中)

本文涉及的产品
票证核验,票证核验 50次/账号
通用文字识别,通用文字识别 200次/月
小语种识别,小语种识别 200次/月
简介: 【OCR学习笔记】3、OCR图像预处理之Python原生实现算法(中)

1 简介


图像噪声是指存在于图像数据中不必要的或多余的干扰信息,产生于图像的采集、量化或传输过程,对图像的后处理、分析均会产生极大的影响,因此一种好的去噪方法在去除噪声的同时,还需要保持图像的边界和细节。


2 预处理方法之平滑去噪


OCR的预处理方法可以分为以下几个大类:二值化、平滑去噪和倾斜角检测以及校正,脑图如下:

本章由于篇幅的原因,此文只讲解平滑去噪部分,往后更新会把后续的部分更新结束。

由上图可以看出,平滑去噪主要分为空间滤波小波阈值滤波非局部滤波方法以及基于神经网络的滤波方法

2.1 空间滤波

空间滤波由一个邻域和对该邻域内像素执行的预定义操作组成,滤波器中心遍历输入图像的每个像素点之后就得到了处理后的图像。每经过一个像素点,邻域中心坐标的像素值就替换为预定义操作的计算结果。若在图像像素上执行的是线性操作,则该滤波器称为线性空间滤波器,反之则称为非线性空间滤波器

2.1.1 线性空间滤波器

常见的线性空间滤波器有平滑线性滤波高斯滤波器,平滑线性滤波器的输出是包含在滤波器模板邻域内像素的简单平均值,因此也称为均值滤波器

  • 高斯滤波器
    假设构造宽为W、高位H的高斯卷积算子,其中W和H为奇数,锚点位置在,步骤如下:
  • 1、计算高斯矩阵
  • 2、计算高斯矩阵的和
  • 3、高斯矩阵除以其本身的和,即归一化操作,得到高斯卷积算子

高斯卷积算子对应的Python实现如下:

# -*- coding: utf-8 -*-
import numpy as np
from scipy import signal
import math
'''
    得到高斯平滑算子:
    getGaussKernel(sigma,H,W),使用过程中一般H和W一般为奇数,sigma大于零
'''
def getGaussKernel(sigma,H,W):
    '''
        第一步:构建高斯矩阵gaussMatrix
    '''
    gaussMatrix = np.zeros([H,W],np.float32)
    #得到中心点的位置
    cH = (H-1)/2
    cW = (W-1)/2
    #计算1/(2*pi*sigma^2)
    coefficient = 1.0/(2*np.pi*math.pow(sigma,2))
    #
    for r in range(H):
        for c in range(W):
            norm2 = math.pow(r-cH,2) + math.pow(c-cW,2)
            gaussMatrix[r][c] = coefficient*math.exp(-norm2/(2*math.pow(sigma,2)))
    '''
        第二步:计算高斯矩阵的和
    '''
    sumGM = np.sum(gaussMatrix)
    '''
        第三步:归一化,gaussMatrix/sumGM
    '''
    gaussKernel = gaussMatrix/sumGM
    return gaussKernel
#主函数
if __name__ =="__main__":
    gaussKernel = getGaussKernel(2,3,3)
    print(gaussKernel)
    #高斯核gaussKernel是可分解的,可以分解为水平方向和垂直方向的卷积核
    gaussKernel_x = getGaussKernel(2,1,3)
    print(gaussKernel_x)
    gaussKernel_y = getGaussKernel(2,3,1)
    print(gaussKernel_y)
    '''
    水平方向和垂直方向的卷积核进行卷积运算,注意:mode='full',boundary = 'fill',fillvalue=0
    这样的参数设置,得到的结果才和gaussKernel完全相等,否则,边界不相等
    '''
    gaussKernel_xy = signal.convolve2d(gaussKernel_x,gaussKernel_y,mode='full',boundary ='fill',fillvalue=0)
    print(gaussKernel_xy)


  • 均值滤波器
    均值滤波,顾名思义就是把图像中的每一个位置的领域的平均值作为该位置的输出值,代码实现与分离的高斯卷积是类似的,只需要将高斯算子替换成均值算子即可。

均值平滑算子对应的Python实现如下:

# -*- coding: utf-8 -*-
import sys
import numpy as np
from scipy import signal
import cv2
# 均值平滑
def meanBlur(image,H,W,_boundary='fill',_fillvalue=0):
    # H、W均不为零
    if H==0 or W==0:
        print 'W or H is not zero'
        return image
    # 没有对均值平滑算子进行分离
    #meanKernel = 1.0/(H*W)*np.ones([H,W],np.float32)
    #result = signal.convolve2d(image,meanKernel,mode='same',boundary = _boundary,fillvalue=_fillvalue)
    # 卷积后进行数据类型转换,得到均值平滑的结果
    #result = result.astype(np.uint8)
    #return result
    # 因为均值算子是可分离的卷积核,根据卷积运算的结合律
    # 可以先进行水平方向的卷积,
    # 再进行垂直方向的卷积
    # 首先水平方向的均值平滑
    meanKernel_x = 1.0/W*np.ones([1,W],np.float32)
    i_conv_mk_x = signal.convolve2d(image,meanKernel_x,mode='same',boundary = _boundary,fillvalue=_fillvalue)
    # 然后对得到的水平卷积的结果再进行垂直方向的卷积
    meanKernel_y = 1.0/H*np.ones([H,1],np.float32)
    i_conv_xy = signal.convolve2d(i_conv_mk_x,meanKernel_y,mode='same',boundary = _boundary,fillvalue=_fillvalue)
    i_conv_xy = np.round(i_conv_xy)
    # 卷积后的结果进行数据类型转换,得到均值平滑的结果
    result = i_conv_xy.astype(np.uint8)
    return result
#主函数:示例
if __name__ =="__main__":
    if len(sys.argv)>1:
        image = cv2.imread(sys.argv[1],cv2.CV_LOAD_IMAGE_GRAYSCALE)
    else:
        print("Usge:python meanBlur.py imageFile")
    # 均值滤波卷积核的宽高均设为 2*halfWinSize+1
    halfWinSize = 1
    MAX_HALFWINSIZE = 20
    cv2.namedWindow("meanBlur",1)
    # 回调函数,均值滤波
    def callback_meanBlur(_halfWinSize):
        result = meanBlur(image,2*_halfWinSize+1,2*_halfWinSize+1,_boundary='symm',_fillvalue=0)
        cv2.imshow("meanBlur",result)
    callback_meanBlur(halfWinSize)
    cv2.createTrackbar("winSize/2","meanBlur",halfWinSize,MAX_HALFWINSIZE,callback_meanBlur)
    latexImage = meanBlur(image,29,29,'symm')
    cv2.imwrite("latexImage.png",latexImage)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

2.1.2 非线性空间滤波器

  • 中值滤波
    是一种非线性数字滤波器。与上述滤波不同,其首先是对邻域内的值进行排序,中值作为输出。该滤波器消除椒盐噪声的效果比平滑线性空间滤波器更好。
    中值滤波对应的Python实现如下:
# -*- coding: utf-8 -*-
import sys
import numpy as np
import cv2
# 中值滤波 
def medianBlur(image,winSize):
    # 图像的宽高
    rows,cols = image.shape
    # 窗口的宽高,均为奇数
    winH,winW = winSize
    halfWinH = (winH-1)/2
    halfWinW = (winW-1)/2
    # 中值滤波后的输出图像
    medianBlurImage = np.zeros(image.shape,image.dtype)
    for r in range(rows):
        for c in range(cols):
            # 判断边界
            rTop = 0 if r-halfWinH < 0 else r-halfWinH
            rBottom = rows-1 if r+halfWinH > rows-1 else r+halfWinH
            cLeft = 0 if c-halfWinW < 0 else c-halfWinW
            cRight = cols-1 if c+halfWinW > cols-1 else c+halfWinW
            # 取中值的区域
            region = image[rTop:rBottom+1,cLeft:cRight+1]
            # 求中值
            medianBlurImage[r][c] = np.median(region)
    return medianBlurImage
# 主函数
if __name__ =="__main__":
    if len(sys.argv)>1:
        image = cv2.imread(sys.argv[1],cv2.CV_LOAD_IMAGE_GRAYSCALE)
    else:
        print("Usge:python medianBlur.py imageFile")
    # 显示原图
    cv2.imshow("image",image)
    # 中值滤波
    medianBlurImage = medianBlur(image,(3,3))
    # 显示中值滤波后的结果
    cv2.imshow("medianBlurImage",medianBlurImage)
    cv2.imwrite("medianBlurImage.jpg",medianBlurImage)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
  • 双边滤波(Bilateral Filter)
    不仅如高斯滤波一样考虑到像素间的欧氏距离,还关注到像素范围域中的辐射差异(如像素与中心间的相似程度、颜色强度和深度距离等),这两个权重域分别称为:空间域(Spatial Domain S)和像素范围域(Range Domain R)。权重的计算公式如下:a0a267b4bdde4779aa73030fb3424d39.png

其中,和是平滑参数,和分别是像素和的强度函数。计算权重之后,对结果做归一化,公式如下:

其中,是去噪后的像素强度。

双边滤波对应的Python实现如下:

# -*- coding: utf-8 -*-
import sys
import numpy as np
import cv2
import math
# 基于空间距离的权重模板 ( 和计算高斯算子的过程是一样的 )
def getClosenessWeight(sigma_g,H,W):
    r,c = np.mgrid[0:H:1, 0:W:1]
    r -= (H-1)/2
    c -= (W-1)/2
    closeWeight = np.exp(-0.5*(np.power(r,2)+np.power(c,2))/math.pow(sigma_g,2))
    return closeWeight
# BilateralFiltering 双边滤波,返回的数据类型为浮点型
def bfltGray(I,H,W,sigma_g,sigma_d):
    # 构建空间距离的权重模板
    closenessWeight = getClosenessWeight(sigma_g,H,W)
    # 模板的中心点位置
    cH = (H -1)/2
    cW = (W -1)/2
    # 图像矩阵的行数和列数
    rows,cols = I.shape
    #双边滤波后的结果
    bfltGrayImage = np.zeros(I.shape,np.float32)
    for r in range(rows):
        for c in range(cols):
            pixel = I[r][c]
            # 判断边界
            rTop = 0 if r-cH < 0 else r-cH
            rBottom = rows-1 if r+cH > rows-1 else r+cH
            cLeft = 0 if c-cW < 0 else c-cW
            cRight = cols-1 if c+cW > cols-1 else c+cW
            # 权重模板作用的区域
            region = I[rTop:rBottom+1,cLeft:cRight+1]
            # 构建灰度值相似性的权重因子
            similarityWeightTemp = np.exp(-0.5*np.power(region -pixel,2.0)/math.pow(sigma_d,2))        
            closenessWeightTemp = closenessWeight[rTop-r+cH:rBottom-r+cH+1,cLeft-c+cW:cRight-c+cW+1]
            # 两个权重模板相乘
            weightTemp = similarityWeightTemp*closenessWeightTemp
            weightTemp = weightTemp/np.sum(weightTemp)
            bfltGrayImage[r][c] = np.sum(region*weightTemp)
    return bfltGrayImage
# 主函数
if __name__ =="__main__":
    if len(sys.argv)>1:
        image = cv2.imread(sys.argv[1],cv2.CV_LOAD_IMAGE_GRAYSCALE)
    else:
        print("Usge:python BFilter.py imageFile")
    # 显示原图
    cv2.imshow("image",image)
    cv2.imwrite("image.png",image)
    # 将灰度值归一化
    image = image/255.0
    # 双边滤波
    bfltImage = bfltGray(image,33,33,10,0.8)
    # 显示双边滤波的结果
    cv2.imshow("BilateralFiltering",bfltImage)
    bfltImage = bfltImage*255.0
    bfltImage = np.round(bfltImage)
    bfltImage = bfltImage.astype(np.uint8)
    # 保存双边滤波的结果
    cv2.imwrite("BilateralFiltering.png",bfltImage)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

2.2 小波阈值去噪

对于二维图像信号,可分别在水平和垂直的方向使用滤波器,从而实现二维小波多分辨率分解。如下图为经过小波三层多分辨率分解之后子图像的划分。

其中,LL子带是在两个方向利用低通小波滤波器产生的小波系数,表示图像的近似;HL子带是在行方向利用低通小波滤波器后,再用高通小波滤波器在列方向卷积产生的系数,表示图像水平方向的奇异特性;LH子带是在行方向利用高通小波滤波器后,再用低通小波滤波器在列方向卷积产生的系数,表示图像垂直方向的奇异特性;HH子带是在两个方向利用高通小波滤波器产生的小波系数,表示图像的对角边缘特性。通常情况下,噪声部分包含在HL、LH和HH中,只要对这三部分作相应的小波系数处理,最后进行重构即可达到消噪的目的。

小波去噪的基本思路

1)二维图像的小波分解:选择一个小波和小波分解的层次N,计算信号s到第N层的分解。

2)对高频系数进行阈值量化:对1~N的每一层选择阈值,并对该层的高频系数进行软阈值量化处理。

3)二维小波重构:根据小波分解第N层的低频系数和经过修改的第一到第N层的各层高频系数,计算二维信号的小波重构。

2.3 非局部方法

2.3.1 NL-Means

A.Buades等人于2005年首次将Non-Local理论应用于图像去噪,提出了基于图像所有像素的非局部均值算法(NL-means),他们对去噪方法Dh做了如下定义:

b68b7d8f4787bd4b12aa2a5bb562caee.png

其中,v是带噪声的图像,n是滤波参数,通常取决于噪声的标准偏差。理想情况下,比v更加平滑,为白噪声。给定离散噪声图像,对于像素i,估计值NL[v]|(i)为图像中所有像素的加权平均值:

95de2701428a513cda97c38735a8cebd.png

其中,权重取决于像素i、j间的相似性,且。而所谓的相似性,则进一步取决于强度灰度级向量和的相似性。其中,表示以像素k为中心固定大小的正方形邻域,该相似度被定义为加权欧式距离的递减函数:,a是高斯核的标准差。与相近的灰阶邻域像素在平均值上有较大的权重:0a44dcadb077009512576cf8ae005c73.png

其中,是归一化常数,参数h表示影响过滤程度。通过控制指数函数的衰减,可以降低权重。

2.3.2 BM3D

BM3D(Block-Matching 3D Filtering)是当前效果最好的算法之一。它与NL-means算法具有相似之处在于同样运用到了非局部块匹配的思想,但其复杂度远高于NL-Means。

BM3D共包含两大步骤,每一步里又包括相似块分组、协同滤波和聚合。找到相似块后,不同于NL-means的均值处理,BM3D会对其做域转换操作,利用协同过滤以降低相似块自身的噪声,并在聚合阶段对相似块进行加权处理。

e172d218eba2d48a804f83d7f3451f10.png

BM3D算法具体步骤:

第1步:基础估计

1)相似块分组:首先在噪声图像中选择参照块,在参照块周围适当大小区域内进行搜索,寻找若干个差异度最小的块,与参照块一起整合成一个三维的矩阵。距离函数的公式如下:

447da7edd2d747b7bb7b9c4eb96d8af4.png

其中,表示以像素R为中心的参照块,为搜索块,为第一步的块大小,为L2距离,Y'为硬阈值操作,为归一化后的二维线性操作。根据距离找到的相似块集合可用如下公式表示:

8ab118959decbdb8b8f00c3fc7a0c1e2.png

其中,为判断是否相似的超参数。

2)协同滤波:先使用归一化的3D线性变换降低相似块中的噪声,再使用对应的反变换得到处理后的相似块:

f7c793c684327dc5482abf6417293dba.png

其中,为归一化的3D线性变换,为对应的反变换,为硬阈值操作,为处理后的相似块。这一步可以有效避免NL-means均值操作导致的相似块信息冗余和引入参照块自身包含的噪声这两大问题。

3)聚合:对上一步处理后得到的相似块进行加权平均值操作得到目标块的像素值:5c52d21ed369fcee8b3c5d40273a9639.png

其中,为权重。

第2步:最终估计

1)相似块分组:对步骤一初步处理后的图像,重新计算L2距离,得到相似块集合:a9d2b369be43c4d2c966b224b1e7c280.png

其中,为判断是否为相似块的超参数。

2)协同过滤:对第一步得到的相似块集合做域变换后,使用维纳收缩系数加权,再经过反变换得到新的集合:

62659d0972652eff5594ae33d68381da.png

其中,为维纳收缩系数。为相似块集合。

3)聚合:与步骤1的聚合操作相似,最终结果与2)一致:

742e4ba8226c3db409464010b52e5170.png

BM3D算法对应的pybm3d库函数使用如下:

import numpy as np
import skimage.data
from skimage.measure import compare_psnr
import pybm3d
noise_std_dev = 40
img = skimage.data.astronaut()
noise = np.random.normal(scale=noise_std_dev, size=img.shape).astype(img.dtype)
noisy_img = img + noise
out = pybm3d.bm3d.bm3d(noisy_img, noise_std_dev)
noise_psnr = compare_psnr(img, noisy_img)
out_psnr = compare_psnr(img, out)
print("PSNR of noisy image: ", noise_psnr)
print("PSNR of reconstructed image: ", out_psnr)

2.4 基于深度学习的方法

2.4.1 MLP

Harold Christopher Burger等人于2012年提出了使用多层感知机(MLP)实现图像去噪的思想,从而探讨深度学习在文字识别任务上是否有必要。整体的网络结构非常简单,含有两层隐藏层的MLP可用如下公式表示:

266f7c653bb0c8212244e6f68239ca3c.png

训练时,以三步长将图像分割为图像块,随机选择一个原始图像块x,加入高斯白噪声,生成对应的噪声图像y,网络将根据和y误差的反向传播进行参数更新。

2.4.2 LLNet

LLNet通过引入序贯相似性检测算法(SSDA)的思想实现低噪度图片的自适应增强(增亮、去噪)。

LLNet利用了我绝望了的降噪能力和深度网络的复杂建模能力来学习低噪度图片的特征并生成含有最少噪声和更高对比度的图片。LLNet的结构如图所示:

LLNet的训练流程如图所示:

其中,训练图片被人工调低亮度并添加噪声。LLNet通过重构图像与原始图像误差的反向传播调整参数。

相关文章
|
2月前
|
算法 数据可视化 数据挖掘
基于EM期望最大化算法的GMM参数估计与三维数据分类系统python源码
本内容展示了基于EM算法的高斯混合模型(GMM)聚类实现,包含完整Python代码、运行效果图及理论解析。程序使用三维数据进行演示,涵盖误差计算、模型参数更新、结果可视化等关键步骤,并附有详细注释与操作视频,适合学习EM算法与GMM模型的原理及应用。
|
2月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
63 1
|
2月前
|
机器学习/深度学习 监控 算法
基于单尺度Retinex和多尺度Retinex的图像增强算法实现
基于单尺度Retinex(SSR)和多尺度Retinex(MSR)的图像增强算法实现
162 1
|
2月前
|
存储 算法 数据安全/隐私保护
基于FPGA的图像退化算法verilog实现,分别实现横向和纵向运动模糊,包括tb和MATLAB辅助验证
本项目基于FPGA实现图像运动模糊算法,包含横向与纵向模糊处理流程。使用Vivado 2019.2与MATLAB 2022A,通过一维卷积模拟点扩散函数,完成图像退化处理,并可在MATLAB中预览效果。
|
2月前
|
存储 监控 算法
基于 Python 跳表算法的局域网网络监控软件动态数据索引优化策略研究
局域网网络监控软件需高效处理终端行为数据,跳表作为一种基于概率平衡的动态数据结构,具备高效的插入、删除与查询性能(平均时间复杂度为O(log n)),适用于高频数据写入和随机查询场景。本文深入解析跳表原理,探讨其在局域网监控中的适配性,并提供基于Python的完整实现方案,优化终端会话管理,提升系统响应性能。
73 4
|
3月前
|
PyTorch 算法框架/工具 C++
人工智能算法python程序运行环境安装步骤整理
本教程详细介绍Python与AI开发环境的配置步骤,涵盖软件下载、VS2017安装、Anaconda配置、PyCharm设置及组件安装等内容,适用于Windows系统,助你快速搭建开发环境。
|
2月前
|
监控 算法 决策智能
基于盲源分离与贝叶斯非局部均值的图像降噪算法
基于盲源分离与贝叶斯非局部均值的图像降噪算法
76 0
|
3月前
|
算法 数据安全/隐私保护
基于混沌加密的遥感图像加密算法matlab仿真
本项目实现了一种基于混沌加密的遥感图像加密算法MATLAB仿真(测试版本:MATLAB2022A)。通过Logistic映射与Baker映射生成混沌序列,对遥感图像进行加密和解密处理。程序分析了加解密后图像的直方图、像素相关性、信息熵及解密图像质量等指标。结果显示,加密图像具有良好的随机性和安全性,能有效保护遥感图像中的敏感信息。该算法适用于军事、环境监测等领域,具备加密速度快、密钥空间大、安全性高的特点。
|
4月前
|
算法 Python
Apriori算法的Python实例演示
经过运行,你会看到一些集合出现,每个集合的支持度也会给出。这些集合就是你想要的,经常一起被购买的商品组合。不要忘记,`min_support`参数将决定频繁项集的数量和大小,你可以根据自己的需要进行更改。
163 18

热门文章

最新文章

推荐镜像

更多