如何用pytesseract在Python中读取扫描表格并转换为CSV文件?
Hey Lucas, let's break down your problem step by step and get that table converted to CSV smoothly.
First, let's clarify what image_to_boxes does—since you mentioned you don't understand its output: this method returns character-level bounding box data, meaning it gives you the coordinates (left, bottom, right, top) for every single character it detects, plus the character itself. It's great for tasks like text alignment or character-level analysis, but totally overkill (and unhelpful) for extracting structured table data. That's why the output seemed meaningless for your goal.
Now, let's fix your original issue with image_to_data and explore better approaches for table extraction:
1. Fix image_to_data for Table Extraction
The most likely reason image_to_data was throwing errors is poor image quality or incorrect Tesseract configuration. Tesseract works best with clean, high-contrast images. Let's add preprocessing and tweak the config:
import cv2 import pytesseract from pytesseract import Output import csv # Load and preprocess the image (critical for Tesseract accuracy) img = cv2.imread("p27-001.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Adaptive thresholding handles uneven lighting better than regular thresholding thresh = cv2.adaptiveThreshold( gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2 ) # Configure Tesseract: --psm 6 assumes a single uniform block of text (perfect for tables) custom_config = r"--oem 3 --psm 6" data = pytesseract.image_to_data(thresh, output_type=Output.DICT, config=custom_config) # Parse the output into a structured table table_data = [] current_row = [] confidence_threshold = 60 # Adjust based on your image's clarity for i in range(len(data["text"])): text = data["text"][i].strip() # Only keep text with decent confidence to avoid garbage if int(data["conf"][i]) > confidence_threshold and text: # Check if we've moved to a new row (using vertical position) if i > 0 and abs(data["top"][i] - data["top"][i-1]) > 10: table_data.append(current_row) current_row = [] current_row.append(text) # Add the final row if current_row: table_data.append(current_row) # Save to CSV with open("p27-001_table.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerows(table_data)
2. Better Approach: Cell Segmentation + OCR
For tables with clear lines, splitting the image into individual cells first will give you much more accurate row/column alignment. Here's how to do it with OpenCV + Tesseract:
import cv2 import pytesseract import csv img = cv2.imread("p27-001.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # Detect horizontal and vertical table lines horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40, 1)) horizontal_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 40)) vertical_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) # Combine lines to get the table grid combined_grid = cv2.addWeighted(horizontal_lines, 0.5, vertical_lines, 0.5, 0.0) combined_grid = cv2.threshold(combined_grid, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] # Find cell contours and sort them by row then column contours, _ = cv2.findContours(combined_grid, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=lambda x: (cv2.boundingRect(x)[1], cv2.boundingRect(x)[0])) table_data = [] current_row = [] prev_y = None for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) # Skip tiny contours (noise) if w > 20 and h > 20: # Extract and preprocess the cell cell = gray[y:y+h, x:x+w] cell_thresh = cv2.threshold(cell, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # OCR the cell text text = pytesseract.image_to_string(cell_thresh, config="--oem 3 --psm 6").strip() # Check for new row if prev_y is not None and abs(y - prev_y) > 15: table_data.append(current_row) current_row = [] current_row.append(text) prev_y = y # Add the last row if current_row: table_data.append(current_row) # Save to CSV with open("p27-001_table.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerows(table_data)
3. Quick Win: Use EasyOCR's Table Detection
If you want to skip the low-level preprocessing, EasyOCR has built-in table detection that works surprisingly well for images:
import easyocr import csv # Initialize reader (add your language code if not English) reader = easyocr.Reader(["en"]) # Detect table and extract cells table_result = reader.readtext("p27-001.jpg", detect_table=True) # Convert to table format table_data = [] for row in table_result[0]["cells"]: row_text = [cell["text"].strip() for cell in row] table_data.append(row_text) # Save to CSV with open("p27-001_table.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerows(table_data)
Final Notes:
- If
image_to_datawas throwing specific errors, double-check your Tesseract installation path (usepytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'on Windows if needed) and image file path. - For messy tables (merged cells, faded lines), you might need to manually clean up the CSV, but the above methods should get you 90% of the way there.
内容的提问来源于stack exchange,提问作者Lucas

