SonFox2920 commited on
Commit
8be899f
·
verified ·
1 Parent(s): f03e6a4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +376 -69
app.py CHANGED
@@ -2,6 +2,7 @@ import streamlit as st
2
  import tensorflow as tf
3
  import numpy as np
4
  import cv2
 
5
  from PIL import Image
6
  from tensorflow.keras import layers, models
7
  from tensorflow.keras.applications import EfficientNetB0
@@ -9,6 +10,25 @@ from tensorflow.keras.applications.efficientnet import preprocess_input
9
  import joblib
10
  import io
11
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  # Add Cloudinary import
14
  import cloudinary
@@ -22,6 +42,7 @@ cloudinary.config(
22
  api_secret = os.getenv("SECRET"),
23
  secure=True
24
  )
 
25
  def upload_to_cloudinary(file_path, label):
26
  """
27
  Upload file to Cloudinary with specified label as folder
@@ -59,7 +80,7 @@ def upload_to_cloudinary(file_path, label):
59
  return f"Error uploading to Cloudinary: {str(e)}"
60
 
61
  def main():
62
- st.title("🨨 Phân loại đá")
63
  st.write("Tải lên hình ảnh của một viên đá để phân loại loại của nó.")
64
 
65
  # Load model and scaler
@@ -88,7 +109,7 @@ def main():
88
 
89
  with st.spinner('Đang phân tích hình ảnh...'):
90
  processed_image = preprocess_image(image, scaler)
91
- prediction = model.predict(processed_image, verbose=0)
92
 
93
  class_names = ['10', '6.5', '7', '7.5', '8', '8.5', '9', '9.2', '9.5', '9.7']
94
  st.session_state.predictions = get_top_predictions(prediction, class_names)
@@ -181,127 +202,413 @@ def load_model_and_scaler():
181
  try:
182
  model = tf.keras.models.load_model('mlp_model.h5')
183
  # Tải scaler đã lưu
184
- scaler = joblib.load('standard_scaler.pkl')
185
  return model, scaler
186
  except Exception as e:
187
  st.error(f"Error loading model or scaler: {str(e)}")
188
  return None, None
189
 
190
  def color_histogram(image, bins=16):
191
- """Calculate color histogram features"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  hist_r = cv2.calcHist([image], [0], None, [bins], [0, 256]).flatten()
193
  hist_g = cv2.calcHist([image], [1], None, [bins], [0, 256]).flatten()
194
  hist_b = cv2.calcHist([image], [2], None, [bins], [0, 256]).flatten()
195
 
196
- hist_r = hist_r / (np.sum(hist_r) + 1e-7)
197
- hist_g = hist_g / (np.sum(hist_g) + 1e-7)
198
- hist_b = hist_b / (np.sum(hist_b) + 1e-7)
 
199
 
200
  return np.concatenate([hist_r, hist_g, hist_b])
201
 
202
  def color_moments(image):
203
- """Calculate color moments features"""
204
- img = image.astype(np.float32) / 255.0
205
- moments = []
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
- for i in range(3):
 
208
  channel = img[:,:,i]
 
 
209
  mean = np.mean(channel)
210
- std = np.std(channel) + 1e-7
211
- skewness = np.mean(((channel - mean) / std) ** 3) if std != 0 else 0
 
212
  moments.extend([mean, std, skewness])
213
 
214
  return np.array(moments)
215
 
216
  def dominant_color_descriptor(image, k=3):
217
- """Calculate dominant color descriptor"""
218
- pixels = image.reshape(-1, 3).astype(np.float32)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
 
 
 
 
220
  criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
221
  flags = cv2.KMEANS_RANDOM_CENTERS
222
 
223
  try:
224
- _, labels, centers = cv2.kmeans(pixels, k, None, criteria, 10, flags)
 
 
 
 
 
225
  unique, counts = np.unique(labels, return_counts=True)
226
  percentages = counts / len(labels)
227
- return np.concatenate([centers.flatten(), percentages])
 
 
 
 
 
228
  except Exception:
229
- return np.zeros(k * 4)
 
230
 
231
  def color_coherence_vector(image, k=3):
