Skip to content

Instantly share code, notes, and snippets.

@shekhargulati
Created January 13, 2025 19:22
Show Gist options
  • Save shekhargulati/1011aa52ea203daffa4e84910318a953 to your computer and use it in GitHub Desktop.
Save shekhargulati/1011aa52ea203daffa4e84910318a953 to your computer and use it in GitHub Desktop.

Creating a "Plant Buddy" application that analyzes photos of your houseplants' soil to determine if they need watering is a fantastic idea! Below, I'll outline a step-by-step guide to building this program, including the technologies you can use, considerations for ensuring accuracy, and tips to make it user-friendly.


1. Overview of the Solution

  • Input: Photo of the plant's soil taken with a smartphone.
  • Processing: Image classification to determine soil moisture.
  • Output:
    • Status: "Thirsty!" or "Doing fine!"
    • Confidence Level: e.g., "70% sure"
    • Logging: Tracks the last watering time.

2. Step-by-Step Guide

Step 1: Set Up Your Development Environment

Tools & Libraries:

  • Programming Language: Python
  • Libraries:
  • IDE: VS Code, PyCharm, or any preferred code editor.

Installation:

pip install tensorflow keras opencv-python pillow sqlite3

Step 2: Data Collection

To train an effective image classifier, you'll need a good dataset.

What You Need:

  • Images of Soil: Take clear photos of the soil from each of your 6 plants. Capture various moisture levels: dry, moist, and overwatered.
  • Variations:
    • Different pot colors and textures.
    • Various lighting conditions (natural light, artificial light).
    • Different shadow patterns.

Tips:

  • Consistency: Try to capture images from the same angle and distance.
  • Quantity: Aim for at least 200 images per class (e.g., 200 dry, 200 moist).

Step 3: Data Labeling

Label each image based on soil moisture:

  • Classes:
    • Thirsty (dry soil)
    • Moist (adequately watered)
    • Overwatered (optional, for more detailed tracking)

Tools for Labeling:

  • LabelImg or simply organize images into folders named after their classes.

Step 4: Data Preprocessing

Handle variations and improve model robustness.

Techniques:

  • Data Augmentation: Apply transformations to increase diversity.
    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    
    datagen = ImageDataGenerator(
        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'
    )
  • Normalization: Scale pixel values.
    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    
    datagen = ImageDataGenerator(rescale=1./255)

Step 5: Building the Image Classifier

Use Transfer Learning with a pre-trained model like MobileNetV2 for efficiency, especially if deploying to mobile.

Sample Code Using TensorFlow & Keras:

import tensorflow as tf
from tensorflow.keras import layers, models

# Load pre-trained model
base_model = tf.keras.applications.MobileNetV2(
    input_shape=(224, 224, 3),
    include_top=False,
    weights='imagenet'
)

base_model.trainable = False  # Freeze base model

