用OCR识别文本的去模糊图像

2024-05-23 14:01:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个模糊的图像:
1 这是名片的一部分,是相机拍摄的一帧,没有适当的焦距

清晰的图像如下所示 2 我正在寻找的方法,可以给我一个更好的图像质量,使图像可以识别的OCR,但也应该是相当快的。图像不太模糊(我想是的),但不利于OCR。我试过:

  • 不同种类的HPF
  • 拉普拉斯人
  • 坎尼探测器
  • 形态操作的组合(打开、关闭)

我还尝试:

  • 用维纳滤波器反褶积
  • 反褶积和Lucy Richardson方法

但要找到正确的点扩散函数并不容易。这些方法被认为是有效的,但不够快。我还尝试了FFT,然后用高斯掩模进行IFFT,但结果并不令人满意。我正在寻找某种用文本消除图像模糊的通用方法,而不仅仅是这个图像。有人能帮我解决这个问题吗?如有任何建议,我将不胜感激。我正在使用OpenCV 3(C++和Python)


Tags: 方法函数图像fftrichardson质量形态焦距
2条回答

你知道Blind deconvolution

盲解卷积是恢复天文图像的一种著名技术。这对于很难找到PSF的应用程序特别有用

^ a2}是该技术的一种C++实现。这个paper也与您正在寻找的内容非常相关。以下是他们算法的示例输出:

enter image description here

我最近也遇到了这个问题,并提出了一个类似的question,其中有更多的细节和最新的方法。到目前为止,这似乎是一个尚未解决的问题。最近有一些研究工作试图通过深入学习解决这些问题。不幸的是,这些作品都没有达到我们的期望。不过,我正在分享这些信息,以防对任何人都有帮助

一,。野外场景文本图像超分辨率

就我们而言,这可能是我们最后的选择;相对而言,表现足够好。这是最近的一项研究工作(TSRN)主要关注此类案例。它的主要直观之处在于引入超分辨率(SR)技术作为预处理。这个implementation看起来是迄今为止最有希望的。这是他们的成就的说明,改善模糊以清洁图像

二,。神经增强

从他们的repo演示来看,它似乎也有一些改进模糊文本的潜力。然而,作者可能在大约4年内没有维持回购协议

三,。基于GAN的盲运动去模糊

吸引人的部分是其中的盲运动去模糊机制,名为DeblurGAN。看起来很有希望

enter image description here

四,。通过核估计和噪声注入实现真实世界的超分辨率

关于their work一个有趣的事实是,与其他文学作品不同,他们首先通过估算各种模糊核以及真实的噪声分布,为现实世界的图像设计了一个新颖的退化框架。基于此,他们获取与真实世界图像共享一个公共域的LR图像。然后,他们提出了一个现实世界的超分辨率模型,旨在更好地感知。从他们的文章中:

enter image description hereenter image description here

然而,在我的观察中,我没有得到预期的结果。我已经提出了一个issue on github,直到现在还没有得到任何回应


用于直接文本去模糊的卷积神经网络

@Ali分享的paper看起来非常有趣,结果非常好。很好,他们共享了经过训练的模型的预训练权重,还共享了python脚本以便于使用。然而,他们已经尝试了Caffe库。我更愿意转换成PyTorch,以便更好地控制。下面是提供的带有Caffe导入的python脚本。请注意,由于缺乏Caffe知识,我无法完全移植它,如果您知道的话,请纠正我

from __future__ import print_function
import numpy as np
import os, sys, argparse, glob, time, cv2, Queue, caffe

# Some Helper Functins 
def getCutout(image, x1, y1, x2, y2, border):
    assert(x1 >= 0 and y1 >= 0)
    assert(x2 > x1 and y2 >y1)
    assert(border >= 0)
    return cv2.getRectSubPix(image, (y2-y1 + 2*border, x2-x1 + 2*border), (((y2-1)+y1) / 2.0, ((x2-1)+x1) / 2.0))

def fillRndData(data, net):
    inputLayer = 'data'
    randomChannels = net.blobs[inputLayer].data.shape[1]
    rndData = np.random.randn(data.shape[0], randomChannels, data.shape[2], data.shape[3]).astype(np.float32) * 0.2
    rndData[:,0:1,:,:] = data
    net.blobs[inputLayer].data[...] = rndData[:,0:1,:,:]

def mkdirp(directory):
    if not os.path.isdir(directory):
        os.makedirs(directory)

主要功能从这里开始