232
- """Calculate color coherence vector"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
234
- gray = np.uint8(gray)
235
 
 
 
 
 
 
236
  _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
 
 
237
  num_labels, labels = cv2.connectedComponents(binary)
238
 
239
  ccv = []
240
  for i in range(1, min(k+1, num_labels)):
241
  region_mask = (labels == i)
242
  total_pixels = np.sum(region_mask)
243
- ccv.extend([total_pixels, total_pixels])
244
 
245
- ccv.extend([0] * (2 * k - len(ccv)))
246
- return np.array(ccv[:2*k])
247
 
248
- @st.cache_resource
249
- def create_vit_feature_extractor():
250
- """Create and cache the ViT feature extractor"""
251
- input_shape = (256, 256, 3)
252
- inputs = layers.Input(shape=input_shape)
253
- x = layers.Lambda(preprocess_input)(inputs)
254
 
255
- base_model = EfficientNetB0(
256
- include_top=False,
257
- weights='imagenet',
258
- input_tensor=x
259
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
- x = layers.GlobalAveragePooling2D()(base_model.output)
262
- return models.Model(inputs=inputs, outputs=x)
263
 
264
  def extract_features(image):
265
- """Extract all features from an image"""
266
- # Traditional features
267
- hist_features = color_histogram(image)
268
- moment_features = color_moments(image)
269
- dominant_features = dominant_color_descriptor(image)
270
- ccv_features = color_coherence_vector(image)
271
-
272
- traditional_features = np.concatenate([
273
- hist_features,
274
- moment_features,
275
- dominant_features,
276
- ccv_features
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  ])
278
 
279
- # Deep features using ViT
280
- feature_extractor = create_vit_feature_extractor()
281
- vit_features = feature_extractor.predict(
282
- np.expand_dims(image, axis=0),
283
- verbose=0
284
- )
285
 
286
- # Combine all features
287
- return np.concatenate([traditional_features, vit_features.flatten()])
 
288
 
289
- def preprocess_image(image, scaler):
290
- """Preprocess the uploaded image"""
291
- # Convert to RGB if needed
292
- if image.mode != 'RGB':
293
- image = image.convert('RGB')
 
 
 
 
 
 
 
 
294
 
295
- # Convert to numpy array and resize
296
- img_array = np.array(image)
297
- img_array = cv2.resize(img_array, (256, 256))
298
- img_array = img_array.astype('float32') / 255.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
 
300
- # Extract all features
301
- features = extract_features(img_array)
 
 
 
 
 
 
 
 
 
 
 
302
 
303
  # Scale features using the provided scaler
304
- scaled_features = scaler.transform(features.reshape(1, -1))
305
 
306
  return scaled_features
307
 
@@ -312,4 +619,4 @@ def get_top_predictions(prediction, class_names):
312
  return [(class_names[i], probabilities[i] * 100) for i in top_indices]
313
 
314
  if __name__ == "__main__":
315
- main()
 
2
  import tensorflow as tf
3
  import numpy as np
4
  import cv2
5
+ import pywt # Thư viện xử lý wavelet
6
  from PIL import Image
7
  from tensorflow.keras import layers, models
8
  from tensorflow.keras.applications import EfficientNetB0
 
10
  import joblib
11
  import io
12
  import os
13
+ import cv2
14
+ import numpy as np
15
+ from tensorflow import keras
16
+ from tensorflow.keras import layers, models
17
+ from sklearn.preprocessing import StandardScaler
18
+ from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
19
+ from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
20
+ import matplotlib.pyplot as plt
21
+ import random
22
+ from keras.applications import ResNet50
23
+ from tensorflow.keras.applications.resnet import preprocess_input
24
+ from tensorflow.keras import layers, models
25
+ from tensorflow.keras.applications.resnet import preprocess_input
26
+ from tensorflow.keras.applications import EfficientNetB0
27
+ from tensorflow.keras.applications.efficientnet import preprocess_input
28
+ from tensorflow.keras.layers import Lambda # Đảm bảo nhập Lambda từ tensorflow.keras.layers
29
+ from skimage.feature import graycomatrix, graycoprops
30
+ from keras.applications import ResNet50
31
+ from tensorflow.keras.applications.resnet import preprocess_input
32
 
33
  # Add Cloudinary import
34
  import cloudinary
 
42
  api_secret = os.getenv("SECRET"),
43
  secure=True
44
  )
45
+
46
  def upload_to_cloudinary(file_path, label):
47
  """
48
  Upload file to Cloudinary with specified label as folder
 
80
  return f"Error uploading to Cloudinary: {str(e)}"
81
 
82
  def main():
83
+ st.title("Web App Phân loại đá")
84
  st.write("Tải lên hình ảnh của một viên đá để phân loại loại của nó.")
