File size: 5,532 Bytes
0507081
1a5f8fd
 
1d1e3da
 
 
1a5f8fd
 
 
87a883e
1d1e3da
 
 
 
87a883e
49bdc4d
0b5db95
49bdc4d
 
 
 
1a5f8fd
0b5db95
49bdc4d
 
 
 
 
0b5db95
 
49bdc4d
 
 
496e98a
0b5db95
 
 
49bdc4d
 
 
87a883e
49bdc4d
0b5db95
1a5f8fd
c0652ff
1a5f8fd
49bdc4d
 
3caa343
49bdc4d
1a5f8fd
 
0b5db95
 
49bdc4d
c0652ff
 
49bdc4d
c0652ff
 
 
 
0b5db95
c0652ff
 
49bdc4d
 
0b5db95
c0652ff
49bdc4d
3caa343
49bdc4d
 
 
c0652ff
3caa343
1a5f8fd
 
3caa343
1a5f8fd
0b5db95
0507081
1a5f8fd
0507081
49bdc4d
3caa343
5699ebb
0b5db95
0507081
0b5db95
 
3caa343
5699ebb
1a5f8fd
49bdc4d
3caa343
5699ebb
0b5db95
3caa343
 
 
 
 
 
06308c8
1a5f8fd
0507081
 
1d1e3da
06308c8
0507081
58fea44
0507081
06308c8
0507081
 
743d772
06308c8
0507081
1d1e3da
 
 
87a883e
1d1e3da
 
 
 
49bdc4d
1d1e3da
87a883e
1d1e3da
06308c8
1a5f8fd
496e98a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import gradio as gr
import cv2
import pytesseract
from PIL import Image
import io
import base64
from datetime import datetime
import pytz
import numpy as np
import logging

# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Configure Tesseract path
try:
    pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract'  # Adjust path if needed
    pytesseract.get_tesseract_version()  # Test Tesseract availability
    logging.info("Tesseract is available")
except Exception as e:
    logging.error(f"Tesseract not found or misconfigured: {str(e)}")

# Preprocessing function
def preprocess_image(img_cv):
    """Preprocess image for OCR: enhance contrast, reduce noise, and apply adaptive thresholding."""
    try:
        # Convert to grayscale
        gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
        # Enhance contrast using CLAHE (Contrast Limited Adaptive Histogram Equalization)
        clahe = cv2.createCLAHE(clipLimit=5.0, tileGridSize=(8, 8))
        contrast = clahe.apply(gray)
        # Reduce noise with Gaussian blur
        blurred = cv2.GaussianBlur(contrast, (5, 5), 0)
        # Apply adaptive thresholding for better binary image representation
        thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
        # Sharpen the image to enhance details
        sharpened = cv2.filter2D(thresh, -1, np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]]))
        return sharpened
    except Exception as e:
        logging.error(f"Image preprocessing failed: {str(e)}")
        return img_cv

# Function to extract weight using OCR
def extract_weight(img):
    """Extract weight from image using Tesseract OCR with improved configuration."""
    try:
        if img is None:
            logging.error("No image provided for OCR")
            return "Not detected", 0.0, None
        
        # Convert PIL image to OpenCV format
        img_cv = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
        # Preprocess the image
        processed_img = preprocess_image(img_cv)
        
        # OCR configuration for digit extraction
        custom_config = r'--oem 3 --psm 6 -c tessedit_char_whitelist=0123456789.'
        
        # Run OCR
        text = pytesseract.image_to_string(processed_img, config=custom_config)
        logging.info(f"OCR result: '{text}'")
        
        # Extract valid weight from OCR result (strip unwanted characters)
        weight = ''.join(filter(lambda x: x in '0123456789.', text.strip()))
        if weight:
            try:
                weight_float = float(weight)
                if weight_float >= 0:  # Only accept valid weights
                    confidence = 95.0  # Assume high confidence if we have a valid weight
                    logging.info(f"Weight detected: {weight} (Confidence: {confidence:.2f}%)")
                    return weight, confidence, processed_img
            except ValueError:
                logging.warning(f"Invalid number format: {weight}")
        
        logging.error("OCR failed to detect a valid weight")
        return "Not detected", 0.0, None
    except Exception as e:
        logging.error(f"OCR processing failed: {str(e)}")
        return "Not detected", 0.0, None

# Main function to process image and display results
def process_image(img):
    """Process uploaded or captured image and extract weight."""
    if img is None:
        logging.error("No image provided")
        return "No image uploaded", None, gr.update(visible=False), gr.update(visible=False)
    
    # Get the current time in IST format
    ist_time = datetime.now(pytz.timezone("Asia/Kolkata")).strftime("%d-%m-%Y %I:%M:%S %p")
    
    # Extract weight and confidence from the image
    weight, confidence, processed_img = extract_weight(img)
    
    if weight == "Not detected" or confidence < 95.0:
        logging.warning(f"Weight detection failed: {weight} (Confidence: {confidence:.2f}%)")
        return f"{weight} (Confidence: {confidence:.2f}%)", ist_time, gr.update(visible=True), gr.update(visible=False)
    
    # Convert processed image to base64 for display
    pil_image = Image.fromarray(processed_img)
    buffered = io.BytesIO()
    pil_image.save(buffered, format="PNG")
    img_base64 = base64.b64encode(buffered.getvalue()).decode()
    
    return f"{weight} kg (Confidence: {confidence:.2f}%)", ist_time, img_base64, gr.update(visible=True)

# Gradio Interface
with gr.Blocks(title="โš–๏ธ Auto Weight Logger") as demo:
    gr.Markdown("## โš–๏ธ Auto Weight Logger")
    gr.Markdown("๐Ÿ“ท Upload or capture an image of a digital weight scale (max 5MB).")

    with gr.Row():
        image_input = gr.Image(type="pil", label="Upload / Capture Image", sources=["upload", "webcam"])
        output_weight = gr.Textbox(label="โš–๏ธ Detected Weight (in kg)")

    with gr.Row():
        timestamp = gr.Textbox(label="๐Ÿ•’ Captured At (IST)")
        snapshot = gr.Image(label="๐Ÿ“ธ Snapshot Image", type="pil")

    submit = gr.Button("๐Ÿ” Detect Weight")
    submit.click(
        fn=process_image,
        inputs=image_input,
        outputs=[output_weight, timestamp, snapshot]
    )

    gr.Markdown("""
    ### Instructions
    - Upload a clear, well-lit image of a digital weight scale display (7-segment font preferred).
    - Ensure the image is < 5MB (automatically resized if larger).
    - Review the detected weight and try again if it's incorrect.
    """)

if __name__ == "__main__":
    demo.launch()