Sanjayraju30 commited on
Commit
523ceab
·
verified ·
1 Parent(s): 136e7c4

Update weight_detector.py

Browse files
Files changed (1) hide show
  1. weight_detector.py +90 -77
weight_detector.py CHANGED
@@ -2,55 +2,60 @@ import cv2
2
  import numpy as np
3
  import easyocr
4
  import re
5
- from typing import Tuple, List, Optional
6
  from PIL import Image, ImageDraw
7
  import pytz
8
  from datetime import datetime
 
9
 
10
  class WeightDetector:
11
  def __init__(self):
12
- """Initialize with English and optimized settings"""
13
  self.reader = easyocr.Reader(
14
  ['en'],
15
  gpu=True,
16
  model_storage_directory='model',
17
- download_enabled=True
 
18
  )
19
  self.ist = pytz.timezone('Asia/Kolkata')
20
-
21
  def get_current_ist(self) -> str:
22
- """Get current time in Indian Standard Time"""
23
- return datetime.now(self.ist).strftime('%Y-%m-%d %H:%M:%S %Z')
24
-
25
- def preprocess_image(self, image: np.ndarray) -> np.ndarray:
26
- """Enhanced image preprocessing for digital displays"""
27
- # Convert to grayscale
 
 
 
 
 
28
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
29
 
30
- # Contrast enhancement
31
- clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
32
- contrast_enhanced = clahe.apply(gray)
33
-
34
- # Thresholding for digital displays
35
- _, thresh = cv2.threshold(contrast_enhanced, 0, 255,
36
- cv2.THRESH_BINARY + cv2.THRESH_OTSU)
37
 
38
- # Noise reduction
39
- denoised = cv2.medianBlur(thresh, 3)
 
40
 
41
- return denoised
42
-
43
- def extract_weight_value(self, text: str) -> Optional[float]:
44
- """Improved weight extraction with better pattern matching"""
45
- # Clean the text
46
- text = text.replace(' ', '').replace(',', '.').lower()
47
 
48
- # Patterns for digital scale displays
49
  patterns = [
50
- r'(\d+\.\d+)[gkl]', # 12.34g or 12.34kg
51
- r'(\d+)[gkl]', # 123g or 123kg
52
- r'(\d+\.\d+)', # Just numbers with decimal
53
- r'(\d+)' # Just whole numbers
54
  ]
55
 
56
  for pattern in patterns:
@@ -58,85 +63,93 @@ class WeightDetector:
58
  if match:
59
  try:
60
  value = float(match.group(1))
61
- # Assume grams if no unit specified
62
- if 'k' in text:
63
- return value * 1000 # Convert kg to g
64
  return value
65
  except ValueError:
66
  continue
67
  return None
68
-
69
- def detect_weight(self, image_path: str) -> Tuple[Optional[float], str, Image.Image]:
70
- """Enhanced weight detection with better error handling"""
71
  try:
72
- # Read image
73
  img = Image.open(image_path).convert("RGB")
74
  img_cv = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
75
 
76
- # Preprocess
77
- processed = self.preprocess_image(img_cv)
 
 
 
 
 
 
78
 
79
- # OCR with configuration optimized for digital displays
 
 
 
80
  results = self.reader.readtext(
81
  processed,
 
82
  paragraph=False,
83
- detail=1,
84
- allowlist='0123456789.gkGlL',
85
- width_ths=2.0,
86
- text_threshold=0.7
87
  )
88
 
89
- # Process all potential weight values
90
  detected_weights = []
91
  for (bbox, text, prob) in results:
92
- weight = self.extract_weight_value(text)
93
- if weight is not None and prob > 0.4: # Minimum confidence
94
  detected_weights.append({
95
- 'weight': weight,
96
- 'text': text,
97
- 'probability': prob,
98
- 'bbox': bbox
99
  })
100
 
101
- # Prepare output
102
- draw = ImageDraw.Draw(img)
103
- current_time = self.get_current_ist()
104
-
105
  if detected_weights:
106
- # Sort by probability and area (larger text is more likely the weight)
107
  detected_weights.sort(
108
- key=lambda x: (
109
- x['probability'],
110
- (x['bbox'][2][0] - x['bbox'][0][0]) * # Width
111
- (x['bbox'][2][1] - x['bbox'][0][1]) # Height
112
- ),
113
  reverse=True
114
  )
115
-
116
  best_match = detected_weights[0]
117
 
118
- # Draw all detections
 
119
  for item in detected_weights:
120
- bbox = item['bbox']
121
  polygon = [(int(x), int(y)) for [x, y] in bbox]
122
  color = "green" if item == best_match else "red"
123
  draw.polygon(polygon, outline=color, width=2)
124
- label = f"{item['weight']}g (p={item['probability']:.2f})"
125
  draw.text((polygon[0][0], polygon[0][1] - 15), label, fill=color)
126
 
127
- # Add timestamp to image
128
- draw.text((10, 10), f"Captured at: {current_time}", fill="blue")
129
 
130
- return best_match['weight'], current_time, img
 
 
 
 
 
131
 
132
- # No weight detected
133
- draw.text((10, 10), f"Captured at: {current_time}", fill="blue")
134
- return None, current_time, img
 
 
 
135
 
136
  except Exception as e:
137
- current_time = self.get_current_ist()
138
- error_img = Image.new("RGB", (300, 100), color="white")
139
- draw = ImageDraw.Draw(error_img)
140
- draw.text((10, 10), f"Error: {str(e)}", fill="red")
141
- draw.text((10, 30), f"Time: {current_time}", fill="blue")
142
- return None, current_time, error_img
 
2
  import numpy as np
3
  import easyocr