85
 
86
  # Load model and scaler
 
109
 
110
  with st.spinner('Đang phân tích hình ảnh...'):
111
  processed_image = preprocess_image(image, scaler)
112
+ prediction = model.predict(processed_image)
113
 
114
  class_names = ['10', '6.5', '7', '7.5', '8', '8.5', '9', '9.2', '9.5', '9.7']
115
  st.session_state.predictions = get_top_predictions(prediction, class_names)
 
202
  try:
203
  model = tf.keras.models.load_model('mlp_model.h5')
204
  # Tải scaler đã lưu
205
+ scaler = joblib.load('scaler.pkl')
206
  return model, scaler
207
  except Exception as e:
208
  st.error(f"Error loading model or scaler: {str(e)}")
209
  return None, None
210
 
211
  def color_histogram(image, bins=16):
212
+ """
213
+ Tính histogram màu cho ảnh RGB
214
+
215
+ Args:
216
+ image (np.ndarray): Ảnh đầu vào
217
+ bins (int): Số lượng bins của histogram
218
+
219
+ Returns:
220
+ np.ndarray: Histogram màu được chuẩn hóa
221
+ """
222
+ # Kiểm tra và chuyển đổi ảnh
223
+ if image is None or image.size == 0:
224
+ raise ValueError("Ảnh không hợp lệ")
225
+
226
+ # Đảm bảo ảnh ở dạng uint8
227
+ if image.dtype != np.uint8:
228
+ image = (image * 255).astype(np.uint8)
229
+
230
+ # Tính histogram cho từng kênh màu
231
  hist_r = cv2.calcHist([image], [0], None, [bins], [0, 256]).flatten()
232
  hist_g = cv2.calcHist([image], [1], None, [bins], [0, 256]).flatten()
233
  hist_b = cv2.calcHist([image], [2], None, [bins], [0, 256]).flatten()
234
 
235
+ # Chuẩn hóa histogram
236
+ hist_r = hist_r / np.sum(hist_r) if np.sum(hist_r) > 0 else hist_r
237
+ hist_g = hist_g / np.sum(hist_g) if np.sum(hist_g) > 0 else hist_g
238
+ hist_b = hist_b / np.sum(hist_b) if np.sum(hist_b) > 0 else hist_b
239
 
240
  return np.concatenate([hist_r, hist_g, hist_b])
241
 
242
  def color_moments(image):
243
+ """
244
+ Tính các moment màu cho ảnh
245
+
246
+ Args:
247
+ image (np.ndarray): Ảnh đầu vào
248
+
249
+ Returns:
250
+ np.ndarray: Các moment màu
251
+ """
252
+ # Kiểm tra và chuyển đổi ảnh
253
+ if image is None or image.size == 0:
254
+ raise ValueError("Ảnh không hợp lệ")
255
+
256
+ # Đảm bảo ảnh ở dạng float và chuẩn hóa
257
+ img = image.astype(np.float32) / 255.0 if image.max() > 1 else image.astype(np.float32)
258
 
259
+ moments = []
260
+ for i in range(3): # Cho mỗi kênh màu
261
  channel = img[:,:,i]
262
+
263
+ # Tính các moment
264
  mean = np.mean(channel)
265
+ std = np.std(channel)
266
+ skewness = np.mean(((channel - mean) / (std + 1e-8)) ** 3)
267
+
268
  moments.extend([mean, std, skewness])
269
 
270
  return np.array(moments)
271
 
272
  def dominant_color_descriptor(image, k=3):
273
+ """
274
+ Xác định các màu chính thống trị trong ảnh
275
+
276
+ Args:
277
+ image (np.ndarray): Ảnh đầu vào
278
+ k (int): Số lượng màu chủ đạo
279
+
280
+ Returns:
281
+ np.ndarray: Các màu chủ đạo và tỷ lệ
282
+ """
283
+ # Kiểm tra và chuyển đổi ảnh
284
+ if image is None or image.size == 0:
285
+ raise ValueError("Ảnh không hợp lệ")
286
+
287
+ # Đảm bảo ảnh ở dạng uint8
288
+ if image.dtype != np.uint8:
289
+ image = (image * 255).astype(np.uint8)
290
 
291
+ # Reshape ảnh thành mảng pixel
292
+ pixels = image.reshape(-1, 3)
293
+
294
+ # Các tham số cho K-means
295
  criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