def main(argv):
    pycaffe_dir = os.path.dirname(__file__)

    parser = argparse.ArgumentParser()
    # Optional arguments.
    parser.add_argument(
        " model_def",
        help="Model definition file.",
        required=True
    )
    parser.add_argument(
        " pretrained_model",
        help="Trained model weights file.",
        required=True
    )
    parser.add_argument(
        " out_scale",
        help="Scale of the output image.",
        default=1.0,
        type=float
    )
    parser.add_argument(
        " output_path",
        help="Output path.",
        default=''
    )
    parser.add_argument(
        " tile_resolution",
        help="Resolution of processing tile.",
        required=True,
        type=int
    )
    parser.add_argument(
        " suffix",
        help="Suffix of the output file.",
        default="-deblur",
    )
    parser.add_argument(
        " gpu",
        action='store_true',
        help="Switch for gpu computation."
    )
    parser.add_argument(
        " grey_mean",
        action='store_true',
        help="Use grey mean RGB=127. Default is the VGG mean."
    )
    parser.add_argument(
        " use_mean",
        action='store_true',
        help="Use mean."
    )
    parser.add_argument(
        " adversarial",
        action='store_true',
        help="Use mean."
    )
    args = parser.parse_args()

    mkdirp(args.output_path)

    if hasattr(caffe, 'set_mode_gpu'):
        if args.gpu:
            print('GPU mode', file=sys.stderr)
            caffe.set_mode_gpu()
        net = caffe.Net(args.model_def, args.pretrained_model, caffe.TEST)
    else:
        if args.gpu:
            print('GPU mode', file=sys.stderr)
        net = caffe.Net(args.model_def, args.pretrained_model, gpu=args.gpu)


    inputs = [line.strip() for line in sys.stdin]

    print("Classifying %d inputs." % len(inputs), file=sys.stderr)


    inputBlob = net.blobs.keys()[0] # [innat]: input shape 
    outputBlob = net.blobs.keys()[-1]

    print( inputBlob, outputBlob)
    channelCount = net.blobs[inputBlob].data.shape[1]
    net.blobs[inputBlob].reshape(1, channelCount, args.tile_resolution, args.tile_resolution)
    net.reshape()

    if channelCount == 1 or channelCount > 3:
        color = 0
    else:
        color = 1

    outResolution = net.blobs[outputBlob].data.shape[2]
    inResolution = int(outResolution / args.out_scale)
    boundary = (net.blobs[inputBlob].data.shape[2] - inResolution) / 2

    for fileName in inputs:
        img = cv2.imread(fileName, flags=color).astype(np.float32)
        original = np.copy(img)
        img = img.reshape(img.shape[0], img.shape[1], -1)
        if args.use_mean:
            if args.grey_mean or channelCount == 1:
                img -= 127
            else:
                img[:,:,0] -= 103.939
                img[:,:,1] -= 116.779
                img[:,:,2] -= 123.68
        img *= 0.004

        outShape = [int(img.shape[0] * args.out_scale) ,
                    int(img.shape[1] * args.out_scale) ,
                    net.blobs[outputBlob].channels]
        imgOut = np.zeros(outShape)

        imageStartTime = time.time()
        for x, xOut in zip(range(0, img.shape[0], inResolution), range(0, imgOut.shape[0], outResolution)):
            for y, yOut in zip(range(0, img.shape[1], inResolution), range(0, imgOut.shape[1], outResolution)):

                start = time.time()

                region = getCutout(img, x, y, x+inResolution, y+inResolution, boundary)
                region = region.reshape(region.shape[0], region.shape[1], -1)
                data = region.transpose([2, 0, 1]).reshape(1, -1, region.shape[0], region.shape[1])

                if args.adversarial:
                    fillRndData(data, net)
                    out = net.forward()
                else:
                    out = net.forward_all(data=data)

                out = out[outputBlob].reshape(out[outputBlob].shape[1], out[outputBlob].shape[2], out[outputBlob].shape[3]).transpose(1, 2, 0)

                if imgOut.shape[2] == 3 or imgOut.shape[2] == 1:
                    out /= 0.004
                    if args.use_mean:
                        if args.grey_mean:
                            out += 127
                        else:
                            out[:,:,0] += 103.939
                            out[:,:,1] += 116.779
                            out[:,:,2] += 123.68

                if out.shape[0] != outResolution:
                    print("Warning: size of net output is %d px and it is expected to be %d px" % (out.shape[0], outResolution))
                if out.shape[0] < outResolution:
                    print("Error: size of net output is %d px and it is expected to be %d px" % (out.shape[0], outResolution))
                    exit()

                xRange = min((outResolution, imgOut.shape[0] - xOut))
                yRange = min((outResolution, imgOut.shape[1] - yOut))

                imgOut[xOut:xOut+xRange, yOut:yOut+yRange, :] = out[0:xRange, 0:yRange, :]
                imgOut[xOut:xOut+xRange, yOut:yOut+yRange, :] = out[0:xRange, 0:yRange, :]

                print(".", end="", file=sys.stderr)
                sys.stdout.flush()


        print(imgOut.min(), imgOut.max())
        print("IMAGE DONE %s" % (time.time() - imageStartTime))
        basename = os.path.basename(fileName)
        name = os.path.join(args.output_path, basename + args.suffix)
        print(name, imgOut.shape)
        cv2.imwrite( name, imgOut)

if __name__ == '__main__':
    main(sys.argv)

要运行该程序,请执行以下操作:

cat fileListToProcess.txt | python processWholeImage.py model_def ./BMVC_nets/S14_19_200.deploy pretrained_model ./BMVC_nets/S14_19_FQ_178000.model output_path ./out/ tile_resolution 300 suffix _out.png gpu use_mean

可以从here (BMVC_net)下载权重文件和上述脚本。但是,您可能需要转换caffe2pytorch。为此,以下是基本出发点:

其次,

# BMVC_net, you need to download it from authors website, link above
model = caffemodel2pytorch.Net(
    prototxt = './BMVC_net/S14_19_200.deploy', 
    weights = './BMVC_net/S14_19_FQ_178000.model',
    caffe_proto = 'https://raw.githubusercontent.com/BVLC/caffe/master/src/caffe/proto/caffe.proto'
)

model.cuda()
model.eval()
torch.set_grad_enabled(False)

在演示张量上运行

# make sure to have right procedure of image normalization and channel reordering
image = torch.Tensor(8, 3, 98, 98).cuda()

# outputs dict of PyTorch Variables
# in this example the dict contains the only key "prob"
#output_dict = model(data = image)

# you can remove unneeded layers:
#del model.prob
#del model.fc8

# a single input variable is interpreted as an input blob named "data"
# in this example the dict contains the only key "fc7"
output_dict = model(image)
# print(output_dict)
print(output_dict.keys())
请注意,有一些基本的事情要考虑;网络期望文本的DPI为120-150,方向合理,黑白级别合理。这些网络预计从输入中减去[103.91116.8123.7]。输入值应进一步乘以0.004

相关问题 更多 >