nvalliant commited on
Commit
7199c9a
Β·
verified Β·
1 Parent(s): fcc0709

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +70 -32
server.py CHANGED
@@ -55,54 +55,92 @@ def map_kaggle_label(raw_label):
55
  return f"{ft}_{rs}", ft, rs
56
 
57
 
58
- # ─── Feature extraction β€” exact copy dari Cell 2 notebook ────────────────────
59
  def extract_features_from_array(img_array, size=(128, 128)):
60
  img_resized = cv2.resize(img_array, size)
61
  gray = cv2.cvtColor(img_resized, cv2.COLOR_BGR2GRAY)
62
  blurred = cv2.GaussianBlur(gray, (5, 5), 0)
63
 
64
- _, mask = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
65
-
66
- contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 
 
 
 
 
 
 
 
 
 
67
  aspect_ratio, extent = 0, 0
68
  if contours:
69
  c = max(contours, key=cv2.contourArea)
70
- x, y, w, h = cv2.boundingRect(c)
71
- aspect_ratio = float(w) / h if h != 0 else 0
72
- area = cv2.contourArea(c)
73
- rect_area = w * h
74
- extent = float(area) / rect_area if rect_area != 0 else 0
75
 
76
- fp = mask > 0
77
 
78
- # HSV (6)
79
  hsv = cv2.cvtColor(img_resized, cv2.COLOR_BGR2HSV)
80
  h_ch, s_ch, v_ch = cv2.split(hsv)
81
  hsv_feats = [
82
- np.mean(h_ch[fp]) if fp.any() else 0, np.mean(s_ch[fp]) if fp.any() else 0,
83
- np.mean(v_ch[fp]) if fp.any() else 0, np.std(h_ch[fp]) if fp.any() else 0,
84
- np.std(s_ch[fp]) if fp.any() else 0, np.std(v_ch[fp]) if fp.any() else 0,
 
 
 
85
  ]
86
 
87
- # LAB (5) ← NEW
88
  lab = cv2.cvtColor(img_resized, cv2.COLOR_BGR2LAB)
89
  l_ch, a_ch, b_ch = cv2.split(lab)
90
  lab_feats = [
91
- np.mean(l_ch[fp]) if fp.any() else 0, np.mean(a_ch[fp]) if fp.any() else 0,
92
- np.mean(b_ch[fp]) if fp.any() else 0, np.std(a_ch[fp]) if fp.any() else 0,
 
 
93
  np.std(b_ch[fp]) if fp.any() else 0,
94
  ]
95
 
96
- # Hue histogram 18 bins (18) ← NEW
97
- h_hist = cv2.calcHist([h_ch], [0], mask, [18], [0, 180])
 
98
  h_hist = cv2.normalize(h_hist, h_hist).flatten().tolist()
99
 