296
  flags = cv2.KMEANS_RANDOM_CENTERS
297
 
298
  try:
299
+ # Thực hiện phân cụm K-means
300
+ _, labels, centers = cv2.kmeans(
301
+ pixels.astype(np.float32), k, None, criteria, 10, flags
302
+ )
303
+
304
+ # Tính toán số lượng và tỷ lệ của từng cụm
305
  unique, counts = np.unique(labels, return_counts=True)
306
  percentages = counts / len(labels)
307
+
308
+ # Kết hợp các màu và tỷ lệ
309
+ dominant_colors = centers.flatten()
310
+ color_percentages = percentages
311
+
312
+ return np.concatenate([dominant_colors, color_percentages])
313
  except Exception:
314
+ # Trả về mảng 0 nếu có lỗi
315
+ return np.zeros(2 * k)
316
 
317
  def color_coherence_vector(image, k=3):
318
+ """
319
+ Tính vector liên kết màu
320
+
321
+ Args:
322
+ image (np.ndarray): Ảnh đầu vào
323
+ k (int): Số lượng vùng
324
+
325
+ Returns:
326
+ np.ndarray: Vector liên kết màu
327
+ """
328
+ # Kiểm tra và chuyển đổi ảnh
329
+ if image is None or image.size == 0:
330
+ raise ValueError("Ảnh không hợp lệ")
331
+
332
+ # Chuyển sang ảnh xám
333
  gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
 
334
 
335
+ # Đảm bảo ảnh ở dạng uint8
336
+ if gray.dtype != np.uint8:
337
+ gray = np.uint8(gray)
338
+
339
+ # Áp dụng Otsu's thresholding
340
  _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
341
+
342
+ # Phân tích thành phần liên thông
343
  num_labels, labels = cv2.connectedComponents(binary)
344
 
345
  ccv = []
346
  for i in range(1, min(k+1, num_labels)):
347
  region_mask = (labels == i)
348
  total_pixels = np.sum(region_mask)
349
+ coherent_pixels = total_pixels
350
 
351
+ ccv.extend([coherent_pixels, total_pixels])
 
352
 
353
+ # Đảm bảo độ dài vector
354
+ while len(ccv) < 2 * k:
355
+ ccv.append(0)
 
 
 
356
 
