Spaces:
Runtime error
Runtime error
Update app.py
Browse filesadd images to gcs
app.py
CHANGED
|
@@ -97,8 +97,15 @@ def load_gradcam_model():
|
|
| 97 |
|
| 98 |
# Utility Functions
|
| 99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
def upload_to_gcs(image_data: io.BytesIO, filename: str, content_type='application/dicom'):
|
| 101 |
-
|
| 102 |
try:
|
| 103 |
blob = bucket_result.blob(filename)
|
| 104 |
blob.upload_from_file(image_data, content_type=content_type)
|
|
@@ -106,9 +113,9 @@ def upload_to_gcs(image_data: io.BytesIO, filename: str, content_type='applicati
|
|
| 106 |
except Exception as e:
|
| 107 |
st.error(f"An unexpected error occurred: {e}")
|
| 108 |
|
| 109 |
-
def load_dicom_from_gcs(
|
| 110 |
# Get the blob object
|
| 111 |
-
blob = bucket_load.blob(
|
| 112 |
|
| 113 |
# Download the file as a bytes object
|
| 114 |
dicom_bytes = blob.download_as_bytes()
|
|
@@ -116,75 +123,95 @@ def load_dicom_from_gcs(file_name: str = "dicom_00000001_000.dcm"):
|
|
| 116 |
# Wrap bytes object into BytesIO (file-like object)
|
| 117 |
dicom_stream = io.BytesIO(dicom_bytes)
|
| 118 |
|
| 119 |
-
# Load the DICOM file
|
| 120 |
ds = pydicom.dcmread(dicom_stream)
|
| 121 |
|
| 122 |
return ds
|
| 123 |
|
| 124 |
-
def png_to_dicom(image_path: str, image_name: str, dicom: str = None):
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
else
|
| 128 |
-
ds = load_dicom_from_gcs(dicom)
|
| 129 |
|
| 130 |
-
|
|
|
|
| 131 |
print("Image Mode:", jpg_image.mode)
|
| 132 |
-
if jpg_image.mode == 'L':
|
| 133 |
-
np_image = np.array(jpg_image.getdata(), dtype=np.uint8)
|
| 134 |
-
ds.Rows = jpg_image.height
|
| 135 |
-
ds.Columns = jpg_image.width
|
| 136 |
-
ds.PhotometricInterpretation = "MONOCHROME1"
|
| 137 |
-
ds.SamplesPerPixel = 1
|
| 138 |
-
ds.BitsStored = 8
|
| 139 |
-
ds.BitsAllocated = 8
|
| 140 |
-
ds.HighBit = 7
|
| 141 |
-
ds.PixelRepresentation = 0
|
| 142 |
-
ds.PixelData = np_image.tobytes()
|
| 143 |
-
ds.save_as(image_name)
|
| 144 |
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
ds.BitsStored = 8
|
| 152 |
-
ds.BitsAllocated = 8
|
| 153 |
-
ds.HighBit = 7
|
| 154 |
-
ds.PixelRepresentation = 0
|
| 155 |
-
ds.PixelData = np_image.tobytes()
|
| 156 |
-
ds.save_as(image_name)
|
| 157 |
-
elif jpg_image.mode == 'RGB':
|
| 158 |
-
np_image = np.array(jpg_image.getdata(), dtype=np.uint8)[:, :3] # Remove alpha if present
|
| 159 |
ds.Rows = jpg_image.height
|
| 160 |
ds.Columns = jpg_image.width
|
| 161 |
-
ds.PhotometricInterpretation = "RGB"
|
| 162 |
-
ds.SamplesPerPixel = 3
|
| 163 |
ds.BitsStored = 8
|
| 164 |
ds.BitsAllocated = 8
|
| 165 |
ds.HighBit = 7
|
| 166 |
ds.PixelRepresentation = 0
|
| 167 |
ds.PixelData = np_image.tobytes()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
ds.save_as(image_name)
|
| 169 |
else:
|
| 170 |
-
raise ValueError("Unsupported image mode:
|
|
|
|
| 171 |
return ds
|
| 172 |
|
| 173 |
-
def
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
-
def upload_folder_images(original_image_path, enhanced_image_path):
|
| 180 |
-
# Extract the base name of the uploaded image without the extension
|
| 181 |
-
folder_name = os.path.splitext(uploaded_file.name)[0]
|
| 182 |
# Create the folder in Cloud Storage
|
| 183 |
bucket_result.blob(folder_name + '/').upload_from_string('', content_type='application/x-www-form-urlencoded')
|
|
|
|
| 184 |
enhancement_name = enhancement_type.split('_')[-1]
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
enhanced_dicom = png_to_dicom(enhanced_image_path, enhancement_name + ".dcm")
|
| 188 |
|
| 189 |
# Convert DICOM to byte stream for uploading
|
| 190 |
original_dicom_bytes = io.BytesIO()
|
|
@@ -199,6 +226,7 @@ def upload_folder_images(original_image_path, enhanced_image_path):
|
|
| 199 |
upload_to_gcs(enhanced_dicom_bytes, folder_name + '/' + enhancement_name + '.dcm', content_type='application/dicom')
|
| 200 |
|
| 201 |
|
|
|
|
| 202 |
def get_mean_std_per_batch(image_path, H=320, W=320):
|
| 203 |
sample_data = []
|
| 204 |
for idx, img in enumerate(df.sample(100)["Image Index"].values):
|
|
@@ -391,6 +419,7 @@ def redirect_button(url):
|
|
| 391 |
# File uploader for DICOM files
|
| 392 |
if uploaded_file is not None:
|
| 393 |
if hasattr(uploaded_file, 'name'):
|
|
|
|
| 394 |
file_extension = uploaded_file.name.split(".")[-1] # Get the file extension
|
| 395 |
if file_extension.lower() == "dcm":
|
| 396 |
# Process DICOM file
|
|
@@ -475,7 +504,8 @@ if uploaded_file is not None:
|
|
| 475 |
# Save original image to a file
|
| 476 |
original_image_path = "original_image.png"
|
| 477 |
cv2.imwrite(original_image_path, original_image)
|
| 478 |
-
|
|
|
|
| 479 |
# Add the redirect button
|
| 480 |
col1, col2, col3 = st.columns(3)
|
| 481 |
with col1:
|
|
|
|
| 97 |
|
| 98 |
# Utility Functions
|
| 99 |
|
| 100 |
+
# Dictionaries to track InstanceNumbers and StudyInstanceUIDs per filename
|
| 101 |
+
# Initialize session state for instance numbers and study UIDs
|
| 102 |
+
if 'instance_numbers' not in st.session_state:
|
| 103 |
+
st.session_state.instance_numbers = {}
|
| 104 |
+
if 'study_uids' not in st.session_state:
|
| 105 |
+
st.session_state.study_uids = {}
|
| 106 |
+
|
| 107 |
def upload_to_gcs(image_data: io.BytesIO, filename: str, content_type='application/dicom'):
|
| 108 |
+
#Uploads an image to Google Cloud Storage.
|
| 109 |
try:
|
| 110 |
blob = bucket_result.blob(filename)
|
| 111 |
blob.upload_from_file(image_data, content_type=content_type)
|
|
|
|
| 113 |
except Exception as e:
|
| 114 |
st.error(f"An unexpected error occurred: {e}")
|
| 115 |
|
| 116 |
+
def load_dicom_from_gcs(dicom_name: str = "dicom_00000001_000.dcm"):
|
| 117 |
# Get the blob object
|
| 118 |
+
blob = bucket_load.blob(dicom_name)
|
| 119 |
|
| 120 |
# Download the file as a bytes object
|
| 121 |
dicom_bytes = blob.download_as_bytes()
|
|
|
|
| 123 |
# Wrap bytes object into BytesIO (file-like object)
|
| 124 |
dicom_stream = io.BytesIO(dicom_bytes)
|
| 125 |
|
| 126 |
+
# Load the DICOM file
|
| 127 |
ds = pydicom.dcmread(dicom_stream)
|
| 128 |
|
| 129 |
return ds
|
| 130 |
|
| 131 |
+
def png_to_dicom(image_path: str, image_name: str, file_name: str, instance_number: int = 1, dicom: str = None, study_instance_uid: str = None, ):
|
| 132 |
+
|
| 133 |
+
# Load the template DICOM file
|
| 134 |
+
ds = load_dicom_from_gcs() if dicom is None else load_dicom_from_gcs(dicom)
|
|
|
|
| 135 |
|
| 136 |
+
# Process the image
|
| 137 |
+
jpg_image = Image.open(image_path) # the PNG or JPG file to be replaced
|
| 138 |
print("Image Mode:", jpg_image.mode)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
+
if jpg_image.mode in ('L', 'RGBA', 'RGB'):
|
| 141 |
+
if jpg_image.mode == 'RGBA':
|
| 142 |
+
np_image = np.array(jpg_image.getdata(), dtype=np.uint8)[:,:3]
|
| 143 |
+
else:
|
| 144 |
+
np_image = np.array(jpg_image.getdata(),dtype=np.uint8)
|
| 145 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
ds.Rows = jpg_image.height
|
| 147 |
ds.Columns = jpg_image.width
|
| 148 |
+
ds.PhotometricInterpretation = "MONOCHROME1" if jpg_image.mode == 'L' else "RGB"
|
| 149 |
+
ds.SamplesPerPixel = 1 if jpg_image.mode == 'L' else 3
|
| 150 |
ds.BitsStored = 8
|
| 151 |
ds.BitsAllocated = 8
|
| 152 |
ds.HighBit = 7
|
| 153 |
ds.PixelRepresentation = 0
|
| 154 |
ds.PixelData = np_image.tobytes()
|
| 155 |
+
|
| 156 |
+
if not hasattr(ds, 'PatientName') or ds.PatientName == '':
|
| 157 |
+
ds.PatientName = os.path.splitext(file_name)[0] # Remove extension
|
| 158 |
+
|
| 159 |
+
ds.SeriesDescription = 'original image' if image_name == 'original_image.dcm' else enhancement_type
|
| 160 |
+
|
| 161 |
+
if hasattr(ds, 'StudyDescription'):
|
| 162 |
+
del ds.StudyDescription
|
| 163 |
+
|
| 164 |
+
if study_instance_uid:
|
| 165 |
+
ds.StudyInstanceUID = study_instance_uid
|
| 166 |
+
else:
|
| 167 |
+
# Check if a StudyInstanceUID exists for the file name
|
| 168 |
+
if file_name in st.session_state.study_uids:
|
| 169 |
+
ds.StudyInstanceUID = st.session_state.study_uids[file_name]
|
| 170 |
+
print(f"Reusing StudyInstanceUID for '{file_name}'")
|
| 171 |
+
else:
|
| 172 |
+
# Generate a new StudyInstanceUID and store it
|
| 173 |
+
new_study_uid = generate_uid()
|
| 174 |
+
st.session_state.study_uids[file_name] = new_study_uid
|
| 175 |
+
ds.StudyInstanceUID = new_study_uid
|
| 176 |
+
print(f"New StudyInstanceUID generated for '{file_name}'")
|
| 177 |
+
|
| 178 |
+
# Generate a new SeriesInstanceUID and SOPInstanceUID for the added image
|
| 179 |
+
ds.SeriesInstanceUID = generate_uid()
|
| 180 |
+
ds.SOPInstanceUID = generate_uid()
|
| 181 |
+
|
| 182 |
+
if hasattr(ds, 'InstanceNumber'):
|
| 183 |
+
st.session_state.instance_numbers[file_name] = int(ds.InstanceNumber) + 1
|
| 184 |
+
else:
|
| 185 |
+
# Manage InstanceNumber based on filename
|
| 186 |
+
if file_name in st.session_state.instance_numbers:
|
| 187 |
+
st.session_state.instance_numbers[file_name] += 1
|
| 188 |
+
else:
|
| 189 |
+
st.session_state.instance_numbers[file_name] = 1
|
| 190 |
+
ds.InstanceNumber = int(st.session_state.instance_numbers[file_name])
|
| 191 |
+
|
| 192 |
ds.save_as(image_name)
|
| 193 |
else:
|
| 194 |
+
raise ValueError(f"Unsupported image mode: {jpg_image.mode}")
|
| 195 |
+
|
| 196 |
return ds
|
| 197 |
|
| 198 |
+
def upload_folder_images(original_image_path, enhanced_image_path, file_name):
|
| 199 |
+
# Convert images to DICOM if result is png
|
| 200 |
+
if not original_image_path.lower().endswith('.dcm'):
|
| 201 |
+
original_dicom = png_to_dicom(original_image_path, "original_image.dcm", file_name=file_name)
|
| 202 |
+
else:
|
| 203 |
+
original_dicom = pydicom.dcmread(original_image_path)
|
| 204 |
+
study_instance_uid = original_dicom.StudyInstanceUID
|
| 205 |
+
|
| 206 |
+
# Use StudyInstanceUID as folder name
|
| 207 |
+
folder_name = study_instance_uid
|
| 208 |
|
|
|
|
|
|
|
|
|
|
| 209 |
# Create the folder in Cloud Storage
|
| 210 |
bucket_result.blob(folder_name + '/').upload_from_string('', content_type='application/x-www-form-urlencoded')
|
| 211 |
+
|
| 212 |
enhancement_name = enhancement_type.split('_')[-1]
|
| 213 |
+
|
| 214 |
+
enhanced_dicom = png_to_dicom(enhanced_image_path, enhancement_name + ".dcm", study_instance_uid=study_instance_uid, file_name=file_name)
|
|
|
|
| 215 |
|
| 216 |
# Convert DICOM to byte stream for uploading
|
| 217 |
original_dicom_bytes = io.BytesIO()
|
|
|
|
| 226 |
upload_to_gcs(enhanced_dicom_bytes, folder_name + '/' + enhancement_name + '.dcm', content_type='application/dicom')
|
| 227 |
|
| 228 |
|
| 229 |
+
|
| 230 |
def get_mean_std_per_batch(image_path, H=320, W=320):
|
| 231 |
sample_data = []
|
| 232 |
for idx, img in enumerate(df.sample(100)["Image Index"].values):
|
|
|
|
| 419 |
# File uploader for DICOM files
|
| 420 |
if uploaded_file is not None:
|
| 421 |
if hasattr(uploaded_file, 'name'):
|
| 422 |
+
file_name = uploaded_file.name
|
| 423 |
file_extension = uploaded_file.name.split(".")[-1] # Get the file extension
|
| 424 |
if file_extension.lower() == "dcm":
|
| 425 |
# Process DICOM file
|
|
|
|
| 504 |
# Save original image to a file
|
| 505 |
original_image_path = "original_image.png"
|
| 506 |
cv2.imwrite(original_image_path, original_image)
|
| 507 |
+
upload_folder_images(original_image_path, enhanced_image_path, file_name)
|
| 508 |
+
|
| 509 |
# Add the redirect button
|
| 510 |
col1, col2, col3 = st.columns(3)
|
| 511 |
with col1:
|