├── README.md └── opencv-photo-to-csv └── src ├── classTable.csv ├── classTable.png └── test6.py /README.md: -------------------------------------------------------------------------------- 1 | # opencv-picture-to-excel 2 | 使用python-opencv识别图片中的表格数据转换为csv 3 | 4 | 代码分析和思路可以看下我写的这篇博客: 5 | [python-opencv表格识别](https://blog.csdn.net/sc9018181134/article/details/104577247) 6 | 7 | 欢迎关注和技术交流~ 8 | -------------------------------------------------------------------------------- /opencv-photo-to-csv/src/classTable.csv: -------------------------------------------------------------------------------- 1 | 节次星期,周一,周二,周三,周四,周五 2 | 一,语文,英语,英语,自然,数学 3 | 二,语文,英语,英语,语文,数学 4 | 三,数学,语文,数学,语文,英语 5 | 四,数学,语文,数学,体育,英语 6 | 五,体育,思想品德,语文,数学,手工 7 | 六,美术,音乐,语文,数学,写字 8 | 9 | 10 | -------------------------------------------------------------------------------- /opencv-photo-to-csv/src/classTable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wxwwt/opencv-picture-to-excel/2867d943a6651987ada1fe283583c050e3fc905e/opencv-photo-to-csv/src/classTable.png -------------------------------------------------------------------------------- /opencv-photo-to-csv/src/test6.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import cv2 4 | import numpy as np 5 | import pytesseract 6 | from PIL import Image 7 | import csv 8 | import re 9 | import json 10 | 11 | 12 | def parse_pic_to_excel_data(src): 13 | raw = cv2.imread(src, 1) 14 | # 灰度图片 15 | gray = cv2.cvtColor(raw, cv2.COLOR_BGR2GRAY) 16 | # 二值化 17 | binary = cv2.adaptiveThreshold(~gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 35, -5) 18 | cv2.imshow("binary_picture", binary) # 展示图片 19 | rows, cols = binary.shape 20 | scale = 40 21 | # 自适应获取核值 识别横线 22 | kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (cols // scale, 1)) 23 | eroded = cv2.erode(binary, kernel, iterations=1) 24 | 25 | dilated_col = cv2.dilate(eroded, kernel, iterations=1) 26 | cv2.imshow("excel_horizontal_line", dilated_col) 27 | # cv2.waitKey(0) 28 | # 识别竖线 29 | scale = 20 30 | kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, rows // scale)) 31 | eroded = cv2.erode(binary, kernel, iterations=1) 32 | dilated_row = cv2.dilate(eroded, kernel, iterations=1) 33 | cv2.imshow("excel_vertical_line", dilated_row) 34 | # cv2.waitKey(0) 35 | # 标识交点 36 | bitwise_and = cv2.bitwise_and(dilated_col, dilated_row) 37 | cv2.imshow("excel_bitwise_and", bitwise_and) 38 | # cv2.waitKey(0) 39 | # 标识表格 40 | merge = cv2.add(dilated_col, dilated_row) 41 | cv2.imshow("entire_excel_contour", merge) 42 | # cv2.waitKey(0) 43 | # 两张图片进行减法运算,去掉表格框线 44 | merge2 = cv2.subtract(binary, merge) 45 | cv2.imshow("binary_sub_excel_rect", merge2) 46 | 47 | new_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2)) 48 | erode_image = cv2.morphologyEx(merge2, cv2.MORPH_OPEN, new_kernel) 49 | cv2.imshow('erode_image2', erode_image) 50 | merge3 = cv2.add(erode_image, bitwise_and) 51 | cv2.imshow('merge3', merge3) 52 | # cv2.waitKey(0) 53 | # 识别黑白图中的白色交叉点,将横纵坐标取出 54 | ys, xs = np.where(bitwise_and > 0) 55 | # 纵坐标 56 | y_point_arr = [] 57 | # 横坐标 58 | x_point_arr = [] 59 | # 通过排序,获取跳变的x和y的值,说明是交点,否则交点会有好多像素值值相近,我只取相近值的最后一点 60 | # 这个10的跳变不是固定的,根据不同的图片会有微调,基本上为单元格表格的高度(y坐标跳变)和长度(x坐标跳变) 61 | i = 0 62 | sort_x_point = np.sort(xs) 63 | for i in range(len(sort_x_point) - 1): 64 | if sort_x_point[i + 1] - sort_x_point[i] > 10: 65 | x_point_arr.append(sort_x_point[i]) 66 | i = i + 1 67 | x_point_arr.append(sort_x_point[i]) # 要将最后一个点加入 68 | 69 | i = 0 70 | sort_y_point = np.sort(ys) 71 | # print(np.sort(ys)) 72 | for i in range(len(sort_y_point) - 1): 73 | if (sort_y_point[i + 1] - sort_y_point[i] > 10): 74 | y_point_arr.append(sort_y_point[i]) 75 | i = i + 1 76 | # 要将最后一个点加入 77 | y_point_arr.append(sort_y_point[i]) 78 | print('y_point_arr', y_point_arr) 79 | print('x_point_arr', x_point_arr) 80 | # 循环y坐标,x坐标分割表格 81 | data = [[] for i in range(len(y_point_arr))] 82 | for i in range(len(y_point_arr) - 1): 83 | for j in range(len(x_point_arr) - 1): 84 | # 在分割时,第一个参数为y坐标,第二个参数为x坐标 85 | cell = raw[y_point_arr[i]:y_point_arr[i + 1], x_point_arr[j]:x_point_arr[j + 1]] 86 | cv2.imshow("sub_pic" + str(i) + str(j), cell) 87 | 88 | # 读取文字,此为默认英文 89 | # pytesseract.pytesseract.tesseract_cmd = 'E:/Tesseract-OCR/tesseract.exe' 90 | text1 = pytesseract.image_to_string(cell, lang="chi_sim") 91 | 92 | # 去除特殊字符 93 | text1 = re.findall(r'[^\*"/:?\\|<>″′‖ 〈\n]', text1, re.S) 94 | text1 = "".join(text1) 95 | print('单元格图片信息:' + text1) 96 | data[i].append(text1) 97 | j = j + 1 98 | i = i + 1 99 | # cv2.waitKey(0) 100 | return data 101 | 102 | 103 | def write_csv(path, data): 104 | with open(path, "w", newline='') as csv_file: 105 | writer = csv.writer(csv_file, dialect='excel') 106 | for index, item in enumerate(data): 107 | writer.writerows([[item[0], item[1], item[2], item[3], item[4], item[5]]]) 108 | 109 | 110 | if __name__ == '__main__': 111 | file = "classTable.png" 112 | # 解析数据 113 | data = parse_pic_to_excel_data(file) 114 | # 写入excel 115 | write_csv(file.replace(".png", ".csv"), data) 116 | --------------------------------------------------------------------------------