CropCNN is a deep-learning-based crop image classification system that identifies agricultural crops from images.
The project uses MobileNetV2 Transfer Learning with ImageNet pretrained weights and classifies images into five crop categories:
- π½ Maize
- πΎ Paddy
- π Sugarcane
- π» Sunflower
- πΎ Wheat
The trained model achieved 98.33% accuracy on an unseen test dataset.
The project is a complete ML application with:
- Deep Learning model (MobileNetV2)
- FastAPI backend
- REST API
- React + Vite frontend
- Image upload and prediction
- Confidence score
- Model evaluation
- Confusion matrix
- Training/validation analysis
- Project Overview
- Features
- Architecture
- Dataset
- Dataset Split
- Model
- Training Configuration
- Training Results
- Evaluation Results
- Confusion Matrix
- Backend
- API
- Frontend
- Project Structure
- Running the Backend
- Running the Frontend
- Testing the API
- Technologies Used
- Limitations
- Future Improvements
CropCNN is an image classification application designed to recognize agricultural crops from photographs.
The system follows this pipeline:
Crop Image
β
βΌ
React + Vite Frontend
β
β HTTP POST
βΌ
FastAPI Backend
β
βΌ
Image Preprocessing
β
βΌ
MobileNetV2
Transfer Learning
β
βΌ
Classification
β
βΌ
Crop + Confidence
Example:
Input:
Wheat crop image
Output:
Crop: Wheat
Confidence: 99.98%
- MobileNetV2-based image classification
- ImageNet pretrained weights
- Transfer learning
- Five crop classes
- Data augmentation
- Training/validation/test split
- Early stopping
- Best-model checkpointing
- FastAPI REST API
- Image upload endpoint
- Image validation
- Model loaded once during application startup
- Prediction endpoint
- Health-check endpoint
- JSON prediction response
- CORS support for the local Vite dev server
The React + Vite frontend provides:
- Image upload and drag-and-drop
- Image preview
- Client-side image validation (type and 10 MB size limit)
- Prediction button with loading state
- Crop prediction with confidence percentage
- Backend health status indicator
- Error handling (invalid file, oversized file, backend offline)
- Responsive interface
The project uses MobileNetV2:
Pretrained weights: ImageNet
Input size: 224 Γ 224 Γ 3
Transfer learning: Yes
Base model: Frozen
The pretrained MobileNetV2 feature extractor is used to learn useful visual features.
A custom classification head was added:
MobileNetV2
β
βΌ
Global Average Pooling
β
βΌ
Dropout (0.2)
β
βΌ
Dense (128, ReLU)
β
βΌ
Dropout (0.2)
β
βΌ
Dense (5, Softmax)
β
βΌ
Crop Class
The five output classes are:
Maize
Paddy
Sugarcane
Sunflower
Wheat
A combined agricultural image dataset was prepared from crop image sources.
The final dataset contains:
Total images: 800
Number of classes: 5
Images per class: 160
Final balanced dataset:
| Crop | Images |
|---|---|
| Maize | 160 |
| Paddy | 160 |
| Sugarcane | 160 |
| Sunflower | 160 |
| Wheat | 160 |
| Total | 800 |
The dataset was intentionally balanced to avoid giving the model a class-frequency advantage.
The dataset was split into:
| Dataset | Images | Percentage |
|---|---|---|
| Training | 560 | 70% |
| Validation | 120 | 15% |
| Testing | 120 | 15% |
| Total | 800 | 100% |
Each class contains:
Training: 112 images
Validation: 24 images
Testing: 24 images
Therefore:
5 Γ 112 = 560 training images
5 Γ 24 = 120 validation images
5 Γ 24 = 120 test images
Images are resized to 224 Γ 224, the input resolution used by MobileNetV2.
MobileNetV2 preprocessing (preprocess_input) is applied before prediction.
The training dataset uses augmentation:
Random Horizontal Flip
Random Rotation (0.1)
Random Zoom (0.1)
Augmentation is applied only to the training data. Validation and test images are not augmented.
| Parameter | Value |
|---|---|
| Model | MobileNetV2 |
| Pretrained weights | ImageNet |
| Input size | 224 Γ 224 |
| Batch size | 32 |
| Epochs | 20 |
| Optimizer | Adam |
| Learning rate | 0.001 |
| Loss | Sparse Categorical Crossentropy |
| Metric | Accuracy |
| Classes | 5 |
The pretrained MobileNetV2 layers were frozen during training. Only the custom classification head was trained.
The training script is at backend/training/train_model.py.
Monitors: val_loss
Patience: 5
Restore best weights: True
This prevents unnecessary training and reduces overfitting.
The best model is selected based on validation loss and saved to:
backend/model/best_mobilenetv2.keras
During training, both training and validation accuracy improved significantly.
At the final epoch the model reached approximately:
Training Accuracy: 96.43%
Validation Accuracy: 94.17%
The best validation accuracy observed during training was 95.83%, with a validation loss of 0.1200 at Epoch 20.
The training and validation accuracy curves stay relatively close, and both loss curves decrease throughout training. Mild fluctuations exist between training and validation performance, but there is no severe overfitting.
πΈ Suggested screenshots: place
training-accuracy.pngandtraining-loss.pngindocs/images/and link them here.
The final evaluation was performed on the completely unseen test dataset:
Test images: 120
Final result:
Test Loss: 0.0578
Test Accuracy: 98.33%
The model correctly classified 118 / 120 images and incorrectly classified 2 / 120 images.
| Class | Precision | Recall | F1-Score | Support |
|---|---|---|---|---|
| Maize | 95.83% | 95.83% | 95.83% | 24 |
| Paddy | 100.00% | 100.00% | 100.00% | 24 |
| Sugarcane | 100.00% | 95.83% | 97.87% | 24 |
| Sunflower | 100.00% | 100.00% | 100.00% | 24 |
| Wheat | 96.00% | 100.00% | 97.96% | 24 |
| Macro Average | 98.37% | 98.33% | 98.33% | 120 |
| Weighted Average | 98.37% | 98.33% | 98.33% | 120 |
Predicted
Maize Paddy Sugarcane Sunflower Wheat
Actual
Maize 23 0 0 0 1
Paddy 0 24 0 0 0
Sugarcane 1 0 23 0 0
Sunflower 0 0 0 24 0
Wheat 0 0 0 0 24
πΈ Suggested screenshot: place
confusion-matrix.pngindocs/images/and link it here.
Only two incorrect predictions occurred in the test dataset:
Error 1: Actual: Maize β Predicted: Wheat
Error 2: Actual: Sugarcane β Predicted: Maize
The main class confusion was therefore Maize β Wheat and Sugarcane β Maize. Paddy, Sunflower, and Wheat had no false-negative predictions in the test set.
The backend is implemented using FastAPI and lives in backend/app/main.py.
Backend responsibilities:
- Receive uploaded image
- Validate the file is an image
- Read and convert the image to RGB
- Resize to 224 Γ 224
- Apply MobileNetV2 preprocessing
- Run model inference
- Select the highest-probability class
- Return crop and confidence
The trained model is loaded once when the FastAPI application starts, avoiding reloading it for every request.
Backend dev server: http://127.0.0.1:8000
GET /{
"message": "Crop Classification API is running"
}GET /health{
"status": "healthy",
"model": "MobileNetV2"
}POST /predictAccepts multipart/form-data with the uploaded image field file.
{
"crop": "Wheat",
"confidence": 0.9998,
"confidence_percent": 99.98
}Open http://127.0.0.1:8000/docs for the auto-generated Swagger UI.
The frontend is implemented with React 19 + Vite (JavaScript + plain CSS) in frontend/.
Frontend source layout:
frontend/src/
βββ App.jsx # main app state and flow
βββ main.jsx # React entry point
βββ index.css # global styles
βββ components/
β βββ Header.jsx # page header
β βββ BackendStatus.jsx # live backend health indicator
β βββ ImageUploader.jsx # upload / drag-and-drop
β βββ ImagePreview.jsx # selected image preview
β βββ LoadingState.jsx # loading spinner
β βββ PredictionResult.jsx # crop + confidence result card
β βββ About.jsx # about section
βββ services/
β βββ api.js # fetch calls to the backend
βββ utils/
βββ imageUtils.js # client-side image validation
Frontend workflow:
User
β
βΌ
Select Image
β
βΌ
Image Preview
β
βΌ
Click "Classify Crop"
β
βΌ
POST /predict
β
βΌ
FastAPI
β
βΌ
MobileNetV2
β
βΌ
Prediction JSON
β
βΌ
Result Card (Crop + Confidence)
The frontend provides image validation, loading state, backend health status, error handling, and a responsive layout.
βββββββββββββββββββββββ
β USER β
β Crop Image β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β React + Vite β
β Frontend β
β http://localhost:5173
ββββββββββββ¬βββββββββββ
β
HTTP REST API
β
βΌ
βββββββββββββββββββββββ
β FastAPI β
β Backend β
β http://127.0.0.1:8000
β β
β GET / β
β GET /health β
β POST /predict β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Preprocessing β
β 224 Γ 224 + MobileNetV2 preprocessing
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β MobileNetV2 β
β ImageNet pretrained β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Prediction β
β Crop + Confidence β
βββββββββββββββββββββββ
CropCNN/
β
βββ backend/
β βββ app/
β β βββ main.py # FastAPI application
β βββ model/ # trained model (gitignored)
β β βββ best_mobilenetv2.keras
β βββ training/
β β βββ train_model.py # MobileNetV2 training script
β βββ requirements.txt
β
βββ frontend/
β βββ src/
β β βββ components/
β β βββ services/
β β βββ utils/
β β βββ App.jsx
β β βββ main.jsx
β β βββ index.css
β βββ .env.example
β βββ package.json
β βββ README.md
β
βββ docs/
β βββ images/ # screenshots (training curves, confusion matrix)
β
βββ .gitignore
βββ README.md
git clone https://github.com/subash3650/CropCNN.git
cd CropCNNWindows:
python -m venv .venv
.venv\Scripts\activatepip install -r backend\requirements.txtFrom the repository root:
uvicorn backend.app.main:app --reloadThe backend runs at http://127.0.0.1:8000.
Swagger UI is available at http://127.0.0.1:8000/docs.
Navigate to the frontend:
cd frontendInstall dependencies:
npm installCreate .env from the example:
cp .env.example .envVITE_API_URL=http://127.0.0.1:8000Start the development server:
npm run devThe frontend is available at http://localhost:5173.
Other scripts:
npm run buildβ production build todist/npm run lintβ run ESLintnpm run previewβ preview the production build
With the backend running, send a test request with curl:
curl -X POST http://127.0.0.1:8000/predict -F "[email protected]"Expected response:
{
"crop": "Wheat",
"confidence": 0.9998,
"confidence_percent": 99.98
}Or use the Swagger UI at http://127.0.0.1:8000/docs to upload an image from the browser.
- Python
- TensorFlow
- Keras
- MobileNetV2
- NumPy
- Python
- FastAPI
- Uvicorn
- Pillow
- TensorFlow
- React
- Vite
- JavaScript
- CSS
- Google Colab
- Git
- GitHub
- VS Code
Although the model achieved 98.33% accuracy on the test dataset, it will not necessarily achieve 98.33% accuracy on every real-world agricultural image.
The dataset is relatively small (800 total images) and contains only five crop categories.
Real-world images can have:
- Different lighting and camera qualities
- Different backgrounds and viewpoints
- Different crop growth stages
- Occlusion and multiple plants in one image
- Disease or damage
- Different geographical conditions
Therefore the test accuracy should be interpreted as performance on this prepared test dataset.
- Larger dataset β collect more images per crop category.
- More crop classes β expand beyond Maize, Paddy, Sugarcane, Sunflower, Wheat.
- Fine-tuning β unfreeze selected MobileNetV2 layers and train with a low learning rate.
- Real-world data β collect images from real farms and varied conditions.
- Mobile / edge deployment β convert the model to TensorFlow Lite or ONNX.
- Cloud deployment β deploy the FastAPI backend and host the frontend separately.
- Agricultural decision support β combine classification with disease detection, crop health, soil/weather information, and irrigation recommendations.
Subash
GitHub: https://github.com/subash3650
Project: https://github.com/subash3650/CropCNN
Add an appropriate open-source license to the repository if required.
CropCNN is an end-to-end machine learning application for agricultural crop classification:
Dataset
β
Preprocessing
β
Data Augmentation
β
MobileNetV2 Transfer Learning
β
Model Training
β
Evaluation
β
FastAPI REST API
β
React + Vite Frontend
β
Crop Prediction
Final test performance: 98.33% accuracy on 120 unseen test images, classifying Maize, Paddy, Sugarcane, Sunflower, and Wheat.