RioJune commited on
Commit
a40ac25
·
1 Parent(s): fba28b5
app.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from PIL import Image
3
+ import torch
4
+ from transformers import AutoModelForCausalLM, AutoProcessor
5
+ import numpy as np
6
+ import supervision as sv
7
+ import albumentations as A
8
+ import cv2
9
+ from transformers import AutoConfig
10
+ import yaml
11
+
12
+ # Set Streamlit page configuration for a wide layout
13
+ st.set_page_config(layout="wide")
14
+
15
+ # Custom CSS for better layout and mobile responsiveness
16
+ st.markdown("""
17
+ <style>
18
+ .main {
19
+ max-width: 1200px; /* Max width for content */
20
+ margin: 0 auto;
21
+ }
22
+ .block-container {
23
+ padding-top: 2rem;
24
+ padding-bottom: 2rem;
25
+ padding-left: 3rem;
26
+ padding-right: 3rem;
27
+ }
28
+ .title {
29
+ font-size: 2.5rem;
30
+ text-align: center;
31
+ color: #FF6347;
32
+ }
33
+ .subheader {
34
+ font-size: 1.5rem;
35
+ margin-bottom: 20px;
36
+ }
37
+ .btn {
38
+ font-size: 1.1rem;
39
+ padding: 10px 20px;
40
+ background-color: #FF6347;
41
+ color: white;
42
+ border-radius: 5px;
43
+ border: none;
44
+ cursor: pointer;
45
+ }
46
+ .btn:hover {
47
+ background-color: #FF4500;
48
+ }
49
+ .column-spacing {
50
+ display: flex;
51
+ justify-content: space-between;
52
+ }
53
+ .col-half {
54
+ width: 48%;
55
+ }
56
+ .col-full {
57
+ width: 100%;
58
+ }
59
+ .instructions {
60
+ padding: 20px;
61
+ background-color: #f9f9f9;
62
+ border-radius: 8px;
63
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
64
+ }
65
+ </style>
66
+ """, unsafe_allow_html=True)
67
+
68
+ # Load Model and Processor
69
+ @st.cache_resource
70
+ def load_model():
71
+ REVISION = 'refs/pr/6'
72
+ MODEL_NAME = "RioJune/AG-KD"
73
+ # MODEL_NAME = '/u/home/lj0/Checkpoints/AD-KD-MICCAI25'
74
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
75
+
76
+ config_model = AutoConfig.from_pretrained ("microsoft/Florence-2-base-ft", trust_remote_code=True)
77
+ config_model.vision_config.model_type = "davit"
78
+
79
+ model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, trust_remote_code=True, config=config_model).to(DEVICE)
80
+
81
+ BASE_PROCESSOR = "microsoft/Florence-2-base-ft"
82
+ processor = AutoProcessor.from_pretrained(BASE_PROCESSOR, trust_remote_code=True)
83
+ processor.image_processor.size = 512
84
+ processor.image_processor.crop_size = 512
85
+
86
+ return model, processor, DEVICE
87
+
88
+ model, processor, DEVICE = load_model()
89
+
90
+ # Load Definitions
91
+ @st.cache_resource
92
+ def load_definitions():
93
+ vindr_path = 'configs/vindr_definition.yaml'
94
+ padchest_path = 'configs/padchest_definition.yaml'
95
+ prompt_path = 'examples/prompt.yaml'
96
+
97
+ with open(vindr_path, 'r') as file:
98
+ vindr_definitions = yaml.safe_load(file)
99
+ with open(padchest_path, 'r') as file:
100
+ padchest_definitions = yaml.safe_load(file)
101
+ with open(prompt_path, 'r') as file:
102
+ prompt_definitions = yaml.safe_load(file)
103
+
104
+ return vindr_definitions, padchest_definitions, prompt_definitions
105
+
106
+ vindr_definitions, padchest_definitions, prompt_definitions = load_definitions()
107
+
108
+ dataset_options = {"Vindr": vindr_definitions, "PadChest": padchest_definitions}
109
+
110
+ def load_example_images():
111
+ return list(prompt_definitions.keys())
112
+
113
+ example_images = load_example_images()
114
+
115
+ def apply_transform(image, size_mode=512):
116
+ pad_resize_transform = A.Compose([
117
+ A.LongestMaxSize(max_size=size_mode, interpolation=cv2.INTER_AREA),
118
+ A.PadIfNeeded(min_height=size_mode, min_width=size_mode, border_mode=cv2.BORDER_CONSTANT, value=(0, 0, 0)),
119
+ A.Resize(height=512, width=512, interpolation=cv2.INTER_AREA),
120
+ ])
121
+ image_np = np.array(image)
122
+ transformed = pad_resize_transform(image=image_np)
123
+ return transformed["image"]
124
+
125
+ # Streamlit UI with Colorful Title and Emojis
126
+ st.markdown("<h1 class='title'>🩺 Enhancing Abnormality Grounding for Vision Language Models with Knowledge Descriptions 🚀</h1>", unsafe_allow_html=True)
127
+ st.markdown(
128
+ "<p style='text-align: center; font-size: 18px;'>Welcome to a simple demo of our work! 🎉 Choose an example or upload your own image to get started! 👇</p>",
129
+ unsafe_allow_html=True
130
+ )
131
+
132
+ # Display Example Images First
133
+ st.subheader("🌄 Example Images")
134
+ selected_example = st.selectbox("Choose an example", example_images)
135
+ image = Image.open(selected_example).convert("RGB")
136
+ example_diseases = prompt_definitions.get(selected_example, [])
137
+ st.write("**Associated Diseases:**", ", ".join(example_diseases))
138
+
139
+ # Layout for Original Image and Instructions
140
+ col1, col2 = st.columns([1, 2])
141
+
142
+ # Left column for original image
143
+ with col1:
144
+ st.image(image, caption=f"Original Example Image: {selected_example}", width=400)
145
+
146
+ # Right column for Instructions and Run Inference Button
147
+ with col2:
148
+ st.subheader("⚙️ Instructions to Get Started:")
149
+ st.write("""
150
+ - **Run Inference**: Click the "Run Inference on Example" button to process the image and display the results.
151
+ - **Choose an Example**: 🌄 Select an example image from the dataset to view its associated diseases.
152
+ - **Upload Your Own Image**: 📤 Upload an image of your choice to analyze it for diseases.
153
+ - **Select Dataset**: 📚 Choose between available datasets (Vindr or PadChest) for disease information.
154
+ - **Select Disease**: 🦠 Pick the disease to be analyzed from the list of diseases in the selected dataset.
155
+ """)
156
+
157
+ st.subheader("⚠️ Warning:")
158
+ st.write("""
159
+ - **🚫 Please avoid uploading non-frontal chest X-ray images.** Our model has been specifically trained on **frontal chest X-ray images** only.
160
+ - This demo is intended for **🔬 research purposes only** and should **❌ not be used for medical diagnoses**.
161
+ - The model’s responses may contain **<span style='color:#dc3545; font-weight:bold;'>🤖 hallucinations or incorrect information</span>**.
162
+ - Always consult a **<span style='color:#dc3545; font-weight:bold;'>👨‍⚕️ medical professional</span>** for accurate diagnosis and advice.
163
+ """, unsafe_allow_html=True)
164
+
165
+
166
+ st.markdown("</div>", unsafe_allow_html=True)
167
+
168
+ # Run Inference Button
169
+ if st.button("Run Inference on Example", key="example"):
170
+ if image is None:
171
+ st.error("❌ Please select an example image first.")
172
+ else:
173
+ # Use the selected example's disease and definition for inference
174
+ disease_choice = example_diseases[0] if example_diseases else ""
175
+ definition = vindr_definitions.get(disease_choice, padchest_definitions.get(disease_choice, ""))
176
+
177
+ # Generate the prompt for the model
178
+ det_obj = f"{disease_choice} means {definition}."
179
+ st.write(f"**Definition:** {definition}")
180
+ prompt = f"Locate the phrases in the caption: {det_obj}."
181
+ prompt = f"<CAPTION_TO_PHRASE_GROUNDING>{prompt}"
182
+
183
+ # Prepare the image and input
184
+ np_image = np.array(image)
185
+ inputs = processor(text=[prompt], images=[np_image], return_tensors="pt", padding=True).to(DEVICE)
186
+
187
+ with st.spinner("Processing... ⏳"):
188
+ outputs = model.generate(
189
+ input_ids=inputs["input_ids"],
190
+ pixel_values=inputs["pixel_values"],
191
+ max_new_tokens=1024,
192
+ num_beams=3,
193
+ output_scores=True, # Make sure we get the scores/logits
194
+ return_dict_in_generate=True # Ensures you get both sequences and scores in the output
195
+ )
196
+
197
+
198
+ # Ensure transition_scores is properly extracted
199
+ transition_scores = model.compute_transition_scores(
200
+ outputs.sequences, outputs.scores, outputs.beam_indices, normalize_logits=False
201
+ )
202
+
203
+ # Get the generated token IDs (ignoring the input tokens part)
204
+ generated_ids = outputs.sequences
205
+ generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
206
+
207
+ # Get input length
208
+ input_length = inputs.input_ids.shape[1]
209
+ generated_tokens = outputs.sequences
210
+
211
+ # Calculate output length (number of generated tokens)
212
+ output_length = np.sum(transition_scores.cpu().numpy() < 0, axis=1)
213
+
214
+ # Get length penalty
215
+ length_penalty = model.generation_config.length_penalty
216
+
217
+ # Calculate total score for the generated sentence
218
+ reconstructed_scores = transition_scores.cpu().sum(axis=1) / (output_length**length_penalty)
219
+
220
+ # Convert log-probability to probability (0-1 range)
221
+ probabilities = np.exp(reconstructed_scores.cpu().numpy())
222
+
223
+ # Streamlit UI to display the result
224
+ st.markdown(f"**🎯 Probability of the Results:** <span style='color:#28a745; font-size:24px; font-weight:bold;'>{probabilities[0] * 100:.2f}%</span>", unsafe_allow_html=True)
225
+
226
+
227
+ predictions = processor.post_process_generation(generated_text, task="<CAPTION_TO_PHRASE_GROUNDING>", image_size=np_image.shape[:2])
228
+
229
+ detection = sv.Detections.from_lmm(sv.LMM.FLORENCE_2, predictions, resolution_wh=np_image.shape[:2])
230
+
231
+ # Annotate the image with bounding boxes and labels
232
+ bounding_box_annotator = sv.BoundingBoxAnnotator(color_lookup=sv.ColorLookup.INDEX)
233
+ label_annotator = sv.LabelAnnotator(color_lookup=sv.ColorLookup.INDEX)
234
+ image_with_predictions = bounding_box_annotator.annotate(np_image.copy(), detection)
235
+ image_with_predictions = label_annotator.annotate(image_with_predictions, detection)
236
+ annotated_image = Image.fromarray(image_with_predictions.astype(np.uint8))
237
+
238
+ # Display the original and result images side by side
239
+ col1, col2 = st.columns([1, 1])
240
+
241
+ with col1:
242
+ st.image(image, caption=f"Original Image: {selected_example}", width=400)
243
+
244
+ with col2:
245
+ st.image(annotated_image, caption="Inference Results 🖼️", width=400)
246
+
247
+ # Display the generated text
248
+ st.write("**Generated Text:**", generated_text)
249
+
250
+ # Upload Image section
251
+ st.subheader("📤 Upload Your Own Image")
252
+
253
+ col1, col2 = st.columns([1, 1])
254
+ with col1:
255
+ dataset_choice = st.selectbox("Select Dataset 📚", options=list(dataset_options.keys()))
256
+ disease_options = list(dataset_options[dataset_choice].keys())
257
+ with col2:
258
+ disease_choice = st.selectbox("Select Disease 🦠", options=disease_options)
259
+
260
+ uploaded_file = st.file_uploader("Upload an Image", type=["png", "jpg", "jpeg"])
261
+
262
+
263
+ col1, col2 = st.columns([1, 2])
264
+
265
+ with col1:
266
+ # Handle file upload
267
+ if uploaded_file:
268
+ image = Image.open(uploaded_file).convert("RGB")
269
+ image = apply_transform(image) # Ensure the uploaded image is transformed correctly
270
+ st.image(image, caption="Uploaded Image", width=400)
271
+
272
+ # Let user select dataset and disease dynamically
273
+ disease_choice = disease_choice if disease_choice else example_diseases[0]
274
+
275
+ # Get Definition Priority: Dataset -> User Input
276
+ definition = vindr_definitions.get(disease_choice, padchest_definitions.get(disease_choice, ""))
277
+ if not definition:
278
+ definition = st.text_input("Enter Definition Manually 📝", value="")
279
+
280
+ with col2:
281
+ # Instructions and warnings
282
+ st.subheader("⚙️ Instructions to Get Started:")
283
+ st.write("""
284
+ - **Run Inference**: Click the "Run Inference on Example" button to process the image and display the results.
285
+ - **Choose an Example**: 🌄 Select an example image from the dataset to view its associated diseases.
286
+ - **Upload Your Own Image**: 📤 Upload an image of your choice to analyze it for diseases.
287
+ - **Select Dataset**: 📚 Choose between available datasets (Vindr or PadChest) for disease information.
288
+ - **Select Disease**: 🦠 Pick the disease to be analyzed from the list of diseases in the selected dataset.
289
+ """)
290
+
291
+ st.subheader("⚠️ Warning:")
292
+ st.write("""
293
+ - **🚫 Please avoid uploading non-frontal chest X-ray images.** Our model has been specifically trained on **frontal chest X-ray images** only.
294
+ - This demo is intended for **🔬 research purposes only** and should **❌ not be used for medical diagnoses**.
295
+ - The model’s responses may contain **<span style='color:#dc3545; font-weight:bold;'>🤖 hallucinations or incorrect information</span>**.
296
+ - Always consult a **<span style='color:#dc3545; font-weight:bold;'>👨‍⚕️ medical professional</span>** for accurate diagnosis and advice.
297
+ """, unsafe_allow_html=True)
298
+
299
+ # Run inference after upload
300
+ if st.button("Run Inference 🏃‍♂️"):
301
+ if image is None:
302
+ st.error("❌ Please upload an image or select an example.")
303
+ else:
304
+ det_obj = f"{disease_choice} means {definition}."
305
+ st.write(f"**Definition:** {definition}")
306
+
307
+ # Construct Prompt with Disease Definition
308
+ prompt = f"Locate the phrases in the caption: {det_obj}."
309
+ prompt = f"<CAPTION_TO_PHRASE_GROUNDING>{prompt}"
310
+
311
+ np_image = np.array(image)
312
+ inputs = processor(text=[prompt], images=[np_image], return_tensors="pt", padding=True).to(DEVICE)
313
+
314
+ with st.spinner("Processing... ⏳"):
315
+ # generated_ids = model.generate(input_ids=inputs["input_ids"], pixel_values=inputs["pixel_values"], max_new_tokens=1024, num_beams=3)
316
+ # generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
317
+
318
+ outputs = model.generate(
319
+ input_ids=inputs["input_ids"],
320
+ pixel_values=inputs["pixel_values"],
321
+ max_new_tokens=1024,
322
+ num_beams=3,
323
+ output_scores=True, # Make sure we get the scores/logits
324
+ return_dict_in_generate=True # Ensures you get both sequences and scores in the output
325
+ )
326
+
327
+ transition_scores = model.compute_transition_scores(
328
+ outputs.sequences, outputs.scores, outputs.beam_indices, normalize_logits=False
329
+ )
330
+
331
+ # Get the generated token IDs (ignoring the input tokens part)
332
+ generated_ids = outputs.sequences
333
+ generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
334
+
335
+ # Get input length
336
+ input_length = inputs.input_ids.shape[1]
337
+
338
+ # Extract generated tokens (ignoring the input tokens)
339
+ # generated_tokens = outputs.sequences[:, input_length:]
340
+ generated_tokens = outputs.sequences
341
+
342
+ # Calculate output length (number of generated tokens)
343
+ output_length = np.sum(transition_scores.cpu().numpy() < 0, axis=1)
344
+
345
+ # Get length penalty
346
+ length_penalty = model.generation_config.length_penalty
347
+
348
+ # Calculate total score for the generated sentence
349
+ reconstructed_scores = transition_scores.cpu().sum(axis=1) / (output_length**length_penalty)
350
+
351
+ # Convert log-probability to probability (0-1 range)
352
+ probabilities = np.exp(reconstructed_scores.cpu().numpy())
353
+
354
+ # Streamlit UI to display the result
355
+
356
+ # st.write(f"**Probability of the Results (0-1):** {probabilities[0]:.4f}")
357
+ st.markdown(f"**🎯 Probability of the Results:** <span style='color:green; font-size:24px; font-weight:bold;'>{probabilities[0] * 100:.2f}%</span>", unsafe_allow_html=True)
358
+
359
+
360
+
361
+ predictions = processor.post_process_generation(generated_text, task="<CAPTION_TO_PHRASE_GROUNDING>", image_size=np_image.shape[:2])
362
+
363
+ detection = sv.Detections.from_lmm(sv.LMM.FLORENCE_2, predictions, resolution_wh=np_image.shape[:2])
364
+
365
+ bounding_box_annotator = sv.BoundingBoxAnnotator(color_lookup=sv.ColorLookup.INDEX)
366
+ label_annotator = sv.LabelAnnotator(color_lookup=sv.ColorLookup.INDEX)
367
+ image_with_predictions = bounding_box_annotator.annotate(np_image.copy(), detection)
368
+ image_with_predictions = label_annotator.annotate(image_with_predictions, detection)
369
+ annotated_image = Image.fromarray(image_with_predictions.astype(np.uint8))
370
+
371
+ # Create two columns to display the original and the results side by side
372
+ col1, col2 = st.columns([1, 1])
373
+
374
+ # Left column for original image
375
+ with col1:
376
+ st.image(image, caption="Uploaded Image", width=400)
377
+
378
+ # Right column for result image
379
+ with col2:
380
+ st.image(annotated_image, caption="Inference Results 🖼️", width=400)
381
+
382
+ # Display the generated text
383
+ st.write("**Generated Text:**", generated_text)
384
+
385
+
386
+
configs/experiment.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Experiment 1 Configuration
2
+
3
+ model:
4
+ model_type: "microsoft/Florence-2-base-ft"
5
+ lora_config: "configs/lora_config.yaml"
6
+ init_checkpoint: "checkpoints/mimic_model_init.pt"
7
+ processor:
8
+ image_size: 512
9
+ crop_size: 512
10
+ peft:
11
+ use_peft: False
12
+ lora_checkpoint: None
13
+ finetune: true # true
14
+
15
+ trainer:
16
+ checkpoint_dir: "../outputs"
17
+ project_name: "Knowledge-AG" # change to your own wandb project name
18
+ entity_name: "compai" # change to your own wandb entity name
19
+ max_epochs: 50
20
+ train_batch_size: 16
21
+ valid_batch_size: 16
22
+ num_workers: 28
23
+ log_every_n_steps: 100
24
+ gpu: 0
25
+ ddp: true
26
+ optimizer: "adamw"
27
+ learning_rate: 3e-6 #5e-6
28
+ weight_decay: 0.01
29
+
30
+ dataset:
31
+ vindr:
32
+ img_root: "/vol/ciamspace/datasets/X-ray/vindr-cxr/processed/images_512/"
33
+ annotation_csv: "/u/home/lj0/Code/AG-KD-miccai25/annotations/vindr_dataset.csv"
34
+ data_pct: 1.0
35
+
36
+
configs/padchest_definition.yaml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pleural thickening: "Increased thickness of the pleura seen as a dense layer around the lung."
2
+ atelectasis: "Collapsed lung tissue causing darkened or shrunken areas in the lung."
3
+ pleural effusion: "Excess fluid in the pleural space appearing as a shadow around the lungs."
4
+ cardiomegaly: "Enlargement of the heart seen when the heart appears larger than normal."
5
+ aortic elongation: "Lengthened and tortuous aorta, visible as an elongated curving structure."
6
+ vertebral degenerative changes: "Irregular vertebral margins with bony sclerosis and osteophytes."
7
+ aortic atheromatosis: "Calcified deposits in the aortic wall appearing as bright, irregular opacities."
8
+ nodule: "A growth or lump in the lung which may appear as a well-defined or irregular shape."
9
+ alveolar pattern: "Cloud-like, patchy opacities representing fluid or cellular accumulation in alveoli."
10
+ hiatal hernia: "A soft-tissue mass or air-fluid level above the diaphragm, near the midline."
11
+ scoliosis: "Sideways curvature of the spine causing misalignment of vertebral bodies."
12
+ hemidiaphragm elevation: "One side of the diaphragm appearing higher than the other, with convex shape."
13
+ hyperinflated lung: "Abnormally increased lung volume with expanded air spaces."
14
+ interstitial pattern: "Fine reticular or nodular opacities spread across the lung, indicating interstitial involvement."
15
+ fracture: "A break in the bone appearing as a radiolucent line or displacement."
16
+ vascular hilar enlargement: "Increased prominence of the pulmonary vessels near the lung hila."
17
+ nsg tube: "A thin radiopaque tube extending from the nasal cavity into the stomach."
18
+ endotracheal tube: "A thin or opaque line in the middle of the trachea. "
19
+ hypoexpansion: "Reduced lung inflation with increased density and narrow intercostal spaces."
20
+ central venous catheter: "A visible line inside large vein."
21
+ electrical device: "A dense, well-defined metallic opacity, typically a pacemaker or defibrillator."
22
+ bronchiectasis: "Dilated bronchi with thick walls, appearing as tubular or cystic opacities."
23
+ goiter: "A soft tissue mass in the anterior neck, sometimes displacing the trachea."
24
+ other entities: "An unusual mass or area in the lung with irregular borders or density."
configs/vindr_definition.yaml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ lung opacity: "An area of increased density in the lung fields typically appearing as a white or grayish patch."
2
+ infiltration: "Accumulation of substances or cells in the lung tissue visible as increased density or nodules."
3
+ consolidation: "Lung tissue filled with fluid or cells causing dense solid areas on imaging."
4
+ nodule or mass: "A growth or lump in the lung which may appear as a well-defined or irregular shape."
5
+ pleural thickening: "Increased thickness of the pleura seen as a dense layer around the lung."
6
+ aortic enlargement: "Widening of the aorta visible as an enlarged artery on imaging."
7
+ pulmonary fibrosis: "Scarring of the lung tissue creating a dense fibrous appearance."
8
+ ild: "Scarring or inflammation of the lung’s interstitial tissue creating a reticular or nodular pattern."
9
+ cardiomegaly: "Enlargement of the heart seen when the heart appears larger than normal."
10
+ other lesion: "An unusual mass or area in the lung with irregular borders or density."
11
+ pleural effusion: "Excess fluid in the pleural space appearing as a shadow around the lungs."
12
+ calcification: "Calcium deposits in lung tissue visible as bright white spots."
13
+ enlarged pa: "Widening of the pulmonary artery seen as an enlarged artery in the chest."
14
+ lung cavity: "Air-filled spaces within the lung often surrounded by dense tissue."
15
+ atelectasis: "Collapsed lung tissue causing darkened or shrunken areas in the lung."
16
+ mediastinal shift: "Displacement of central chest structures like the heart to one side."
17
+ lung cyst: "Fluid-filled spaces in the lung often round with thin walls."
18
+ pneumothorax: "Air trapped in the pleural space creating a gap or absence of lung tissue."
19
+ emphysema: "Enlarged air spaces in the lungs appearing over-expanded or damaged."
20
+ clavicle fracture: "A break in the collarbone seen as a gap or irregularity in the bone."
21
+ rib fracture: "A break in one or more ribs appearing as a visible crack or displacement."
22
+ edema: "Fluid accumulation in the lungs creating a hazy or clouded area."
examples/26746130963764173994750391023442607773-2_mukhp1.png ADDED
examples/f1eb2216d773ced6330b1f31e18f04f8.png ADDED
examples/fb4dfacc089f4b5550f03f52e706b6f2.png ADDED
examples/prompt.yaml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ ./examples/26746130963764173994750391023442607773-2_mukhp1.png:
2
+ - electrical device
3
+
4
+ ./examples/f1eb2216d773ced6330b1f31e18f04f8.png:
5
+ - pulmonary fibrosis
6
+
7
+ ./examples/fb4dfacc089f4b5550f03f52e706b6f2.png:
8
+ - cardiomegaly
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit
2
+ torch
3
+ transformers
4
+ pillow
5
+ numpy
6
+ supervision
7
+ albumentations
8
+ opencv-python
9
+ pyyaml
10
+ einops
11
+ timm