如何评估扫描文档的图像质量

通过文档扫描仪或者相机扫描文档时,我们可能会获得质量较差的文档图像。在本文中,我们将讨论如何评估扫描文档的图像质量,以便重新捕获文档以获得更好的图像。编写了一个Web应用用于自动化评估。

在线demo

评估文档图像质量的几个方面

以下是我们归纳的评估质量的几个方面。

模糊

模糊可能是由于拍摄过程中的抖动或失焦造成的。

模糊图像示例:

清晰图像示例:

倾斜

如果放置在文件扫描仪上的文档没有放正,那么扫描的图像可能会偏斜。

过度曝光

曝光过度会产生非常明亮且对比度较低的图像。

长宽比

文件通常有固定的长宽比。例如,身份证的物理尺寸为86mm × 54mm ,其图像也应具有此长宽比。

因相机设置不正确而被拉伸的身份证图像示例:

OCR置信度

OCR软件在给出文本结果时通常还包含置信度分数。该分数可以反映文档图像的质量。

编写用于自动评估的Web应用

下面是编写自动评估文档质量的Web应用的分步过程。

新页面

创建包含以下内容的新页面:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Quality Evaluation of Scanned Documents</title>
  <style>
    .main {
      display: flex;
    }
  </style>
</head>
<body>
  <div class="home">
    <h2>Quality Evaluation of Scanned Documents</h2>
    <div class="main">
    </div>
  </div>
</body>
</html>

添加依赖项

  1. 添加Dynamic Web TWAIN,用于扫描文档和加载图像或PDF文件。

    添加库和一个div,用于容纳其控件。

    HTML:

    html 复制代码
    <style>
      #dwtcontrolContainer {
        width: 240px;
        height: 320px;
      }
    </style>
    <script src="https://unpkg.com/dwt@18.4.2/dist/dynamsoft.webtwain.min.js"></script>
    <div class="main">
      <div class="scanner">
        <div id="dwtcontrolContainer"></div>
      </div>
    </div>

    使用以下JavaScript初始化Web TWAIN的实例。可以在这里申请许可证。

    js 复制代码
    let DWObject;
    Dynamsoft.DWT.AutoLoad = false;
    Dynamsoft.DWT.ProductKey = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="; //one-day trial
    Dynamsoft.DWT.ResourcesPath = "https://unpkg.com/dwt@18.4.2/dist";
    
    window.onload = function(){
      initDWT();
    }
    
    function initDWT(){
      return new Promise((resolve, reject) => {
        Dynamsoft.DWT.CreateDWTObjectEx(
          {
            WebTwainId: 'dwtcontrol'
          },
          function(obj) {
            DWObject = obj;
            DWObject.Viewer.bind(document.getElementById('dwtcontrolContainer'));
            DWObject.Viewer.height = "100%";
            DWObject.Viewer.width = "100%";
            DWObject.Viewer.show();
            resolve();
          },
          function(err) {
            console.log(err);
            reject(err);
          }
        );
      })
    }
  2. 添加OpenCV.js用于图像处理。

    添加库并获取其加载状态。

    html 复制代码
    <script>
      var Module = {
        // https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
        onRuntimeInitialized() {
          document.getElementsByClassName("OpenCVStatus")[0].innerText = 'OpenCV.js is ready.';
        }
      };
    </script>
    <script async src="https://docs.opencv.org/4.8.0/opencv.js" type="text/javascript"></script>
  3. 添加Tesseract.js用于OCR。

    html 复制代码
    <script src='https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'></script>
    <script>
    let worker;
    window.onload = function(){
      initTesseract();
    }
    async function initTesseract(){
      worker = await Tesseract.createWorker("eng", 1, {
        logger: function(m){console.log(m);}
      });
    }
    </script>

检测模糊

由于模糊图像中的像素具有相似的相邻像素,我们可以在灰度图像上应用3 x 3拉普拉斯核,然后计算方差以检测模糊。

以下是使用OpenCV.js检测模糊的代码。如果方差小于200 ,则判断图像为模糊。

js 复制代码
function DetectBlur(src){
  let img = cv.imread(src);
  let gray = new cv.Mat();
  cv.cvtColor(img, gray, cv.COLOR_RGBA2GRAY);

  let laplacianMat = new cv.Mat();
  cv.Laplacian(gray, laplacianMat, cv.CV_64F);
  let mean = new cv.Mat(1, 4, cv.CV_64F);
  let standardDeviationMat = new cv.Mat(1, 4, cv.CV_64F);
  cv.meanStdDev(laplacianMat, mean, standardDeviationMat);

  let standardDeviation = standardDeviationMat.doubleAt(0, 0);
  let variance = standardDeviation * standardDeviation;

  let threshold = 200;
  let isBlurry = variance < threshold;
  img.delete();
  gray.delete();
  laplacianMat.delete();
  mean.delete();
  standardDeviationMat.delete();
  return isBlurry;
}

检测过度曝光

我们可以使用直方图来检测过度曝光。直方图是理解图像的一种方法。它以像素值(范围通常从 0 到 255)为X轴,以图像中相应像素数量为Y轴。

正常文档图像可能具有以下直方图:

图像:

曝光过度的图像可能具有以下直方图:

图像:

我们可以看到,过度曝光的图像具有更集中的强度分布,并且分布更靠近直方图的右侧。

以下是使用OpenCV.js和直方图检测过度曝光的代码:

js 复制代码
function DetectOverExposure(src){
  let img = cv.imread(src);
  cv.cvtColor(img, img, cv.COLOR_RGBA2GRAY, 0);
  let srcVec = new cv.MatVector();
  srcVec.push_back(img);
  let accumulate = false;
  let channels = [0];
  let histSize = [256];
  let ranges = [0, 255];
  let hist = new cv.Mat();
  let mask = new cv.Mat();
  let color = new cv.Scalar(255, 255, 255);
  let scale = 2;
  // You can try more different parameters
  cv.calcHist(srcVec, channels, mask, hist, histSize, ranges, accumulate);
  let result = cv.minMaxLoc(hist, mask);
  if (result.maxLoc.y > 240) {
    let data = hist.data32F
    let darkPixels = 0;
    for (let index = 0; index <= 200; index++) {
      const pixels = data[index];
      darkPixels = darkPixels + pixels;
    }
    let totalPixels = src.naturalHeight * src.naturalWidth;
    let percent = darkPixels/totalPixels;
    hist.delete();
    img.delete();
    if (percent < 0.2) {
      return true;
    } else {
      return false;
    }
  }else{
    hist.delete();
    img.delete();
    return false;
  }
}

检测倾斜

我们可以通过文字行的轮廓来检测倾斜角度。我们在上一篇文章中已经讨论过这点。

以下是使用Web TWAIN检测倾斜的代码。如果检测到的倾斜角度大于1,则判断文档图像为倾斜。

js 复制代码
function DetectSkewness(){
  return new Promise((resolve, reject) => {
    DWObject.GetSkewAngle(
      DWObject.SelectedImagesIndices[0],
      function(angle) {
        console.log("skew angle: " + angle);
        if (Math.abs(angle)>1) {
          resolve(true);
        }else{
          resolve(false);
        }
      },
      function(errorCode, errorString) {
        console.log(errorString);
        reject(errorString);
      }
    );
  })
}

检查长宽比

在检查长宽比是否正确之前,我们需要先知道文档的类型。

我们可以让用户先选择文件类型。

html 复制代码
 <label>
  Expected Document Type:
  <select id="documentType">
    <option value="">None</option>
    <option value="2480x3508">A4</option>
    <option value="1013x638">ID Card</option>
  </select>
</label>

然后使用以下代码检查长宽比:

js 复制代码
function DetectIfAspectRatioIncorrect(img){
  let documentSize = document.getElementById("documentType").selectedOptions[0].value;
  if (documentSize) {
    let width = documentSize.split("x")[0];
    let height = documentSize.split("x")[1];
    let ratio = width / height;
    let imgRatio = img.naturalWidth / img.naturalHeight;
    let percent = Math.max(ratio,imgRatio) / Math.min(ratio,imgRatio);
    if (percent > 1.1) {
      console.log(percent);
      return true;
    }else{
      return false;
    }
  }else{
    return false;
  }
}

获取OCR置信度

这里,我们使用Tesseract.js执行OCR并获取置信度。

js 复制代码
async function getOCRConfidence(img){
  const result = await worker.recognize(img);
  const data = result.data;
  let size = data.lines.length;
  let totalConfidence = 0;
  data.lines.forEach(line => {
    totalConfidence = line.confidence + totalConfidence;
  });
  let confidence = parseInt(totalConfidence/size);
  console.log(confidence);
  return confidence;
}

计算总分

我们可以计算一个总分来评估质量。

js 复制代码
let overallScore = 0;
overallScore = overallScore + (isBlurry ? 0 : 1) * 20;
overallScore = overallScore + (isOverexposed ? 0 : 1) * 20;
overallScore = overallScore + (isAspectRatioIncorrect ? 0 : 1) * 20;
overallScore = overallScore + (isSkewed ? 0 : 1) * 20;
overallScore = overallScore + OCRConfidence * 0.2;

结果显示在表格中。

源代码

可以在以下仓库中找到所有代码和在线演示:

github.com/tony-xlh/qu...

相关推荐
饼干哥哥12 分钟前
搭建一个云端Skills系统,随时随地记录TikTok爆款
前端·后端
副露のmagic12 分钟前
数组章节 leetcode 思路&实现
算法·leetcode·职场和发展
荣光属于凯撒15 分钟前
P2176 [USACO11DEC] RoadBlock S / [USACO14FEB] Roadblock G/S
算法·图论
雨季mo浅忆29 分钟前
记录利用Cursor快速实现拖拽式问卷题型创建
算法
酉鬼女又兒40 分钟前
零基础快速入门前端Web存储(sessionStorage & localStorage)知识点详解与蓝桥杯考点应用(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·职场和发展·蓝桥杯·html
Yzzz-F41 分钟前
2018-2019 ACM-ICPC, Asia Dhaka Regional ContestC[数论]
算法
DanCheOo44 分钟前
# 从"会用 AI"到"架构 AI":高级前端的认知升级
前端·ai编程
社恐的下水道蟑螂1 小时前
前端面试必问 Git 通关指南:常用命令速查 + merge/rebase 深度辨析,看完再也不慌
前端·git·面试
Frostnova丶1 小时前
LeetCode 3474. 字典序最小的生成字符串
算法·leetcode·职场和发展
REDcker1 小时前
Nagle 算法与 TCP_NODELAY、TCP_CORK 详解
网络·tcp/ip·算法