File size: 5,078 Bytes
2cf552b
 
 
fa75c38
 
 
 
74ed344
 
 
fa75c38
 
 
 
 
 
 
 
 
 
74ed344
fa75c38
f3bd758
 
fa75c38
74ed344
 
 
fa75c38
 
 
 
 
 
 
74ed344
 
 
fa75c38
 
 
 
 
2cf552b
fa75c38
 
 
74ed344
fa75c38
 
 
 
 
2cf552b
 
fa75c38
74ed344
 
 
 
 
 
 
 
 
 
 
 
 
 
2cf552b
 
fa75c38
74ed344
 
 
fa75c38
f3bd758
fa75c38
74ed344
 
 
 
f3bd758
 
 
 
74ed344
fa75c38
74ed344
 
 
fa75c38
 
 
f3bd758
fa75c38
 
 
74ed344
 
 
fa75c38
f3bd758
 
fa75c38
74ed344
fa75c38
 
 
 
74ed344
fa75c38
 
 
 
74ed344
fa75c38
 
74ed344
 
f3bd758
 
 
74ed344
fa75c38
 
 
 
 
 
 
 
2cf552b
74ed344
2cf552b
 
fa75c38
2cf552b
f3bd758
2cf552b
 
 
74ed344
 
2cf552b
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import cv2
import numpy as np
import pandas as pd
import gradio as gr


def detect_baseline_and_solvent_front(image):
    """
    Detect the baseline and solvent front in the TLC plate image.
    """
    try:
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        blurred = cv2.GaussianBlur(gray, (5, 5), 0)
        edges = cv2.Canny(blurred, 50, 150)

        row_sums = edges.sum(axis=1)
        baseline_y = None
        solvent_front_y = None

        for i, value in enumerate(row_sums):
            if value > 50:  # Threshold for significant edge detection
                if baseline_y is None:
                    baseline_y = i
                solvent_front_y = i

        if baseline_y is None or solvent_front_y is None:
            raise ValueError("Could not detect baseline or solvent front.")

        return baseline_y, solvent_front_y
    except Exception as e:
        print(f"Error in detecting baseline and solvent front: {e}")
        return None, None


def detect_spots(image):
    """
    Detect spots on the TLC plate.
    """
    try:
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        blurred = cv2.GaussianBlur(gray, (5, 5), 0)
        _, threshold = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY_INV)
        contours, _ = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        spots = []
        for contour in contours:
            x, y, w, h = cv2.boundingRect(contour)
            if w > 5 and h > 5:  # Filter small noise
                spots.append((x, y, w, h))
        return spots
    except Exception as e:
        print(f"Error in detect_spots: {e}")
        return []


def calculate_rf(spots, solvent_front_y, baseline_y):
    """
    Calculate the Rf values for detected spots.
    """
    try:
        rf_values = []
        for _, y, _, _ in spots:
            distance_compound = y - baseline_y
            distance_solvent = solvent_front_y - baseline_y
            rf = distance_compound / distance_solvent if distance_solvent > 0 else 0
            rf_values.append(round(rf, 2))
        return rf_values
    except Exception as e:
        print(f"Error in calculate_rf: {e}")
        return []


def annotate_image(image, spots, rf_values):
    """
    Annotate the image with detected spots and their Rf values.
    """
    try:
        annotated_image = image.copy()
        for (x, y, w, h), rf in zip(spots, rf_values):
            if x < 0 or y < 0 or x + w > image.shape[1] or y + h > image.shape[0]:
                continue  # Skip invalid spots

            # Annotate with Rf value
            cv2.putText(
                annotated_image, f"Rf={rf:.2f}", (x, y - 10),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1
            )
            # Draw rectangle around the spot
            cv2.rectangle(annotated_image, (x, y), (x + w, y + h), (0, 255, 0), 2)

        # Convert to RGB for Gradio compatibility
        annotated_image = cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB)
        return annotated_image
    except Exception as e:
        print(f"Error in annotate_image: {e}")
        return None


def process_tlc(image):
    """
    Process the TLC plate image and calculate Rf values.
    """
    try:
        if image is None or not isinstance(image, np.ndarray):
            return "Error: Invalid image uploaded. Please try again with a valid image.", None

        # Detect baseline and solvent front
        baseline_y, solvent_front_y = detect_baseline_and_solvent_front(image)
        if baseline_y is None or solvent_front_y is None:
            return "Error: Unable to detect baseline or solvent front.", None

        # Detect spots on the TLC plate
        spots = detect_spots(image)
        if not spots:
            return "Error: No spots detected on the TLC plate.", None

        # Calculate Rf values
        rf_values = calculate_rf(spots, solvent_front_y, baseline_y)

        # Annotate the image with detected spots and Rf values
        annotated_image = annotate_image(image, spots, rf_values)
        if annotated_image is None:
            return "Error: Could not annotate the TLC plate image.", None

        # Generate a CSV report of Rf values
        report_data = {"Spot": list(range(1, len(spots) + 1)), "Rf Value": rf_values}
        report = pd.DataFrame(report_data).to_csv(index=False)

        return annotated_image, report
    except Exception as e:
        print(f"Error in process_tlc: {e}")
        return "Error: Processing failed. Check inputs and try again.", None


# Define Gradio Interface
interface = gr.Interface(
    fn=process_tlc,
    inputs=gr.Image(type="numpy", label="Upload TLC Plate Image"),
    outputs=[
        gr.Image(type="numpy", label="Annotated TLC Plate"),
        gr.File(label="Download Rf Report (CSV)"),
    ],
    title="TLC Analyzer",
    description="Upload a TLC plate image to automatically calculate Rf values. "
                "The application detects the solvent front and baseline automatically.",
)

if __name__ == "__main__":
    interface.launch()