Image processing 提高tesseract OCR精度的图像处理

Image processing 提高tesseract OCR精度的图像处理,image-processing,ocr,tesseract,Image Processing,Ocr,Tesseract,我一直在使用tesseract将文档转换为文本。文档的质量参差不齐,我正在寻找关于什么样的图像处理可以改善结果的技巧。我注意到,高度像素化的文本(例如传真机生成的文本)对于tesseract来说尤其难以处理——可能所有字符的锯齿边缘都会混淆形状识别算法 什么样的图像处理技术可以提高准确性?我一直在使用高斯模糊来平滑像素化图像,并看到了一些小的改进,但我希望有一种更具体的技术可以产生更好的结果。比如说,一个调整为黑白图像的过滤器,它可以平滑不规则的边缘,然后是一个过滤器,它可以增加对比度,使字符更

我一直在使用tesseract将文档转换为文本。文档的质量参差不齐,我正在寻找关于什么样的图像处理可以改善结果的技巧。我注意到,高度像素化的文本(例如传真机生成的文本)对于tesseract来说尤其难以处理——可能所有字符的锯齿边缘都会混淆形状识别算法

什么样的图像处理技术可以提高准确性?我一直在使用高斯模糊来平滑像素化图像,并看到了一些小的改进,但我希望有一种更具体的技术可以产生更好的结果。比如说,一个调整为黑白图像的过滤器,它可以平滑不规则的边缘,然后是一个过滤器,它可以增加对比度,使字符更加清晰

