| import os
|
| import numpy as np
|
| import tensorflow as tf
|
| from tensorflow.keras import layers, models
|
| from tensorflow.keras.preprocessing.image import ImageDataGenerator
|
| from sklearn.model_selection import train_test_split
|
| import matplotlib.pyplot as plt
|
|
|
|
|
| dataset_path = r"C:\Users\Joel\Desktop\bin\Soil-Type-1\Soil Types"
|
| output_model_path = r"C:\Users\Joel\Desktop\bin\Soil-Type-1\soil_type_model.h5"
|
|
|
| def create_soil_type_classifier():
|
|
|
|
|
|
|
| train_dir = os.path.join(dataset_path, 'train')
|
| val_dir = os.path.join(dataset_path, 'validation')
|
|
|
| if not os.path.exists(train_dir):
|
| os.makedirs(train_dir)
|
| if not os.path.exists(val_dir):
|
| os.makedirs(val_dir)
|
|
|
|
|
| soil_types = [d for d in os.listdir(dataset_path) if os.path.isdir(os.path.join(dataset_path, d))
|
| and d not in ['train', 'validation']]
|
|
|
| for soil_type in soil_types:
|
| train_soil_dir = os.path.join(train_dir, soil_type)
|
| val_soil_dir = os.path.join(val_dir, soil_type)
|
|
|
| if not os.path.exists(train_soil_dir):
|
| os.makedirs(train_soil_dir)
|
| if not os.path.exists(val_soil_dir):
|
| os.makedirs(val_soil_dir)
|
|
|
|
|
| for soil_type in soil_types:
|
| soil_dir = os.path.join(dataset_path, soil_type)
|
| image_files = [f for f in os.listdir(soil_dir) if f.endswith(('.jpg', '.jpeg', '.png'))]
|
|
|
|
|
| np.random.shuffle(image_files)
|
|
|
|
|
| train_files = image_files[:int(0.8 * len(image_files))]
|
| val_files = image_files[int(0.8 * len(image_files)):]
|
|
|
|
|
| import shutil
|
| for file in train_files:
|
| src = os.path.join(soil_dir, file)
|
| dst = os.path.join(train_dir, soil_type, file)
|
| shutil.copy(src, dst)
|
|
|
|
|
| for file in val_files:
|
| src = os.path.join(soil_dir, file)
|
| dst = os.path.join(val_dir, soil_type, file)
|
| shutil.copy(src, dst)
|
|
|
| print(f"Dataset organized into {len(soil_types)} categories: {', '.join(soil_types)}")
|
|
|
|
|
| train_datagen = ImageDataGenerator(
|
| rescale=1./255,
|
| rotation_range=20,
|
| width_shift_range=0.2,
|
| height_shift_range=0.2,
|
| shear_range=0.2,
|
| zoom_range=0.2,
|
| horizontal_flip=True,
|
| fill_mode='nearest'
|
| )
|
|
|
| validation_datagen = ImageDataGenerator(rescale=1./255)
|
|
|
|
|
| img_height, img_width = 224, 224
|
| batch_size = 32
|
|
|
|
|
| train_generator = train_datagen.flow_from_directory(
|
| train_dir,
|
| target_size=(img_height, img_width),
|
| batch_size=batch_size,
|
| class_mode='categorical'
|
| )
|
|
|
| validation_generator = validation_datagen.flow_from_directory(
|
| val_dir,
|
| target_size=(img_height, img_width),
|
| batch_size=batch_size,
|
| class_mode='categorical'
|
| )
|
|
|
|
|
| model = models.Sequential([
|
|
|
| layers.Conv2D(32, (3, 3), activation='relu', input_shape=(img_height, img_width, 3)),
|
| layers.MaxPooling2D((2, 2)),
|
| layers.Conv2D(64, (3, 3), activation='relu'),
|
| layers.MaxPooling2D((2, 2)),
|
| layers.Conv2D(128, (3, 3), activation='relu'),
|
| layers.MaxPooling2D((2, 2)),
|
| layers.Conv2D(128, (3, 3), activation='relu'),
|
| layers.MaxPooling2D((2, 2)),
|
|
|
|
|
| layers.Flatten(),
|
| layers.Dropout(0.5),
|
| layers.Dense(512, activation='relu'),
|
| layers.Dense(len(soil_types), activation='softmax')
|
| ])
|
|
|
|
|
| model.compile(
|
| optimizer='adam',
|
| loss='categorical_crossentropy',
|
| metrics=['accuracy']
|
| )
|
|
|
|
|
| epochs = 15
|
|
|
| history = model.fit(
|
| train_generator,
|
| steps_per_epoch=train_generator.samples // batch_size,
|
| epochs=epochs,
|
| validation_data=validation_generator,
|
| validation_steps=validation_generator.samples // batch_size
|
| )
|
|
|
|
|
| model.save(output_model_path)
|
| print(f"Model saved to {output_model_path}")
|
|
|
|
|
| acc = history.history['accuracy']
|
| val_acc = history.history['val_accuracy']
|
| loss = history.history['loss']
|
| val_loss = history.history['val_loss']
|
|
|
| plt.figure(figsize=(12, 4))
|
| plt.subplot(1, 2, 1)
|
| plt.plot(acc, label='Training Accuracy')
|
| plt.plot(val_acc, label='Validation Accuracy')
|
| plt.xlabel('Epoch')
|
| plt.ylabel('Accuracy')
|
| plt.legend()
|
|
|
| plt.subplot(1, 2, 2)
|
| plt.plot(loss, label='Training Loss')
|
| plt.plot(val_loss, label='Validation Loss')
|
| plt.xlabel('Epoch')
|
| plt.ylabel('Loss')
|
| plt.legend()
|
|
|
| plt.tight_layout()
|
| plt.savefig(os.path.join(dataset_path, 'training_results.png'))
|
| plt.show()
|
|
|
|
|
| return model, train_generator.class_indices
|
|
|
| def predict_soil_type(model, image_path, class_indices):
|
| """
|
| Predict soil type for a given image
|
| """
|
| img_height, img_width = 224, 224
|
|
|
|
|
| img = tf.keras.preprocessing.image.load_img(
|
| image_path, target_size=(img_height, img_width)
|
| )
|
| img_array = tf.keras.preprocessing.image.img_to_array(img)
|
| img_array = tf.expand_dims(img_array, 0) / 255.0
|
|
|
|
|
| predictions = model.predict(img_array)
|
| score = tf.nn.softmax(predictions[0])
|
|
|
|
|
| predicted_class = np.argmax(score)
|
| confidence = 100 * np.max(score)
|
|
|
|
|
| class_names = {v: k for k, v in class_indices.items()}
|
| predicted_soil_type = class_names[predicted_class]
|
|
|
| print(f"This image is classified as: {predicted_soil_type} with {confidence:.2f}% confidence")
|
| return predicted_soil_type, confidence
|
|
|
|
|
| if __name__ == "__main__":
|
| model, class_indices = create_soil_type_classifier()
|
|
|
|
|
|
|
| test_image = input("Enter path to a test image: ")
|
| if os.path.exists(test_image):
|
| predict_soil_type(model, test_image, class_indices)
|
| else:
|
| print("Invalid image path. You can test the model later with a valid image.") |