使用阿里云的图片识别成表格ocr(将图片表格转换成excel)

本文介绍如何使用阿里云API将表格图片转换为可编辑的Excel文件,包括购买服务、获取AppCode、整合代码及前端实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了简便财务总是要对照着别人发来的表格图片制作成自己的表格
  • 图片识别 识别成表格 表格识别 ocr
  • 使用阿里云api
  • 购买(印刷文字识别-表格识别) https://market.aliyun.com/products/57124001/cmapi024968.html
  • 获得阿里云图片识别表格的appcode
效果图如下

效果图

整合的代码
package com.xai.wuye.controller.api;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.xai.wuye.common.JsonResult;
import com.xai.wuye.exception.ResultException;
import com.xai.wuye.model.AParam
import com.xai.wuye.service.CarService;
import com.xai.wuye.util.HttpUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static org.apache.tomcat.util.codec.binary.Base64.encodeBase64;

@Controller
@EnableAsync
@RequestMapping("/api/ocr")
public class AliOCRImages {


    @Autowired
    CarService carService;


    private String OcrPath = "/home/runApp/car/orc/";


    @ResponseBody
    @RequestMapping("table")
    public JsonResult getFirstLicence(@RequestParam(value = "file", required = false) MultipartFile file) {
        if (file == null || file.isEmpty()||file.getSize() > 1204*1204*3)
            throw new ResultException(0,"文件为null,且不能大于3M");

        String filename = file.getOriginalFilename();
        String filepath = OcrPath+"temp/"+filename;
        File newFile = new File(filepath);
        try {
            file.transferTo(newFile);

            String host = "https://form.market.alicloudapi.com";
            String path = "/api/predict/ocr_table_parse";
            
            // 输入阿里的code
            String appcode = "4926a667ee6c41329c278361*****";
            String imgFile = "图片路径";
            Boolean is_old_format = false;//如果文档的输入中含有inputs字段,设置为True, 否则设置为False
            //请根据线上文档修改configure字段
            JSONObject configObj = new JSONObject();
            configObj.put("format", "xlsx");
            configObj.put("finance", false);
            configObj.put("dir_assure", false);
            String config_str = configObj.toString();
            //            configObj.put("min_size", 5);
            //String config_str = "";

            String method = "POST";
            Map<String, String> headers = new HashMap<String, String>();
            //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
            headers.put("Authorization", "APPCODE " + appcode);

            Map<String, String> querys = new HashMap<String, String>();

            // 对图像进行base64编码
            String imgBase64 = "";
            try {

                byte[] content = new byte[(int) newFile.length()];
                FileInputStream finputstream = new FileInputStream(newFile);
                finputstream.read(content);
                finputstream.close();
                imgBase64 = new String(encodeBase64(content));
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
            // 拼装请求body的json字符串
            JSONObject requestObj = new JSONObject();
            try {
                if(is_old_format) {
                    JSONObject obj = new JSONObject();
                    obj.put("image", getParam(50, imgBase64));
                    if(config_str.length() > 0) {
                        obj.put("configure", getParam(50, config_str));
                    }
                    JSONArray inputArray = new JSONArray();
                    inputArray.add(obj);
                    requestObj.put("inputs", inputArray);
                }else{
                    requestObj.put("image", imgBase64);
                    if(config_str.length() > 0) {
                        requestObj.put("configure", config_str);
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            String bodys = requestObj.toString();

            try {
                /**
                 * 重要提示如下:
                 * HttpUtils请从
                 * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
                 * 下载
                 *
                 * 相应的依赖请参照
                 * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
                 */
                HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
                int stat = response.getStatusLine().getStatusCode();
                if(stat != 200){
                    System.out.println("Http code: " + stat);
                    System.out.println("http header error msg: "+ response.getFirstHeader("X-Ca-Error-Message"));
                    System.out.println("Http body error msg:" + EntityUtils.toString(response.getEntity()));
                    return null;
                }

                String res = EntityUtils.toString(response.getEntity());
                JSONObject res_obj = JSON.parseObject(res);
                Long fileName = System.currentTimeMillis();
                if(is_old_format) {



                    JSONArray outputArray = res_obj.getJSONArray("outputs");
                    String output = outputArray.getJSONObject(0).getJSONObject("outputValue").getString("dataValue");
                    JSONObject out = JSON.parseObject(output);
                    System.out.println(out.toJSONString());


                }else{

                    String tmp_base64path = OcrPath + fileName;
                    File tmp_base64file = new File(tmp_base64path);
                    if(!tmp_base64file.exists()){
                        tmp_base64file.getParentFile().mkdirs();
                    }
                    tmp_base64file.createNewFile();

                    // write
                    FileWriter fw = new FileWriter(tmp_base64file, true);
                    BufferedWriter bw = new BufferedWriter(fw);
                    bw.write(res_obj.getString("tables"));
                    bw.flush();
                    bw.close();
                    fw.close();

                    String exelFilePath = OcrPath + fileName + "_1.xlsx";
                    Runtime.getRuntime().exec("touch "+exelFilePath).destroy();
                    Process exec = Runtime.getRuntime().exec("sed -i -e 's/\\\\n/\\n/g' " + tmp_base64path);
                    exec.waitFor();
                    exec.destroy();

                    Process exec1 = null;
                    String[] cmd = { "/bin/sh", "-c", "base64 -d " + tmp_base64path + " > " + exelFilePath };
                    exec1 = Runtime.getRuntime().exec(cmd);
                    exec1.waitFor();
                    exec1.destroy();


                    return JsonResult.success(fileName);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }



        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


    @ResponseBody
    @RequestMapping("getId")
    public ResponseEntity<FileSystemResource> getFirstLicence(String id) {
        String exelFilePath = OcrPath + id + "_1.xlsx";
        return export(new File(exelFilePath));
    }


    public ResponseEntity<FileSystemResource> export(File file) {
        if (file == null) {
            return null;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", "attachment; filename=" + System.currentTimeMillis() + ".xls");
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        headers.add("Last-Modified", new Date().toString());
        headers.add("ETag", String.valueOf(System.currentTimeMillis()));

        return ResponseEntity
                .ok()
                .headers(headers)
                .contentLength(file.length())
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .body(new FileSystemResource(file));
    }

    public static JSONObject getParam(int type, String dataValue) {
        JSONObject obj = new JSONObject();
        try {
            obj.put("dataType", type);
            obj.put("dataValue", dataValue);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return obj;
    }

}
大功告成
  • 以下是静态页面代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <title>table</title>
</head>
<body>
  <div id="app">
      <el-upload
              class="upload-demo"
              drag
              action="https://www.***.com/car/api/ocr/table"
              :file-list="imagelist"
              :on-preview="pre"
                >
          <i class="el-icon-upload"></i>
          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
          <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
      </el-upload>
      <div class="img-content" v-for="(item,key) in imagelist" :key="key">
          <img :src="item.url">
          <div class="name">
              <div>{{ item.name }}</div>
              <el-button type="text" @click="handleFileName(item,key)">修改名字</el-button>
          </div>
          <!-- 删除icon -->
          <div class="del">
              <i @click="handleFileRemove(item,key)" class="el-icon-delete2"></i>
          </div>
          <!-- 放大icon -->
          <div class="layer" @click="handleFileEnlarge(item.url)">
              <i class="el-icon-view"></i>
          </div>
      </div>
  </div>
</body>
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: function() {
        return {
            visible: false,
            imagelist: [

            ]

        }
      },
        methods: {
            pre(res) {
                console.log(res.response.msg)
                window.open("https://www.***.com/api/ocr/getId?id="+res.response.data);
            }
        }

    })
  </script>
</html>

转载于:https://www.cnblogs.com/rolandlee/p/10671544.html

<think>嗯,用户问的是Python识别表格图片,我需要详细介绍一下。首先得确定用户的需求是什么,可能他们想从图片中提取表格数据,转换成可编辑的格式,比如Excel或者CSV。常见的应用场景可能有处理扫描的文档、截图或者照片中的表格。 接下来,我需要考虑技术实现的步骤。一般来说,处理这种问题需要几个步骤:图像预处理、表格检测、文本识别和结构重建。每个步骤都需要不同的工具和方法。 首先,图像预处理。图片可能有倾斜、噪点或者光照不均的问题,所以需要用OpenCV这样的库来处理,比如灰度化、二值化、降噪、矫正角度等。这些操作可以提高后续步骤的准确性。 然后是表格检测。这里可以用深度学习的模型,比如YOLO或者Faster R-CNN来检测图片中的表格区域。或者,如果表格结构比较明显,也可以用传统的图像处理技术,比如检测水平和垂直线条,找到交叉点来确定表格的位置。 接下来是文本识别,也就是OCR。Tesseract是一个常用的OCR引擎,但单独使用可能效果不够好,特别是对中文的支持可能有限。可能需要用PaddleOCR,它支持中文且准确率较高。需要将检测到的每个单元格的图片区域提取出来,分别进行OCR识别。 最后是结构重建。识别出来的文本需要按照原来的表格结构组织起来,可能需要确定行列的位置,合并跨行跨列的单元格等。这部分的逻辑可能比较复杂,特别是当表格有合并单元格或者复杂边框的时候。 然后需要整合这些步骤,用Python脚本或者工具库来实现。比如,用OpenCV处理图像,用PaddleDetection做表格检测,用PaddleOCR做文字识别,然后用pandas或者openpyxl导出到Excel。 可能还需要提到一些现的库或工具,比如Tabula-Py、Camelot,不过这些主要针对PDF中的表格,如果是图片的话可能不太适用。所以重点还是在OCR方案上。 另外,用户可能会遇到的挑战,比如表格边框不清晰、文字重叠、字体多样等,需要预处理或者调整模型参数。可能还需要后处理来校正识别错误,比如用正则表达式检查日期、数字格式等。 最后,给出一个简单的代码示例,展示整个流程,帮助用户快速上手。同时提醒一些注意事项,比如安装依赖库的步骤,处理中文时的语言设置,以及可能的错误处理。 总结下来,回答的结构应该是先介绍应用场景,然后分步骤讲解技术实现,每个步骤用到的工具和库,给出代码示例,最后提到可能的挑战和注意事项。这样用户就能有一个清晰的思路,知道如何开始和深入了。</think>Python识别表格图片通常涉及OCR(光学字符识别)技术和图像处理,以下是分步骤实现方法: 一、技术实现流程 1. 图像预处理 - 使用OpenCV进行: $$ \text{灰度化} \rightarrow \text{二值化} \rightarrow \text{降噪} \rightarrow \text{透视校正} $$ - 关键代码: ```python import cv2 img = cv2.imread('table.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] ``` 2. 表格结构检测 - 使用深度学习模型(推荐): - PaddleDetection中的PP-YOLOE表格检测模型 - 传统方法(适合简单表格): ```python # 检测水平/垂直线 horizontal = cv2.erode(thresh, np.ones((5,50), np.uint8), iterations=1) vertical = cv2.erode(thresh, np.ones((50,5), np.uint8), iterations=1) ``` 3. 文字识别OCR) - 推荐方案组合: ```mermaid graph TD A[单元格区域] --> B{PaddleOCR} B -->|中文优先| C[高精度识别] B -->|英文为主| D[Tesseract] ``` 4. 结构重建 - 使用坐标信息构建DataFrame: ```python import pandas as pd cells = [...] # 包含文本和坐标的列表 df = pd.DataFrame([[cell.text for cell in row] for row in sorted_rows]) ``` 二、推荐工具组合 1. 全流程方案:PaddleOCR(含版面分析) ```python from paddleocr import PaddleOCR ocr = PaddleOCR(use_angle_cls=True, lang='ch') result = ocr.ocr('table.jpg', cls=True) ``` 2. 进阶方案: - 表格检测:TableNet - 文本识别:EasyOCR - 后处理:Tabula-py 三、典型代码示例 ```python import cv2 from paddleocr import PaddleOCR # 初始化OCR ocr = PaddleOCR(use_angle_cls=True, lang='ch') # 处理图像 image = cv2.imread('financial_table.jpg') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 执行OCR识别 result = ocr.ocr(gray, cls=True) # 解析表格结构 table_data = [] for line in result: text = line[1][0] position = line[0] # 根据坐标排序到对应行列 # ...(需要添加坐标排序逻辑) # 输出为Excel pd.DataFrame(table_data).to_excel('output.xlsx') ``` 四、常见问题处理 1. 复杂表格应对策略: - 嵌套表格:采用分层次检测 - 无线表格使用文本间距分析 - 合并单元格:通过行列坐标跨度检测 2. 准确率提升技巧: - 预处理时保留$0.5^\circ$以内的倾斜校正 - 对数字列设置正则约束:$\d+(?:,\d{3})*\.?\d*$ - 使用自定义词典增强专业术语识别 五、注意事项 1. 安装依赖: ```shell pip install paddleocr opencv-python pandas ``` 2. 中文识别需下载额外模型文件(约200MB) 3. GPU加速可提升10-20倍速度(需安装CUDA版本) 实际应用中建议从简单表格开始测试,逐步增加复杂度。对于关键业务场景,建议使用商业API(如阿里云表格识别)提升稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值