357
+ return np.array(ccv)
358
+
359
+ def edge_features(image, bins=16):
360
+ """
361
+ Trích xuất đặc trưng cạnh từ ảnh
362
+
363
+ Args:
364
+ image (np.ndarray): Ảnh đầu vào
365
+ bins (int): Số lượng bins của histogram
366
+
367
+ Returns:
368
+ np.ndarray: Đặc trưng cạnh
369
+ """
370
+ # Kiểm tra và chuyển đổi ảnh
371
+ if image is None or image.size == 0:
372
+ raise ValueError("Ảnh không hợp lệ")
373
+
374
+ # Chuyển sang ảnh xám
375
+ gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
376
+
377
+ # Đảm bảo ảnh ở dạng uint8
378
+ if gray.dtype != np.uint8:
379
+ gray = np.uint8(gray)
380
+
381
+ # Tính Sobel edges
382
+ sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
383
+ sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
384
+ sobel_mag = np.sqrt(sobel_x**2 + sobel_y**2)
385
+
386
+ # Chuẩn hóa độ lớn Sobel
387
+ sobel_mag = np.uint8(255 * sobel_mag / np.max(sobel_mag))
388
+
389
+ # Tính histogram của Sobel magnitude
390
+ sobel_hist = cv2.calcHist([sobel_mag], [0], None, [bins], [0, 256]).flatten()
391
+ sobel_hist = sobel_hist / np.sum(sobel_hist) if np.sum(sobel_hist) > 0 else sobel_hist
392
+
393
+ # Tính mật độ cạnh bằng Canny
394
+ canny_edges = cv2.Canny(gray, 100, 200)
395
+ edge_density = np.sum(canny_edges) / (gray.shape[0] * gray.shape[1])
396
+
397
+ return np.concatenate([sobel_hist, [edge_density]])
398
+
399
+
400
+
401
+ def histogram_in_color_space(image, color_space='HSV', bins=16):
402
+ """
403
+ Tính histogram của ảnh trong một không gian màu mới.
404
+ """
405
+ if color_space == 'HSV':
406
+ converted = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
407
+ elif color_space == 'LAB':
408
+ converted = cv2.cvtColor(image, cv2.COLOR_RGB2Lab)
409
+ else:
410
+ raise ValueError("Unsupported color space")
411
+
412
+ histograms = []
413
+ for i in range(3): # 3 kênh màu
414
+ hist = cv2.calcHist([converted], [i], None, [bins], [0, 256]).flatten()
415
+ hist = hist / np.sum(hist)
416
+ histograms.append(hist)
417
+
418
+ return np.concatenate(histograms)
419
+
420
+ def glcm_features(image, distances=[1, 2, 3], angles=[0, np.pi/4, np.pi/2, 3*np.pi/4], levels=256):
421
+ """
422
+ Tính các đặc trưng GLCM của ảnh grayscale.
423
+ """
424
+ gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
425
+
426
+ # Đảm bảo ảnh ở dạng uint8
427
+ if gray.dtype != np.uint8:
428
+ gray = (gray * 255).astype(np.uint8)
429
+
430
+ glcm = graycomatrix(gray, distances=distances, angles=angles, levels=levels, symmetric=True, normed=True)
431
+
432
+ features = []
433
+ # Các thuộc tính phổ biến: contrast, homogeneity, energy, correlation
434
+ for prop in ['contrast', 'homogeneity', 'energy', 'correlation']:
435
+ features.extend(graycoprops(glcm, prop).flatten())
436
+
437
+ return np.array(features)
438
+
439
+
440
+ def gabor_features(image, kernels=None):
441
+ """
442
+ Tính các đặc trưng từ bộ lọc Gabor.
443
+ """
444
+ if kernels is None:
445
+ kernels = []
446
+ for theta in np.arange(0, np.pi, np.pi / 4): # Các góc từ 0 đến 180 độ
447
+ for sigma in [1, 3]: # Các giá trị sigma
448
+ for frequency in [0.1, 0.5]: # Các tần số
449
+ kernel = cv2.getGaborKernel((9, 9), sigma, theta, 1/frequency, gamma=0.5, ktype=cv2.CV_32F)
450
+ kernels.append(kernel)
451
+
452
+ gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
453
+ features = []
454
+ for kernel in kernels:
455
+ filtered = cv2.filter2D(gray, cv2.CV_32F, kernel)
456
+ features.append(filtered.mean())
457
+ features.append(filtered.var())
458
+
459
+ return np.array(features)
460
+
461
+ def wavelet_features(image, wavelet='db1', level=3):
462
+ """
463
+ Trích xuất các hệ số wavelet từ ảnh grayscale.
464
+ """
465
+ gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
466
+ coeffs = pywt.wavedec2(gray, wavelet, level=level)
467
+ features = []
468
+ for coeff in coeffs:
469
+ if isinstance(coeff, tuple): # Chi tiết (LH, HL, HH)
470
+ for subband in coeff:
471
+ features.append(subband.mean())
472
+ features.append(subband.var())
473
+ else: # Xấp xỉ (LL)
474
+ features.append(coeff.mean())
475
+ features.append(coeff.var())
476
+
477
+ return np.array(features)
478
+
479
+ def fractal_dimension(image):
480
+ """
481
+ Tính Fractal Dimension của ảnh.
482
+ """
483
+ # Chuyển đổi ảnh sang grayscale
484
+ gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
485
+
486
+ # Đảm bảo ảnh ở dạng uint8
487
+ if gray.dtype != np.uint8:
488
+ gray = (gray * 255).astype(np.uint8)
489
+
490
+ # Áp dụng Canny để tìm cạnh
491
+ edges = cv2.Canny(gray, 100, 200)
492
+
493
+ # Tính fractal dimension dựa trên phương pháp box-counting
494
+ sizes = []
495
+ counts = []
496
+ for size in range(2, 65, 2): # Kích thước hộp từ 2 đến 64
497
+ region_size = (edges.shape[0] // size, edges.shape[1] // size)
498
+ count = np.sum(cv2.resize(edges, region_size, interpolation=cv2.INTER_AREA) > 0)
499
+ sizes.append(size)
500
+ counts.append(count)
501
+
502
+ # Tính log-log slope
503
+ log_sizes = np.log(sizes)
504
+ log_counts = np.log(counts)
505
+ slope, _ = np.polyfit(log_sizes, log_counts, 1)
506
+
507
+ # Trả về giá trị fractal dimension
508
+ return np.array([slope])
509
 
 
 
510
 
511
  def extract_features(image):
512
+ """
513
+ Extract multiple features from an image, including edge-based features.
514
+ """
515
+ color_hist = color_histogram(image)
516
+ color_mom = color_moments(image)
517
+ dom_color = dominant_color_descriptor(image)
518
+ ccv = color_coherence_vector(image)
519
+ edges = edge_features(image)
520
+
521
+ # Các đặc trưng từ phương pháp mới
522
+ hsv_hist = histogram_in_color_space(image, color_space='HSV')
523
+ # lab_hist = histogram_in_color_space(image, color_space='LAB')
524
+ glcm = glcm_features(image)
525
+ gabor = gabor_features(image)
526
+ wavelet = wavelet_features(image)
527
+ # fractal = fractal_dimension(image)
528
+
529
+ # Kết hợp tất cả thành một vector đặc trưng
530
+ return np.concatenate([
531
+ color_hist,
532
+ color_mom,
533
+ dom_color,
534
+ ccv,
535
+ edges,
536
+ hsv_hist,
537
+ # lab_hist,
538
+ glcm,
539
+ gabor,
540
+ wavelet,
541
+ # fractal
542
  ])
543
 
 
 
 
 
 
 
544
 
545
+ def create_resnet50_feature_extractor(input_shape=(256, 256, 3), num_classes=None):
546
+ # Xây dựng mô hình ResNet112 đã huấn luyện sẵn từ TensorFlow
547
+ inputs = layers.Input(shape=input_shape)
548
 
549
+ # Thêm lớp Lambda để tiền xử lý ảnh
550
+ x = Lambda(preprocess_input, output_shape=input_shape)(inputs) # Xử lý ảnh đầu vào
551
+
552
+ # Sử dụng mô hình ResNet112 đã được huấn luyện sẵn
553
+ resnet50_model = ResNet50(include_top=False, weights='imagenet', input_tensor=x)
554
+
555
+ # Trích xuất đặc trưng từ mô hình ResNet112
556
+ x = layers.GlobalAveragePooling2D()(resnet50_model.output)
557
+
558
+ if num_classes:
559
+ x = layers.Dense(num_classes, activation='softmax')(x) # Thêm lớp phân loại (nếu có)
560
+
561
+ return models.Model(inputs=inputs, outputs=x)
562
 
563
+ def extract_features(image):
564
+ """
565
+ Extract multiple features from an image, including edge-based features.
566
+ """
567
+ color_hist = color_histogram(image)
568
+ color_mom = color_moments(image)
569
+ dom_color = dominant_color_descriptor(image)
570
+ ccv = color_coherence_vector(image)
571
+ edges = edge_features(image)
572
+
573
+ # Các đặc trưng từ phương pháp mới
574
+ hsv_hist = histogram_in_color_space(image, color_space='HSV')
575
+ # lab_hist = histogram_in_color_space(image, color_space='LAB')
576
+ glcm = glcm_features(image)
577
+ gabor = gabor_features(image)
578
+ wavelet = wavelet_features(image)
579
+ # fractal = fractal_dimension(image)
580
+
581
+ # Kết hợp tất cả thành một vector đặc trưng
582
+ return np.concatenate([
583
+ color_hist,
584
+ color_mom,
585
+ dom_color,
586
+ ccv,
587
+ edges,
588
+ hsv_hist,
589
+ # lab_hist,
590
+ glcm,
591
+ gabor,
592
+ wavelet,
593
+ # fractal
594
+ ])
595
 
596
+ def preprocess_image(image, scaler):
597
+ image=np.array(image)
598
+ img_size=(256, 256)
599
+ img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
600
+ img = cv2.resize(img, img_size)
601
+ img_array = img.astype('float32') / 255.0
602
+
603
+ features1 = np.array(extract_features(img_array))
604
+ resnet_extractor = create_resnet50_feature_extractor()
605
+ features2 = resnet_extractor.predict(np.expand_dims(img_array, axis=0))
606
+ print(f"Shape of features1: {features1.shape}")
607
+ print(f"Shape of features2: {features2.shape}")
608
+ features = np.concatenate([np.expand_dims(features1, axis=0), features2], axis=1) # Concatenate along axis 0
609
 
610
  # Scale features using the provided scaler
611
+ scaled_features = scaler.transform(features) # Reshape for scaling
612
 
613
  return scaled_features
614
 
 
619
  return [(class_names[i], probabilities[i] * 100) for i in top_indices]
620
 
621
  if __name__ == "__main__":
622
+ main()