# Add custom layers
model = models.Sequential([
    base_model,
    layers.GlobalAveragePooling2D(),
    layers.Dense(128, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(2, activation='softmax')  # Modify for number of classes
])

model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# Summary
model.summary()

Training:

# Assuming you have training and validation generators
history = model.fit(
    train_generator,
    epochs=10,
    validation_data=validation_generator
)

Step 6: Evaluating the Model

Ensure your model meets the necessary checks.

  • Handle Different Pot Colors & Lighting:

    • Ensure your dataset includes diverse examples.
    • Use data augmentation to simulate different lighting and pot colors.
  • Avoid Confusing Shadows with Wet Soil:

    • Include images with varying shadows in both classes.
    • Apply image preprocessing techniques to reduce shadow effects (e.g., histogram equalization).
  • Performance Metrics:

    • Aim for high accuracy on validation data.
    • Use confusion matrices to check for misclassifications.

Step 7: Building the Application Interface

Create a simple interface where you can upload a photo and get the status.

Option 1: Web Application using Flask

Installation:

pip install flask

Sample Flask App:

from flask import Flask, request, render_template
from tensorflow.keras.preprocessing import image
import numpy as np
import sqlite3
from datetime import datetime

app = Flask(__name__)

# Load the trained model
model = tf.keras.models.load_model('plant_buddy_model.h5')

def predict_moisture(img_path):
    img = image.load_img(img_path, target_size=(224, 224))
    img_array = image.img_to_array(img)
    img_array = tf.keras.applications.mobilenet_v2.preprocess_input(img_array)
    img_array = np.expand_dims(img_array, axis=0)
    
    predictions = model.predict(img_array)
    confidence = np.max(predictions) * 100
    class_idx = np.argmax(predictions)
    class_labels = ['Thirsty!', 'Doing fine!']
    status = class_labels[class_idx]
    return status, confidence

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['file']
        file_path = f"uploads/{f.filename}"
        f.save(file_path)
        
        status, confidence = predict_moisture(file_path)
        
        # Log watering time if needed
        if status == 'Doing fine!':
            last_watered = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            # Save to database or file
            conn = sqlite3.connect('watering_log.db')
            cursor = conn.cursor()
            cursor.execute("INSERT INTO watering_log (plant, time) VALUES (?, ?)", ("Plant1", last_watered))
            conn.commit()
            conn.close()
        
        return render_template('result.html', status=status, confidence=confidence)
    return render_template('upload.html')

if __name__ == '__main__':
    app.run(debug=True)

Templates:

  • upload.html: Form to upload image.
  • result.html: Display status and confidence.

Database Setup (Optional):

import sqlite3

conn = sqlite3.connect('watering_log.db')
cursor = conn.cursor()
cursor.execute('''
    CREATE TABLE watering_log (
        id INTEGER PRIMARY KEY,
        plant TEXT,
        time TEXT
    )
''')
conn.commit()
conn.close()

Option 2: Mobile Application

For a mobile-friendly solution, consider using TensorFlow Lite and frameworks like React Native or Flutter to build cross-platform apps.

Step 8: Tracking Last Watered Time

Implement a logging mechanism to record when each plant was last watered.

Using SQLite:

  • Create a table with columns: plant_id, plant_name, last_watered_time.
  • Update the last_watered_time each time the app indicates watering is done.

Sample Code:

def log_watering(plant_name):
    conn = sqlite3.connect('watering_log.db')
    cursor = conn.cursor()
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    cursor.execute("""
        INSERT INTO watering_log (plant, time) VALUES (?, ?)
    """, (plant_name, now))
    conn.commit()
    conn.close()

Step 9: Ensuring Usability and Reliability

To make sure the application is effective and user-friendly:

  • User Interface:

    • Make the upload process simple.
    • Display clear messages and confidence levels.
  • Notifications:

    • Implement reminders based on the last watered time and plant type.
  • Continuous Learning:

    • Allow the app to learn from new images to improve accuracy over time.
  • Testing:

    • Test the app under various conditions to ensure it doesn’t get confused by pot colors, lighting, or shadows.

3. Additional Tips

A. Improving Model Accuracy

  • Balanced Dataset: Ensure equal representation of all classes.
  • Higher Resolution Images: Improve input image quality for better feature extraction.
  • Hyperparameter Tuning: Experiment with learning rates, batch sizes, and number of epochs.

B. Deployment Considerations

  • Local vs. Cloud Processing:

    • Local: Faster response; use TensorFlow Lite for mobile.
    • Cloud: Easier model updates; use APIs if processing power is a concern.
  • Privacy: Ensure images are stored securely, especially if using cloud services.

C. Enhancing Features

  • Multiple Plant Support: Allow identification and tracking of multiple plants.
  • Environmental Data: Incorporate data like humidity and temperature for more precise watering needs.
  • User Feedback: Let users correct predictions to improve the model.

4. Example Project Structure

plant_buddy/
├── app.py
├── model/
│   └── plant_buddy_model.h5
├── templates/
│   ├── upload.html
│   └── result.html
├── static/
│   └── uploads/
├── watering_log.db
└── requirements.txt

5. Conclusion

Building a "Plant Buddy" application involves collecting and labeling data, training an image classification model, and creating an interface for ease of use. By following the steps outlined above and paying attention to the checks you've mentioned, you can create a reliable tool to help you manage your houseplants better and prevent overwatering or underwatering.

Remember, the key to a successful model lies in diverse and high-quality data. Start small, iterate based on results, and gradually enhance your application with additional features to suit your needs.

Good luck with your Plant Buddy project! 🌱

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment