[Python] detect text in format "number unit" using pytesseract OCR ValueError on converting...

Discussão em 'Python' iniciado por Stack, Setembro 16, 2024.

  1. Stack

    Stack Membro Participativo

    This is from an online hackathon which has ended(extract entity values of objects from images), I'm a newbie but I tried first with the task of creating an ocr function for extracting text from preprocessed images and passing it through a parse_string(s) func to check for format However, I keep getting Error at one file with output.

    constants.py contains all the valid units taken, ex. weight : g , pound etc, volume: millilitre, ..

    This is my function :

    def extract_text(image_path):
    """Perform OCR to extract text from the image."""
    if not image_path or not os.path.exists(image_path):
    print(f"Image path does not exist: {image_path}")
    return ""

    try:
    image = cv2.imread(image_path)
    if image is None:
    print(f"Error reading image file: {image_path}")
    return ""

    # Preprocess the image for OCR
    image = rescale_image(image)
    image = enhance_contrast(image)
    image = binarize_image(image)
    image = enhance_structure(image)

    # Extract text using Tesseract
    config = "--psm 6" # specify page segmentation mode(psm) for no.s
    text = pytesseract.image_to_string(image, config=config)

    """Sanitize OCR output by removing non-alphanumeric characters and trimming noise."""
    # Remove unwanted symbols or characters
    text = re.sub(r'[^a-zA-Z0-9\s,.]', '', text)
    # Replace multiple spaces with a single space
    text = re.sub(r'\s+', ' ', text).strip()

    return text

    except Exception as e:
    print(f"Error extracting text from {image_path}: {e}")
    return ""

    def batch_ocr(image_paths, num_threads=5):
    """Perform OCR on a batch of images using multiple threads."""
    with ThreadPoolExecutor(max_workers=num_threads) as executor:
    ocr_results = list(tqdm(executor.map(extract_text, image_paths), total=len(image_paths)))

    # filter out invalid ocr results
    valid_results = []
    for result in ocr_results:
    if re.match(r'^\d+(\.\d+)?\s+[a-zA-Z]+$', result.strip()): # Simple number + unit pattern
    valid_results.append(result)
    else:
    valid_results.append("") # Mark invalid results as empty

    return valid_results


    # ----------------------- Utility Functions -----------------------

    def common_mistake(unit):
    """Correct common unit mistakes."""
    unit = unit.lower().strip()
    corrections = {
    'grams': 'gram',
    'kilograms': 'kilogram',
    'ounces': 'ounce',
    'centimetres': 'centimetre',
    'inches': 'inch',
    'lbs': 'pound',
    'storager': 'storage',
    'dcuratcn': 'duration',
    'ttralagn': 'translation', # Example OCR mistake corrections
    # Add more corrections here
    }
    return corrections.get(unit, unit)

    # valid numeric string check
    def is_valid_numeric_string(s):
    """Check if the string likely contains a valid numeric value and unit."""
    # Check if the string contains any numbers
    return any(char.isdigit() for char in s)

    def parse_string(s):
    """Parse a string to extract number and unit."""
    if not s or str(s).lower() == 'nan':
    print(f"Empty or NaN string encountered: {s}")
    return None, None

    # Filter out invalid strings before parsing

    if is_valid_numeric_string(s):
    s = s.strip()
    print(f"Parsing string: {s}")
    pattern = re.compile(r'^-?\d+(\.\d+)?\s+[a-zA-Z\s]+$')

    # if not pattern.match(s):
    # raise ValueError(f"Invalid format in {s}")
    # handle the case where the string is not in the expected format
    if not pattern.match(s):
    print(f"Skipping invalid format: {s}")
    return None, None # Skip invalid entries

    parts = s.split(maxsplit=1)

    # sanitize the number part
    number_str = parts[0].replace(",", "").strip() # Remove commas and extra spaces
    try:
    number = float(number_str) # Extract the number part
    except ValueError:
    print(f"Invalid number format in: {s} (number part: '{number_str}')")
    return None, None
    unit = common_mistake(parts[1].strip().lower())

    # Handle allowed_units using your constants
    return number, unit

    else:
    print(f"Skipping non-numeric string: {s}")
    return None, None # Skip non-numeric entries


    Output:

    ValueError: Invalid format in STORER

    + DCURATCN TRENDS A TTRALAGN Sean ume TTA i


    I thus researched and added rescaling(300ppi) , contrast , binarise, blur, denoising, dilation and erosion, and added error handling and log in the function but the error persists. Please Help(also if this is not the right way, please guide me on how can I properly improve the efficiency of ocr and detect the desired texts from images).

    Continue reading...

Compartilhe esta Página