100
- # GLCM with distances=[1,3,5], 4 angles, 6 props (6) ← EXPANDED
101
- # Quantise to 32 levels: reduces sparsity and speeds up computation.
102
- # ⚠️ Must match the notebook β€” retrain if you change this value.
103
- masked_gray = cv2.bitwise_and(gray, gray, mask=mask).astype(np.uint8)
104
- masked_gray = (masked_gray // 8).astype(np.uint8) # 256 β†’ 32 levels
105
- glcm = graycomatrix(masked_gray, distances=[1, 3, 5],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
107
  levels=32, symmetric=True, normed=True)
108
  glcm_feats = [
@@ -110,23 +148,23 @@ def extract_features_from_array(img_array, size=(128, 128)):
110
  graycoprops(glcm, 'correlation').mean(),
111
  graycoprops(glcm, 'energy').mean(),
112
  graycoprops(glcm, 'homogeneity').mean(),
113
- graycoprops(glcm, 'dissimilarity').mean(), # NEW
114
- graycoprops(glcm, 'ASM').mean(), # NEW
115
  ]
116
 
117
- # LBP histogram 10 bins (10) ← NEW
118
  lbp = local_binary_pattern(gray, P=8, R=1, method='uniform')
119
  lbp_pixels = lbp[fp] if fp.any() else lbp.ravel()
120
  lbp_hist, _ = np.histogram(lbp_pixels, bins=10, range=(0, 10), density=True)
121
 
122
  features = hsv_feats + lab_feats + h_hist + glcm_feats + lbp_hist.tolist() + [aspect_ratio, extent]
123
-
124
- # raw dict for frontend display (keep the same keys you already use)
125
  raw = {
126
  'h_mean': hsv_feats[0], 's_mean': hsv_feats[1], 'v_mean': hsv_feats[2],
127
  'h_std': hsv_feats[3], 's_std': hsv_feats[4], 'v_std': hsv_feats[5],
128
  'contrast': glcm_feats[0], 'correlation': glcm_feats[1],
129
- 'energy': glcm_feats[2], 'homogeneity': glcm_feats[3],
130
  'aspect_ratio': aspect_ratio, 'extent': extent,
131
  }
132
  return features, raw
@@ -245,4 +283,4 @@ if __name__ == '__main__':
245
  print("RIPE.AI β€” Flask API Server")
246
  print("=" * 60)
247
  print(f"Model loaded: {model_loaded}")
248
- app.run(host='0.0.0.0', port=7860, debug=False)
 
55
  return f"{ft}_{rs}", ft, rs
56
 
57
 
58
+ # ─── Feature extraction β€” exact copy dari notebook (GrabCut version) ─────────
59
  def extract_features_from_array(img_array, size=(128, 128)):
60
  img_resized = cv2.resize(img_array, size)
61
  gray = cv2.cvtColor(img_resized, cv2.COLOR_BGR2GRAY)
62
  blurred = cv2.GaussianBlur(gray, (5, 5), 0)
63
 
64
+ # ── Segmentation: GrabCut (matches notebook) ──────────────────────────────
65
+ h, w = blurred.shape[:2]
66
+ margin = int(min(h, w) * 0.085)
67
+ rect = (margin, margin, w - margin * 2, h - margin * 2)
68
+ mask = np.zeros(blurred.shape[:2], np.uint8)
69
+ bgd_model = np.zeros((1, 65), np.float64)
70
+ fgd_model = np.zeros((1, 65), np.float64)
71
+ cv2.grabCut(img_resized, mask, rect, bgd_model, fgd_model,
72
+ iterCount=20, mode=cv2.GC_INIT_WITH_RECT)
73
+ mask2 = np.where((mask == 2) | (mask == 0), 0, 255).astype('uint8')
74
+
75
+ # ── Shape features ────────────────────────────────────────────────────────
76
+ contours, _ = cv2.findContours(mask2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
77
  aspect_ratio, extent = 0, 0
78
  if contours:
79
  c = max(contours, key=cv2.contourArea)
80
+ x, y, bw, bh = cv2.boundingRect(c)
81
+ aspect_ratio = float(bw) / bh if bh != 0 else 0
82
+ area = cv2.contourArea(c)
83
+ rect_area = bw * bh
84
+ extent = float(area) / rect_area if rect_area != 0 else 0
85
 
86
+ fp = mask2 > 0
87
 
88
+ # ── HSV color features (6) ────────────────────────────────────────────────
89
  hsv = cv2.cvtColor(img_resized, cv2.COLOR_BGR2HSV)
90
  h_ch, s_ch, v_ch = cv2.split(hsv)
91
  hsv_feats = [
92
+ np.mean(h_ch[fp]) if fp.any() else 0,
93
+ np.mean(s_ch[fp]) if fp.any() else 0,
94
+ np.mean(v_ch[fp]) if fp.any() else 0,
95
+ np.std(h_ch[fp]) if fp.any() else 0,
96
+ np.std(s_ch[fp]) if fp.any() else 0,
97
+ np.std(v_ch[fp]) if fp.any() else 0,
98
  ]
99
 
100
+ # ── LAB color features (5) ────────────────────────────────────────────────
101
  lab = cv2.cvtColor(img_resized, cv2.COLOR_BGR2LAB)
102
  l_ch, a_ch, b_ch = cv2.split(lab)
103
  lab_feats = [
104
+ np.mean(l_ch[fp]) if fp.any() else 0,
105
+ np.mean(a_ch[fp]) if fp.any() else 0,
106
+ np.mean(b_ch[fp]) if fp.any() else 0,
107
+ np.std(a_ch[fp]) if fp.any() else 0,
108
  np.std(b_ch[fp]) if fp.any() else 0,
109
  ]
110
 
111
+ # ── Hue histogram 18 bins (18) ────────────────────────────────────────────
112
+ # NOTE: uses mask2 (uint8 0/255) as the cv2.calcHist mask β€” matches notebook
113
+ h_hist = cv2.calcHist([h_ch], [0], mask2, [18], [0, 180])
114
  h_hist = cv2.normalize(h_hist, h_hist).flatten().tolist()
115
 
116
+ # ── GLCM texture (6) ──────────────────────────────────────────────────────
117
+ # Crop to bounding box of mask, inpaint background pixels, then quantise.
118
+ # This exactly replicates the notebook's GLCM pipeline.
119
+ x, y, bw, bh = cv2.boundingRect(mask2)
120
+ if bw > 0 and bh > 0:
121
+ gray_crop = gray[y:y + bh, x:x + bw]
122
+ mask_crop = mask2[y:y + bh, x:x + bw]
123
+ masked_gray_raw = np.where(mask_crop > 0, gray_crop, 0).astype(np.uint8)
124
+ inv_mask_crop = cv2.bitwise_not(mask_crop)
125
+ if np.count_nonzero(inv_mask_crop) > 0:
126
+ inpainted = cv2.inpaint(masked_gray_raw, inv_mask_crop,
127
+ inpaintRadius=1, flags=cv2.INPAINT_TELEA)
128
+ masked_gray = inpainted if inpainted is not None else masked_gray_raw
129
+ else:
130
+ masked_gray = masked_gray_raw
131
+ else:
132
+ # GrabCut returned empty mask β€” fall back to full grayscale
133
+ masked_gray = gray
134
+
135
+ masked_gray_q = (masked_gray // 8).astype(np.uint8)
136
+ valid_pixels = masked_gray_q[masked_gray_q > 0]
137
+ if valid_pixels.size < 100:
138
+ # Fallback: use full unmasked grayscale
139
+ glcm_input = (gray // 8).astype(np.uint8)
140
+ else:
141
+ glcm_input = masked_gray_q
142
+
143
+ glcm = graycomatrix(glcm_input, distances=[1, 3, 5],
144
  angles=[0, np.pi/4, np.pi/2, 3*np.pi/4],
145
  levels=32, symmetric=True, normed=True)
146
  glcm_feats = [
 
148
  graycoprops(glcm, 'correlation').mean(),
149
  graycoprops(glcm, 'energy').mean(),
150
  graycoprops(glcm, 'homogeneity').mean(),
151
+ graycoprops(glcm, 'dissimilarity').mean(),
152
+ graycoprops(glcm, 'ASM').mean(),
153
  ]
154
 
155
+ # ── LBP texture 10 bins (10) ──────────────────────────────────────────────
156
  lbp = local_binary_pattern(gray, P=8, R=1, method='uniform')
157
  lbp_pixels = lbp[fp] if fp.any() else lbp.ravel()
158
  lbp_hist, _ = np.histogram(lbp_pixels, bins=10, range=(0, 10), density=True)
159
 
160
  features = hsv_feats + lab_feats + h_hist + glcm_feats + lbp_hist.tolist() + [aspect_ratio, extent]
161
+
162
+ # raw dict for frontend display
163
  raw = {
164
  'h_mean': hsv_feats[0], 's_mean': hsv_feats[1], 'v_mean': hsv_feats[2],
165
  'h_std': hsv_feats[3], 's_std': hsv_feats[4], 'v_std': hsv_feats[5],
166
  'contrast': glcm_feats[0], 'correlation': glcm_feats[1],
167
+ 'energy': glcm_feats[2], 'homogeneity': glcm_feats[3],
168
  'aspect_ratio': aspect_ratio, 'extent': extent,
169
  }
170
  return features, raw
 
283
  print("RIPE.AI β€” Flask API Server")
284
  print("=" * 60)
285
  print(f"Model loaded: {model_loaded}")
286
+ app.run(host='0.0.0.0', port=5000, debug=False)