4
  import re
 
5
  from PIL import Image, ImageDraw
6
  import pytz
7
  from datetime import datetime
8
+ from skimage import filters
9
 
10
  class WeightDetector:
11
  def __init__(self):
12
+ """OCR optimized for 7-segment displays"""
13
  self.reader = easyocr.Reader(
14
  ['en'],
15
  gpu=True,
16
  model_storage_directory='model',
17
+ download_enabled=True,
18
+ recog_network='english_g2' # Better for digital displays
19
  )
20
  self.ist = pytz.timezone('Asia/Kolkata')
21
+
22
  def get_current_ist(self) -> str:
23
+ """Get current IST time"""
24
+ return datetime.now(self.ist).strftime('%Y-%m-%d %H:%M:%S IST')
25
+
26
+ def is_blurry(self, image: np.ndarray, threshold=100) -> bool:
27
+ """Check if image is blurry using Laplacian variance"""
28
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
29
+ variance = cv2.Laplacian(gray, cv2.CV_64F).var()
30
+ return variance < threshold
31
+
32
+ def preprocess_7segment(self, image: np.ndarray) -> np.ndarray:
33
+ """Optimized preprocessing for 7-segment displays"""
34
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
35
 
36
+ # Adaptive thresholding for digital displays
37
+ thresh = cv2.adaptiveThreshold(
38
+ gray, 255,
39
+ cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
40
+ cv2.THRESH_BINARY_INV, 11, 2
41
+ )
 
42
 
43
+ # Remove small noise
44
+ kernel = np.ones((2, 2), np.uint8)
45
+ cleaned = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
46
 
47
+ return cleaned
48
+
49
+ def extract_weight(self, text: str) -> Optional[float]:
50
+ """Extract weight value (handles decimals, units like g/kg)"""
51
+ text = text.replace(" ", "").replace(",", ".")
 
52
 
53
+ # Patterns for digital scales (e.g., "0.000g", "12.34 kg")
54
  patterns = [
55
+ r'(\d+\.\d+)\s*[gGkK]', # 12.34g or 12.34kg
56
+ r'(\d+)\s*[gGkK]', # 123g or 123kg
57
+ r'(\d+\.\d+)', # Decimal only
58
+ r'(\d+)' # Whole number
59
  ]
60
 
61
  for pattern in patterns:
 
63
  if match:
64
  try:
65
  value = float(match.group(1))
66
+ if 'k' in text.lower(): # Convert kg to g
67
+ return value * 1000
 
68
  return value
69
  except ValueError:
70
  continue
71
  return None
72
+
73
+ def detect_weight(self, image_path: str) -> dict:
74
+ """Detect weight from image with error checks"""
75
  try:
 
76
  img = Image.open(image_path).convert("RGB")
77
  img_cv = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
78
 
79
+ # Check for blur
80
+ if self.is_blurry(img_cv):
81
+ return {
82
+ "weight": None,
83
+ "message": "⚠️ Image is blurry! Ensure clear focus.",
84
+ "image": img,
85
+ "time": self.get_current_ist()
86
+ }
87
 
88
+ # Preprocess for 7-segment digits
89
+ processed = self.preprocess_7segment(img_cv)
90
+
91
+ # OCR with 7-segment optimization
92
  results = self.reader.readtext(
93
  processed,
94
+ allowlist='0123456789.gkGKlL',
95
  paragraph=False,
96
+ text_threshold=0.7,
97
+ width_ths=1.5
 
 
98
  )
99
 
100
+ # Extract and validate weights
101
  detected_weights = []
102
  for (bbox, text, prob) in results:
103
+ weight = self.extract_weight(text)
104
+ if weight and prob > 0.5: # Minimum confidence
105
  detected_weights.append({
106
+ "weight": weight,
107
+ "text": text,
108
+ "probability": prob,
109
+ "bbox": bbox
110
  })
111
 
112
+ # Select best match (highest confidence + largest area)
 
 
 
113
  if detected_weights:
 
114
  detected_weights.sort(
115
+ key=lambda x: (x["probability"],
116
+ (x["bbox"][2][0] - x["bbox"][0][0]) * # Width
117
+ (x["bbox"][2][1] - x["bbox"][0][1])), # Height
 
 
118
  reverse=True
119
  )
 
120
  best_match = detected_weights[0]
121
 
122
+ # Draw annotations
123
+ draw = ImageDraw.Draw(img)
124
  for item in detected_weights:
125
+ bbox = item["bbox"]
126
  polygon = [(int(x), int(y)) for [x, y] in bbox]
127
  color = "green" if item == best_match else "red"
128
  draw.polygon(polygon, outline=color, width=2)
129
+ label = f"{item['weight']}g (Conf: {item['probability']:.2f})"
130
  draw.text((polygon[0][0], polygon[0][1] - 15), label, fill=color)
131
 
132
+ # Add timestamp
133
+ draw.text((10, 10), f"Time: {self.get_current_ist()}", fill="blue")
134
 
135
+ return {
136
+ "weight": best_match["weight"],
137
+ "message": f"✅ Detected: {best_match['weight']}g (Conf: {best_match['probability']:.2f})",
138
+ "image": img,
139
+ "time": self.get_current_ist()
140
+ }
141
 
142
+ return {
143
+ "weight": None,
144
+ "message": "❌ No weight detected. Ensure clear 7-segment digits.",
145
+ "image": img,
146
+ "time": self.get_current_ist()
147
+ }
148
 
149
  except Exception as e:
150
+ return {
151
+ "weight": None,
152
+ "message": f"⚠️ Error: {str(e)}",
153
+ "image": None,
154
+ "time": self.get_current_ist()
155
+ }