diff --git a/DirectoryImageMaskProcessor_23directions.py b/DirectoryImageMaskProcessor_23directions.py new file mode 100644 index 0000000..4ac22b4 --- /dev/null +++ b/DirectoryImageMaskProcessor_23directions.py @@ -0,0 +1,96 @@ +from PIL import Image +import os +from red23connected_components import CrackClassifier + + +class DirectoryImageMaskProcessor_23directions: + def __init__(self, input_directory): + self.input_directory = input_directory + parent_directory = os.path.dirname(input_directory) + # self.red_output_directory = os.path.join(parent_directory, "red_crack_masks") + # self.green_output_directory = os.path.join( + # parent_directory, "green_spall_masks" + # ) + # self.horizontal_masks_directory = os.path.join( + # parent_directory, "horizontal_crack_masks" + # ) + # self.vertical_masks_directory = os.path.join( + # parent_directory, "vertical_crack_masks" + # ) + # self.diagonal_masks_directory = os.path.join( + # parent_directory, "diagonal_crack_masks" + # ) + self.output_directory = os.path.join(parent_directory, "3masks") + + def process_directory(self): + # Ensure the output directories exist + # os.makedirs(self.red_output_directory, exist_ok=True) + # os.makedirs(self.green_output_directory, exist_ok=True) + # os.makedirs(self.horizontal_crack_masks, exist_ok=True) + # os.makedirs(self.vertical_crack_masks, exist_ok=True) + # os.makedirs(self.diagonal_crack_masks, exist_ok=True) + + image_files = [ + f + for f in os.listdir(self.input_directory) + if f.lower().endswith(("png", "jpg", "jpeg")) + ] + total_images = len(image_files) + print(f"Found {total_images} images to process.") + + for idx, image_file in enumerate(image_files, start=1): + print(f"Processing image {idx}/{total_images}: {image_file}") + self.process_image(image_file) + + print("All images processed successfully.") + + def process_image(self, image_file): + # Load and convert the image + image_path = os.path.join(self.input_directory, image_file) + output_directory_w_filename = os.path.join(self.output_directory, image_file) + CrackClassifier.classify_and_save_cracks( + image_path, output_directory_w_filename + ) + # image = Image.open(image_path).convert("RGBA") + + # # Split the loaded image into separate channels + # r, g, b, a = image.split() + + # # Create and save the red and green masks + # self.create_and_save_mask( + # r, image_file, self.red_output_directory, mask_type="red" + # ) + # self.create_and_save_mask( + # g, image_file, self.green_output_directory, mask_type="green" + # ) + + def create_and_save_mask(self, channel, image_file, output_directory, mask_type): + # Create a mask from the given channel + mask = Image.merge( + "RGBA", + ( + channel if mask_type == "red" else Image.new("L", channel.size, 0), + channel if mask_type == "green" else Image.new("L", channel.size, 0), + Image.new("L", channel.size, 0), + channel, + ), + ) + + # Define the full path for the mask + mask_path = os.path.join(output_directory, image_file) + + # Save the mask + mask.save(mask_path) + print(f"Saved {mask_type} mask: {mask_path}") + + +# Example usage +if __name__ == "__main__": + input_directory = "images_folder" # Adjust this path to your folder of images + + processor = DirectoryImageMaskProcessor(input_directory) + processor.process_directory() + + print( + f"Processing complete. Check the parent directory of '{input_directory}' for the 'red_crack_masks' and 'green_spall_masks' folders." + ) diff --git a/crack23directions.py b/crack23directions.py index 97d5df2..7eddf45 100644 --- a/crack23directions.py +++ b/crack23directions.py @@ -8,6 +8,9 @@ from pathlib import Path from DirectoryImageMaskProcessor_1 import DirectoryImageMaskProcessor +from DirectoryImageMaskProcessor_23directions import ( + DirectoryImageMaskProcessor_23directions, +) class CrackMaskProcessor: @@ -42,6 +45,9 @@ def ensure_directories_exist(self): def get_crack_spall_mask_path(self): return self.mask_directory + def get_red_crack_mask_path(self): + return self.mask_directory.replace("crackmask", "red_crack_masks") + def get_and_ensure_3masks_directory(self): # Replace 'crackmask' with '3masks' in the mask_directory path masks_directory = self.mask_directory.replace("crackmask", "3masks") @@ -55,6 +61,17 @@ def get_and_ensure_3masks_directory(self): # Main part of the script +def extract_crack(crack_spall_mask_path): + input_directory = crack_spall_mask_path + + processor_extract_crack = DirectoryImageMaskProcessor(input_directory) + processor_extract_crack.process_directory() + + print( + f"Processing complete. Check the parent directory of '{input_directory}' for the results." + ) + + if __name__ == "__main__": script_dir = Path(__file__).parent.absolute() config_ini_path = script_dir / "config.ini" @@ -66,15 +83,22 @@ def get_and_ensure_3masks_directory(self): crack_spall_mask_path = processor.get_crack_spall_mask_path() print(f"Crack/Spall Mask Path: {crack_spall_mask_path}") + # Extracting red crack images into a seperate file + # extract_crack(crack_spall_mask_path) + + # Get red_crack_masks directory path + red_crack_mask_path = processor.get_red_crack_mask_path() + print(f"red_crack_mask Path: {red_crack_mask_path}") + masks_directory_path = processor.get_and_ensure_3masks_directory() print(f"'3masks' Directory Path: {masks_directory_path}") - # Extracting red crack images into a seperate file - input_directory = crack_spall_mask_path + # Extracting three directions of cracks into three files + input_directory = red_crack_mask_path - processor = DirectoryImageMaskProcessor(input_directory) - processor.process_directory() + processor_extract_3 = DirectoryImageMaskProcessor_23directions(input_directory) + processor_extract_3.process_directory() print( - f"Processing complete. Check the parent directory of '{input_directory}' for the results." + f"Processing complete. Check the parent directory of '{masks_directory_path}' for the results." ) diff --git a/crackmask2spalloverlay.py b/crackmask2spalloverlay.py index 14af952..fbf4de7 100644 --- a/crackmask2spalloverlay.py +++ b/crackmask2spalloverlay.py @@ -24,13 +24,27 @@ def main(): # Iterate over the files in the mask directory for mask_name in os.listdir(mask_dir): # Extract the image name from the filename - raw_name = mask_name.split(".")[0] + ".JPG" - + raw_name_base = mask_name.split(".")[0] + raw_name_jpg = f"{raw_name_base}.jpg" + raw_name_JPG = f"{raw_name_base}.JPG" + + # Check for the existence of the raw image file with both extensions + raw_path_jpg = os.path.join(raw_dir, raw_name_jpg) + raw_path_JPG = os.path.join(raw_dir, raw_name_JPG) + + if os.path.exists(raw_path_jpg): + raw_path = raw_path_jpg + elif os.path.exists(raw_path_JPG): + raw_path = raw_path_JPG + else: + print(f"Error: Raw image file not found for {mask_name}. Skipping...") + continue + # Load the mask and raw images mask = cv2.imread(os.path.join(mask_dir, mask_name), cv2.IMREAD_GRAYSCALE) - raw = cv2.imread(os.path.join(raw_dir, raw_name)) + raw = cv2.imread(raw_path) if mask is None or raw is None: - print(f"Error reading {mask_name} or {raw_name}. Skipping...") + print(f"Error reading {mask_name} or {raw_path}. Skipping...") continue print(raw.shape) print(mask.shape) @@ -39,7 +53,7 @@ def main(): # raw[mask == 38] = [0, 0, 255] raw[mask == 75] = [0, 0, 255] # Save the overlaid image to the output directory - spall_overlaid_image_path = os.path.join(spall_overlay_directory, raw_name) + spall_overlaid_image_path = os.path.join(spall_overlay_directory, os.path.basename(raw_path)) cv2.imwrite(spall_overlaid_image_path, raw) print(f"Saved {spall_overlaid_image_path}") diff --git a/cracksegmentation.py b/cracksegmentation.py index 6f769d3..87276b3 100644 --- a/cracksegmentation.py +++ b/cracksegmentation.py @@ -47,7 +47,7 @@ --model "{model_path}" \ --images "{raw_directory}" \ --output "{mask_directory}" \ - --extension 'JPG' + --extension jpg png JPG """ os.system(command) diff --git a/red23connected_components.py b/red23connected_components.py new file mode 100644 index 0000000..5831223 --- /dev/null +++ b/red23connected_components.py @@ -0,0 +1,81 @@ +import numpy as np +from skimage.measure import label, regionprops +from PIL import Image, ImageDraw +import os + + +class CrackClassifier: + def __init__(self): + pass + + @classmethod + def classify_and_save_cracks(cls, red_mask_image_path, output_folder): + # Load the red mask image + red_mask = Image.open(red_mask_image_path) + + # Convert to numpy array and get the alpha channel as the mask + red_mask_np = np.array(red_mask) + alpha_channel = red_mask_np[ + :, :, 3 + ] # Assuming the alpha channel is the last one + + # Label connected components + labeled_mask = label(alpha_channel) + + # Analyze properties of labeled regions + regions = regionprops(labeled_mask) + + # Placeholder for categorized cracks + vertical_cracks = [] + horizontal_cracks = [] + diagonal_cracks = [] + + # Classify based on orientation and aspect ratio + for props in regions: + y0, x0, y1, x1 = props.bbox + region_height = y1 - y0 + region_width = x1 - x0 + aspect_ratio = region_width / float(region_height) + + if aspect_ratio > 2: + horizontal_cracks.extend(props.coords) + elif aspect_ratio < 0.5: + vertical_cracks.extend(props.coords) + else: + # Diagonal classification can be refined as needed + orientation = props.orientation + if -np.pi / 4 <= orientation <= np.pi / 4: + horizontal_cracks.extend(props.coords) + else: + diagonal_cracks.extend(props.coords) + + # Create the output directory if it doesn't exist + if not os.path.exists(output_folder): + os.makedirs(output_folder) + + # Image shape needed for mask creation + image_shape = alpha_channel.shape + + # Save masks for each type of crack + cls._save_crack_mask( + vertical_cracks, f"{output_folder}/vertical_crack_mask.png", image_shape + ) + cls._save_crack_mask( + horizontal_cracks, f"{output_folder}/horizontal_crack_mask.png", image_shape + ) + cls._save_crack_mask( + diagonal_cracks, f"{output_folder}/diagonal_crack_mask.png", image_shape + ) + + @staticmethod + def _save_crack_mask(coords_list, mask_path, image_shape): + # Create an empty image with transparent background + crack_mask = Image.new("RGBA", (image_shape[1], image_shape[0]), (0, 0, 0, 0)) + draw = ImageDraw.Draw(crack_mask) + + # Draw each pixel for the classified cracks + for coord in coords_list: + draw.point((coord[1], coord[0]), fill=(255, 0, 0, 255)) # (x, y) + + # Save the mask + crack_mask.save(mask_path)