对于图像处理新手,有什么一般性的建议吗

  • 固定DPI(如果需要)最小为300 DPI
  • 固定文本大小(例如,12磅应该可以)
  • 尝试修复文本行(反斜和反斜文本)
  • 尝试固定图像的照明(例如,图像中没有黑暗部分)
  • 图像二值化与去噪
  • 没有适合所有情况的通用命令行(有时需要模糊和锐化图像)。但是你可以试试看


    如果你不喜欢命令行,也许你可以尝试使用开源或商业软件。

    我绝对不是OCR专家。但本周我需要将jpg中的文本转换成文本

    我从彩色RGB 445x747像素jpg开始。 我立即尝试了tesseract,但程序几乎没有转换任何内容。 然后我进入GIMP并做了以下操作。 图像>模式>灰度 图像>缩放图像>1191x2000像素 过滤器>增强>取消锐化遮罩,其值为半径=6.8,数量=2.69,阈值=0 然后我以100%的质量保存为新的jpg

    然后,Tesseract能够将所有文本提取到一个.txt文件中


    Gimp是你的朋友。

    这是很久以前的事了,但它可能仍然有用

    我的经验表明,在将图像传递给tesseract之前在内存中调整图像大小有时会有所帮助


    尝试不同的插值模式。这篇文章对我帮助很大。

    在这方面对我帮助最大的是Capture2Text项目的源代码。

    顺便说一句:它的作者分享了这样一个辛苦的算法,真是太好了

    请特别注意Capture2Text\SourceCode\leptonica\u util\leptonica\u util.c文件-这是此实用程序图像预处理的核心

    如果要运行二进制文件,可以在Capture2Text\Output\folder中检查进程前后的图像转换


    注意:上述解决方案使用Tesseract进行OCR和Leptonica进行预处理。

    三点可提高图像的可读性:

  • 使用可变高度和宽度调整图像大小(用图像高度和宽度乘以0.5、1和2)。

  • 将图像转换为灰度格式(黑白)。

  • 去除噪声像素并使图像更清晰(过滤图像)。

  • 请参阅以下代码:

    调整大小

    public Bitmap Resize(Bitmap bmp, int newWidth, int newHeight)
            {
             
                    Bitmap temp = (Bitmap)bmp;
                
                    Bitmap bmap = new Bitmap(newWidth, newHeight, temp.PixelFormat);
                 
                    double nWidthFactor = (double)temp.Width / (double)newWidth;
                    double nHeightFactor = (double)temp.Height / (double)newHeight;
    
                    double fx, fy, nx, ny;
                    int cx, cy, fr_x, fr_y;
                    Color color1 = new Color();
                    Color color2 = new Color();
                    Color color3 = new Color();
                    Color color4 = new Color();
                    byte nRed, nGreen, nBlue;
    
                    byte bp1, bp2;
    
                    for (int x = 0; x < bmap.Width; ++x)
                    {
                        for (int y = 0; y < bmap.Height; ++y)
                        {
    
                            fr_x = (int)Math.Floor(x * nWidthFactor);
                            fr_y = (int)Math.Floor(y * nHeightFactor);
                            cx = fr_x + 1;
                            if (cx >= temp.Width) cx = fr_x;
                            cy = fr_y + 1;
                            if (cy >= temp.Height) cy = fr_y;
                            fx = x * nWidthFactor - fr_x;
                            fy = y * nHeightFactor - fr_y;
                            nx = 1.0 - fx;
                            ny = 1.0 - fy;
    
                            color1 = temp.GetPixel(fr_x, fr_y);
                            color2 = temp.GetPixel(cx, fr_y);
                            color3 = temp.GetPixel(fr_x, cy);
                            color4 = temp.GetPixel(cx, cy);
    
                            // Blue
                            bp1 = (byte)(nx * color1.B + fx * color2.B);
    
                            bp2 = (byte)(nx * color3.B + fx * color4.B);
    
                            nBlue = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
    
                            // Green
                            bp1 = (byte)(nx * color1.G + fx * color2.G);
    
                            bp2 = (byte)(nx * color3.G + fx * color4.G);
    
                            nGreen = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
    
                            // Red
                            bp1 = (byte)(nx * color1.R + fx * color2.R);
    
                            bp2 = (byte)(nx * color3.R + fx * color4.R);
    
                            nRed = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
    
                            bmap.SetPixel(x, y, System.Drawing.Color.FromArgb
                    (255, nRed, nGreen, nBlue));
                        }
                    }
    
           
    
                    bmap = SetGrayscale(bmap);
                    bmap = RemoveNoise(bmap);
    
                    return bmap;
                
            }
    
    
    public Bitmap SetGrayscale(Bitmap img)
                {
        
                    Bitmap temp = (Bitmap)img;
                    Bitmap bmap = (Bitmap)temp.Clone();
                    Color c;
                    for (int i = 0; i < bmap.Width; i++)
                    {
                        for (int j = 0; j < bmap.Height; j++)
                        {
                            c = bmap.GetPixel(i, j);
                            byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);
        
                            bmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                        }
                    }
                    return (Bitmap)bmap.Clone();
        
                }
    
    
    public Bitmap RemoveNoise(Bitmap bmap)
                {
        
                    for (var x = 0; x < bmap.Width; x++)
                    {
                        for (var y = 0; y < bmap.Height; y++)
                        {
                            var pixel = bmap.GetPixel(x, y);
                            if (pixel.R < 162 && pixel.G < 162 && pixel.B < 162)
                                bmap.SetPixel(x, y, Color.Black);
                            else if (pixel.R > 162 && pixel.G > 162 && pixel.B > 162)
                                bmap.SetPixel(x, y, Color.White);
                        }
                    }
        
                    return bmap;
                }
    
    公共位图调整大小(位图bmp、int-newWidth、int-newHeight)
    {
    位图温度=(位图)bmp;
    位图bmap=新位图(新宽度、新高度、临时像素格式);
    双nWidthFactor=(双)临时宽度/(双)新宽度;
    双N权重系数=(双)温度高度/(双)新高度;
    纽约州纽约州财政部双倍外汇;
    int-cx,cy,fr_x,fr_y;
    颜色1=新颜色();
    颜色2=新颜色();
    Color color3=新颜色();
    Color color4=新颜色();
    字节nRed、nGreen、nBlue;
    字节bp1,bp2;
    对于(int x=0;x=温度宽度)cx=fr\ux;
    cy=fr_y+1;
    如果(cy>=温度高度)cy=fr\u y;
    fx=x*nWidthFactor-fr_x;
    fy=y*n权重因子-fr_y;
    nx=1.0-fx;
    ny=1.0-fy;
    color1=温度获取像素(fr_x,fr_y);
    color2=温度获取像素(cx,fr_y);
    color3=温度获取像素(fr_x,cy);
    color4=温度获取像素(cx,cy);
    //蓝色的
    bp1=(字节)(nx*color1.B+fx*color2.B);
    bp2=(字节)(nx*color3.B+fx*color4.B);
    nBlue=(字节)(ny*(双字节)(bp1)+fy*(双字节)(bp2));
    //绿色的
    bp1=(字节)(nx*color1.G+fx*color2.G);
    bp2=(字节)(nx*color3.G+fx*color4.G);
    nGreen=(字节)(ny*(双字节)(bp1)+fy*(双字节)(bp2));
    //红色的
    bp1=(字节)(nx*color1.R+fx*color2.R);
    bp2=(字节)(nx*color3.R+fx*color4.R);
    nRed=(字节)(ny*(双字节)(bp1)+fy*(双字节)(bp2));
    bmap.SetPixel(x,y,System.Drawing.Color.FromArgb
    (255,nRed,nGreen,nBlue));
    }
    }
    bmap=设置灰度(bmap);
    bmap=清除噪声(bmap);
    返回bmap;
    }
    // Resize
    public Bitmap resize(Bitmap img, int newWidth, int newHeight) {
        Bitmap bmap = img.copy(img.getConfig(), true);
    
        double nWidthFactor = (double) img.getWidth() / (double) newWidth;
        double nHeightFactor = (double) img.getHeight() / (double) newHeight;
    
        double fx, fy, nx, ny;
        int cx, cy, fr_x, fr_y;
        int color1;
        int color2;
        int color3;
        int color4;
        byte nRed, nGreen, nBlue;
    
        byte bp1, bp2;
    
        for (int x = 0; x < bmap.getWidth(); ++x) {
            for (int y = 0; y < bmap.getHeight(); ++y) {
    
                fr_x = (int) Math.floor(x * nWidthFactor);
                fr_y = (int) Math.floor(y * nHeightFactor);
                cx = fr_x + 1;
                if (cx >= img.getWidth())
                    cx = fr_x;
                cy = fr_y + 1;
                if (cy >= img.getHeight())
                    cy = fr_y;
                fx = x * nWidthFactor - fr_x;
                fy = y * nHeightFactor - fr_y;
                nx = 1.0 - fx;
                ny = 1.0 - fy;
    
                color1 = img.getPixel(fr_x, fr_y);
                color2 = img.getPixel(cx, fr_y);
                color3 = img.getPixel(fr_x, cy);
                color4 = img.getPixel(cx, cy);
    
                // Blue
                bp1 = (byte) (nx * Color.blue(color1) + fx * Color.blue(color2));
                bp2 = (byte) (nx * Color.blue(color3) + fx * Color.blue(color4));
                nBlue = (byte) (ny * (double) (bp1) + fy * (double) (bp2));
    
                // Green
                bp1 = (byte) (nx * Color.green(color1) + fx * Color.green(color2));
                bp2 = (byte) (nx * Color.green(color3) + fx * Color.green(color4));
                nGreen = (byte) (ny * (double) (bp1) + fy * (double) (bp2));
    
                // Red
                bp1 = (byte) (nx * Color.red(color1) + fx * Color.red(color2));
                bp2 = (byte) (nx * Color.red(color3) + fx * Color.red(color4));
                nRed = (byte) (ny * (double) (bp1) + fy * (double) (bp2));
    
                bmap.setPixel(x, y, Color.argb(255, nRed, nGreen, nBlue));
            }
        }
    
        bmap = setGrayscale(bmap);
        bmap = removeNoise(bmap);
    
        return bmap;
    }
    
    // SetGrayscale
    private Bitmap setGrayscale(Bitmap img) {
        Bitmap bmap = img.copy(img.getConfig(), true);
        int c;
        for (int i = 0; i < bmap.getWidth(); i++) {
            for (int j = 0; j < bmap.getHeight(); j++) {
                c = bmap.getPixel(i, j);
                byte gray = (byte) (.299 * Color.red(c) + .587 * Color.green(c)
                        + .114 * Color.blue(c));
    
                bmap.setPixel(i, j, Color.argb(255, gray, gray, gray));
            }
        }
        return bmap;
    }
    
    // RemoveNoise
    private Bitmap removeNoise(Bitmap bmap) {
        for (int x = 0; x < bmap.getWidth(); x++) {
            for (int y = 0; y < bmap.getHeight(); y++) {
                int pixel = bmap.getPixel(x, y);
                if (Color.red(pixel) < 162 && Color.green(pixel) < 162 && Color.blue(pixel) < 162) {
                    bmap.setPixel(x, y, Color.BLACK);
                }
            }
        }
        for (int x = 0; x < bmap.getWidth(); x++) {
            for (int y = 0; y < bmap.getHeight(); y++) {
                int pixel = bmap.getPixel(x, y);
                if (Color.red(pixel) > 162 && Color.green(pixel) > 162 && Color.blue(pixel) > 162) {
                    bmap.setPixel(x, y, Color.WHITE);
                }
            }
        }
        return bmap;
    }
    
    $ tesseract --oem 1 -l deu page.png result pdf
    
    img = cv2.resize(img, None, fx=1.2, fy=1.2, interpolation=cv2.INTER_CUBIC)
    
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    kernel = np.ones((1, 1), np.uint8)
    img = cv2.dilate(img, kernel, iterations=1)
    img = cv2.erode(img, kernel, iterations=1)
    
    cv2.threshold(cv2.GaussianBlur(img, (5, 5), 0), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.bilateralFilter(img, 5, 75, 75), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.threshold(cv2.medianBlur(img, 3), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    cv2.adaptiveThreshold(cv2.GaussianBlur(img, (5, 5), 0), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.bilateralFilter(img, 9, 75, 75), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)
    
    cv2.adaptiveThreshold(cv2.medianBlur(img, 3), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 31, 2)