|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import cv2 |
|
|
import numpy as np |
|
|
from PIL import Image |
|
|
import torch |
|
|
from torchvision import models, transforms |
|
|
from ultralytics import YOLO |
|
|
import gradio as gr |
|
|
import torch.nn as nn |
|
|
import os |
|
|
|
|
|
|
|
|
|
|
|
USAGE_GUIDELINES = """ |
|
|
## 1. Quick Start Guide: Run Instructions |
|
|
|
|
|
**English:** |
|
|
1. **Upload:** Click the 'Upload Rice Image' box and select your image (JPG or PNG). |
|
|
2. **Run:** Click the **"Run Analysis"** button. |
|
|
3. **Review:** The output image will show each detected rice grain marked with its predicted class label. |
|
|
|
|
|
**Urdu (اردو):** |
|
|
## 1. فوری استعمال کی ہدایات: تجزیہ شروع کریں |
|
|
1. **تصویر اپ لوڈ کریں:** 'چاول کی تصویر اپ لوڈ کریں' کے باکس پر کلک کریں اور اپنی تصویر (JPG یا PNG) منتخب کریں۔ |
|
|
2. **چلائیں:** **"تجزیہ شروع کریں"** بٹن پر کلک کریں۔ |
|
|
3. **نتائج دیکھیں:** آؤٹ پٹ تصویر ہر شناخت شدہ چاول کے دانے کو اس کی پیش گوئی کردہ قسم کے لیبل کے ساتھ دکھائے گی۔ |
|
|
""" |
|
|
|
|
|
INPUT_EXPLANATION = """ |
|
|
## 2. Expected Inputs / متوقع ان پٹ |
|
|
|
|
|
| Input Field (ان پٹ فیلڈ) | Purpose (مقصد) | Requirement (ضرورت) | |
|
|
| :--- | :--- | :--- | |
|
|
| **Upload Image** / تصویر اپ لوڈ کریں | The image containing the rice grains for analysis. | Must be a single image file (JPG, PNG). The input should preferably contain clear, separated rice grains. | |
|
|
|
|
|
**Important Note (اہم نوٹ):** For the best detection and classification accuracy, ensure the rice grains are scattered (not heavily overlapping) and the background is simple. |
|
|
""" |
|
|
|
|
|
OUTPUT_EXPLANATION = """ |
|
|
## 3. Expected Outputs (Detection and Classification) / متوقع آؤٹ پٹ |
|
|
|
|
|
The output is the original image overlayed with results from the two-stage AI model: |
|
|
|
|
|
* **Bounding Boxes:** Each individual rice grain detected by the YOLO model is enclosed in a **Green rectangle**. |
|
|
* **Labels:** Above each rectangle, the predicted class label is displayed: |
|
|
* **c9** (A specific rice variety) |
|
|
* **kant** (Another specific rice variety) |
|
|
* **superf** (A third specific rice variety) |
|
|
|
|
|
**Urdu (اردو):** |
|
|
آؤٹ پٹ اصل تصویر ہوگی جس پر دو مراحل پر مشتمل AI ماڈل کے نتائج لگائے گئے ہیں: |
|
|
* **نشان زد ڈبے:** YOLO ماڈل سے تلاش کیے گئے ہر چاول کے دانے کے گرد **سبز رنگ کا مستطیل** لگایا جائے گا۔ |
|
|
* **لیبلز:** ہر مستطیل کے اوپر اس کی پیش گوئی کردہ قسم کا لیبل درج ہوگا: c9، kant، یا superf۔ |
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
yolo_model = YOLO('best.pt') |
|
|
resnet = models.resnet50(weights=None) |
|
|
resnet.fc = nn.Linear(resnet.fc.in_features, 3) |
|
|
resnet.load_state_dict(torch.load('rice_resnet_model.pth', map_location=device)) |
|
|
resnet = resnet.to(device) |
|
|
resnet.eval() |
|
|
except Exception as e: |
|
|
print(f"Error loading models: {e}. Ensure 'best.pt' and 'rice_resnet_model.pth' are present.") |
|
|
yolo_model = None |
|
|
resnet = None |
|
|
|
|
|
|
|
|
class_labels = ["c9", "kant", "superf"] |
|
|
|
|
|
|
|
|
transform = transforms.Compose([ |
|
|
transforms.Resize((224, 224)), |
|
|
transforms.ToTensor(), |
|
|
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) |
|
|
]) |
|
|
|
|
|
def classify_crop(crop_img): |
|
|
"""Classify a single rice grain crop""" |
|
|
if resnet is None: |
|
|
return "Error" |
|
|
image = transform(crop_img).unsqueeze(0).to(device) |
|
|
with torch.no_grad(): |
|
|
output = resnet(image) |
|
|
_, predicted = torch.max(output, 1) |
|
|
return class_labels[predicted.item()] |
|
|
|
|
|
def detect_and_classify(input_image): |
|
|
"""Process the image and classify each grain""" |
|
|
if yolo_model is None or resnet is None: |
|
|
raise gr.Error("Models failed to load. Cannot proceed with analysis.") |
|
|
|
|
|
if input_image is None: |
|
|
raise gr.Error("Please upload an image or select an example.") |
|
|
|
|
|
image = np.array(input_image) |
|
|
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) |
|
|
|
|
|
|
|
|
results = yolo_model(image, verbose=False)[0] |
|
|
boxes = results.boxes.xyxy.cpu().numpy() |
|
|
|
|
|
if len(boxes) == 0: |
|
|
gr.Warning("No rice grains detected in the image.") |
|
|
return Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) |
|
|
|
|
|
|
|
|
for box in boxes: |
|
|
x1, y1, x2, y2 = map(int, box[:4]) |
|
|
crop = image[y1:y2, x1:x2] |
|
|
|
|
|
|
|
|
if crop.shape[0] > 0 and crop.shape[1] > 0: |
|
|
crop_pil = Image.fromarray(cv2.cvtColor(crop, cv2.COLOR_BGR2RGB)) |
|
|
predicted_label = classify_crop(crop_pil) |
|
|
|
|
|
|
|
|
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) |
|
|
cv2.putText(image, |
|
|
predicted_label, |
|
|
(x1, y1-10), |
|
|
cv2.FONT_HERSHEY_SIMPLEX, |
|
|
0.9, |
|
|
(36, 255, 12), |
|
|
2) |
|
|
|
|
|
return Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(title="Rice Variety Classification") as demo: |
|
|
|
|
|
gr.Markdown( |
|
|
""" |
|
|
# Rice Variety Classification System / چاول کی اقسام کی شناخت کا نظام |
|
|
Upload an image containing rice grains. The system will detect and classify each grain using a two-stage AI pipeline (YOLO for detection, ResNet for classification). |
|
|
""" |
|
|
) |
|
|
|
|
|
|
|
|
with gr.Accordion(" Tips & Guidelines (ہدایات)", open=False): |
|
|
gr.Markdown(USAGE_GUIDELINES) |
|
|
gr.Markdown("---") |
|
|
gr.Markdown(INPUT_EXPLANATION) |
|
|
gr.Markdown("---") |
|
|
gr.Markdown(OUTPUT_EXPLANATION) |
|
|
|
|
|
gr.Markdown("---") |
|
|
|
|
|
|
|
|
gr.Markdown("## Start Analysis / تجزیہ شروع کریں") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("## Step 1: Upload an Image of Rice / چاول کی تصویر اپ لوڈ کریں") |
|
|
image_input = gr.Image(type="pil") |
|
|
gr.Markdown("## Step 2: Click Run Analysis /تجزیہ شروع کریں ") |
|
|
submit_btn = gr.Button("Run Analysis / تجزیہ شروع کریں", variant="primary") |
|
|
gr.Markdown("## Outputs / نتائج ") |
|
|
output_image = gr.Image(scale=2, interactive=True) |
|
|
|
|
|
submit_btn.click( |
|
|
fn=detect_and_classify, |
|
|
inputs=image_input, |
|
|
outputs=output_image |
|
|
) |
|
|
|
|
|
gr.Markdown("---") |
|
|
|
|
|
|
|
|
gr.Markdown("## Example Images / مثال تصاویر") |
|
|
|
|
|
gr.Examples( |
|
|
examples=[ |
|
|
"samples/rice1.jpg", |
|
|
"samples/rice2.jpg", |
|
|
"samples/rice3.jpg", |
|
|
"samples/rice4.jpg", |
|
|
"samples/rice5.jpg", |
|
|
"samples/rice6.jpg" |
|
|
], |
|
|
inputs=image_input, |
|
|
outputs=output_image, |
|
|
fn=detect_and_classify, |
|
|
cache_examples=True, |
|
|
label="Click to load and run a sample image / نمونہ تصویر لوڈ اور رن کرنے کے لیے کلک کریں" |
|
|
) |
|
|
|
|
|
demo.queue() |
|
|
demo.launch() |
|
|
|