<jupyter_start><jupyter_text>Image Splitter for MetashapeThis script aims to split the images stitched and processed with metashape into data that can be fed into a CNN or other machine learning AI.<jupyter_code># Import OpenCV libraries
import cv2
import matplotlib.pyplot as plt

import numpy as np
import tifffile
# Import image
img = tifffile.imread('./input/GeoTiff_cropped_2020_06_11.tif')

# Check to make sure we don't import garbage
if img.dtype == np.uint8:
    depth = 8
elif img.dtype == np.uint16:
    depth = 16
else:
    print("Warning: unsupported data type {}. Assuming 16-bit.", img.dtype)
    depth = 16
    
# Find the dimensions and channels of the image
img_height, img_width, img_channels = img.shape
print("Image height (Pixels):\t", img_height)
print("Image width (Pixels):\t", img_width)
print("Image channels:\t\t", img_channels)
print("----------------------------------")

# Calculate corrected image size, so it can be split into 255x255 blocks
img_height_cropped = (int(img_height/256)*256)-1
img_width_cropped = (int(img_width/256)*256)-1

print("Image height cropped:\t", img_height_cropped)
print("Image width cropped:\t", img_width_cropped)
print("----------------------------------")

# Crop the image
img_crop  = img[0:img_height_cropped, 0:img_width_cropped]
img_height_corrected, img_width_corrected, img_channels = img_crop.shape

print("New image height:\t", img_height_corrected)
print("New image width:\t", img_width_corrected)
print("Image channels:\t\t", img_channels)
print("----------------------------------")

img_crop_norm_tmp = np.zeros((img_height_corrected, img_width_corrected))
img_crop = cv2.normalize(img_crop, img_crop_norm_tmp, 0, 255, cv2.NORM_MINMAX)

# Split the image into its cahnnels
img_crop_ch1, img_crop_ch2, img_crop_ch3, img_crop_ch4, img_crop_ch5, img_crop_ch6 = cv2.split(img_crop)

print("Image has been split into 6 seperate images")
# Normalize all chennales individually
# Normalizing channel 1
img_crop_norm_tmp = np.zeros((img_height_corrected, img_width_corrected))
img_crop_ch1 = cv2.normalize(img_crop_ch1, img_crop_norm_tmp, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)

# Normalizing channel 2
img_crop_norm_tmp = np.zeros((img_height_corrected, img_width_corrected))
img_crop_ch2 = cv2.normalize(img_crop_ch2, img_crop_norm_tmp, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)

# Normalizing channel 3
img_crop_norm_tmp = np.zeros((img_height_corrected, img_width_corrected))
img_crop_ch3 = cv2.normalize(img_crop_ch3, img_crop_norm_tmp, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)

# Normalizing channel 4
img_crop_norm_tmp = np.zeros((img_height_corrected, img_width_corrected))
img_crop_ch4 = cv2.normalize(img_crop_ch4, img_crop_norm_tmp, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)

# Normalizing channel 5
img_crop_norm_tmp = np.zeros((img_height_corrected, img_width_corrected))
img_crop_ch5 = cv2.normalize(img_crop_ch5, img_crop_norm_tmp, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)

# Normalizing channel 6
img_crop_norm_tmp = np.zeros((img_height_corrected, img_width_corrected))
img_crop_ch6 = cv2.normalize(img_crop_ch6, img_crop_norm_tmp, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)
# Import mask
img_mask = cv2.imread('./input/Mask.jpg')

# Check to make sure we don't import garbage
if img_mask.dtype == np.uint8:
    depth = 8
elif img_mask.dtype == np.uint16:
    depth = 16
else:
    print("Warning: unsupported data type {}. Assuming 16-bit.", img_rgb.dtype)
    depth = 16
    
# Find the dimensions and channels of the image
img_mask_height, img_mask_width, img_mask_channels = img_mask.shape
print("Image height (Pixels):\t", img_mask_height)
print("Image width (Pixels):\t", img_mask_width)
print("Image channels:\t\t", img_mask_channels)
print("----------------------------------")

# Calculate corrected image size, so it can be split into 255x255 blocks
img_mask_height_cropped = (int(img_mask_height/256)*256)-1
img_mask_width_cropped = (int(img_mask_width/256)*256)-1

print("Image height cropped:\t", img_mask_height_cropped)
print("Image width cropped:\t", img_mask_width_cropped)
print("----------------------------------")

# Crop the image
img_mask_crop  = img_mask[0:img_mask_height_cropped, 0:img_mask_width_cropped]
img_mask_height_corrected, img_mask_width_corrected, img_mask_channels = img_mask_crop.shape

print("New image height:\t", img_mask_height_corrected)
print("New image width:\t", img_mask_width_corrected)
print("Image channels:\t\t", img_mask_channels)
print("----------------------------------")
# Import RGB reference
img_rgb = cv2.imread('./input/RGB.jpg')


# Check to make sure we don't import garbage
if img_rgb.dtype == np.uint8:
    depth = 8
elif img_rgb.dtype == np.uint16:
    depth = 16
else:
    print("Warning: unsupported data type {}. Assuming 16-bit.", img_rgb.dtype)
    depth = 16
    
# Find the dimensions and channels of the image
img_rgb_height, img_rgb_width, img_rgb_channels = img_rgb.shape
print("Image height (Pixels):\t", img_rgb_height)
print("Image width (Pixels):\t", img_rgb_width)
print("Image channels:\t\t", img_rgb_channels)
print("----------------------------------")

# Calculate corrected image size, so it can be split into 255x255 blocks
img_rgb_height_cropped = (int(img_rgb_height/256)*256)-1
img_rgb_width_cropped = (int(img_rgb_width/256)*256)-1

print("Image height cropped:\t", img_rgb_height_cropped)
print("Image width cropped:\t", img_rgb_width_cropped)
print("----------------------------------")

# Crop the image
img_rgb_crop  = img_rgb[0:img_rgb_height_cropped, 0:img_rgb_width_cropped]
img_rgb_height_corrected, img_rgb_width_corrected, img_rgb_channels = img_rgb_crop.shape


print("New image height:\t", img_rgb_height_corrected)
print("New image width:\t", img_rgb_width_corrected)
print("Image channels:\t\t", img_rgb_channels)
print("----------------------------------")
import os

# Define chunk size and make sure directory paths exist
counter = 0
chunk_size = 128 # In pixels
Path = 'output/'
res = os.system("mkdir -p " + Path + "Field_1")
print(res)
res = os.system("mkdir -p " + Path + "Field_2")
print(res)
res = os.system("mkdir -p " + Path + "Field_3")
print(res)
res = os.system("mkdir -p " + Path + "Field_4")
print(res)
res = os.system("mkdir -p " + Path + "Mask_reference")
print(res)
res = os.system("mkdir -p " + Path + "RGB_reference")
print(res)

# Equalize histograms of all channels and save originals and modified channels
cv2.imwrite(Path + '/image_ch1.jpg', img_crop_ch1)
img_crop_ch1_eq = cv2.equalizeHist(img_crop_ch1)
cv2.imwrite(Path + '/image_eq_ch1.jpg', img_crop_ch1_eq)

cv2.imwrite(Path + '/image_ch2.jpg', img_crop_ch2)
img_crop_ch2_eq = cv2.equalizeHist(img_crop_ch2)
cv2.imwrite(Path + '/image_eq_ch2.jpg', img_crop_ch2_eq)

cv2.imwrite(Path + '/image_ch3.jpg', img_crop_ch3)
img_crop_ch3_eq = cv2.equalizeHist(img_crop_ch3)
cv2.imwrite(Path + '/image_eq_ch3.jpg', img_crop_ch3_eq)

cv2.imwrite(Path + '/image_ch4.jpg', img_crop_ch4)
img_crop_ch4_eq = cv2.equalizeHist(img_crop_ch4)
cv2.imwrite(Path + '/image_eq_ch4.jpg', img_crop_ch4_eq)

cv2.imwrite(Path + '/image_ch5.jpg', img_crop_ch5)
img_crop_ch5_eq = cv2.equalizeHist(img_crop_ch5)
cv2.imwrite(Path + '/image_eq_ch5.jpg', img_crop_ch5_eq)

cv2.imwrite(Path + '/image_ch6.jpg', img_crop_ch6)
img_crop_ch6_eq = cv2.equalizeHist(img_crop_ch6)
cv2.imwrite(Path + '/image_eq_ch6.jpg', img_crop_ch6_eq)
img_rgb_merged = cv2.merge((img_crop_ch1_eq, img_crop_ch2_eq, img_crop_ch3_eq))
img_rgb_grayed = cv2.cvtColor(img_rgb_merged, cv2.COLOR_BGR2GRAY)


# This instance merges the six channels back together before saving the chunks
img_merged = cv2.merge((img_rgb_grayed, img_crop_ch4_eq, img_crop_ch5_eq, img_crop_ch6_eq))
#img_merged = cv2.merge((img_crop_ch1_eq, img_crop_ch2_eq, img_crop_ch3_eq, img_crop_ch4_eq, img_crop_ch5_eq, img_crop_ch6_eq))
# Find the dimensions and channels of the image
img_rgb_height, img_rgb_width, img_rgb_channels = img_merged.shape
print("Image height (Pixels):\t", img_rgb_height)
print("Image width (Pixels):\t", img_rgb_width)
print("Image channels:\t\t", img_rgb_channels)
print("----------------------------------")

# Iterate though the maks by chunk_size and sort chunks into directories
for i in range(int((img_height_corrected+1)/chunk_size)):
    for j in range(int((img_width_corrected+1)/chunk_size)):
        counter += 1
        print("Processing square ", counter)
        
        img_mask_tmp = img_mask_crop[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size]
        img_rgb_tmp = img_rgb_crop[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size]
        
        if img_mask_tmp[int(chunk_size/2), int(chunk_size/2), 0] == 17:
            #tifffile.imsave(Path + '/Field_1/image_' + str(counter) + '.tiff', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Field_1/image_' + str(counter) + '.jpg', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Mask_reference/image_' + str(counter) + '.jpg', img_mask_tmp)
            cv2.imwrite(Path + '/RGB_reference/image_' + str(counter) + '_rgb.jpg', img_rgb_tmp)

        if img_mask_tmp[int(chunk_size/2), int(chunk_size/2), 0] == 68:
            #tifffile.imsave(Path + '/Field_2/image_' + str(counter) + '.tiff', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Field_2/image_' + str(counter) + '.jpg', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Mask_reference/image_' + str(counter) + '.jpg', img_mask_tmp)
            cv2.imwrite(Path + '/RGB_reference/image_' + str(counter) + '_rgb.jpg', img_rgb_tmp)
        
        if img_mask_tmp[int(chunk_size/2), int(chunk_size/2), 0] == 136:
            #tifffile.imsave(Path + '/Field_3/image_' + str(counter) + '.tiff', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Field_3/image_' + str(counter) + '.jpg', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Mask_reference/image_' + str(counter) + '.jpg', img_mask_tmp)
            cv2.imwrite(Path + '/RGB_reference/image_' + str(counter) + '_rgb.jpg', img_rgb_tmp)
        
        if img_mask_tmp[int(chunk_size/2), int(chunk_size/2), 0] == 187:
            #tifffile.imsave(Path + '/Field_4/image_' + str(counter) + '.tiff', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Field_4/image_' + str(counter) + '.jpg', img_merged[(i*chunk_size):(i*chunk_size)+chunk_size, (j*chunk_size):(j*chunk_size)+chunk_size])
            cv2.imwrite(Path + '/Mask_reference/image_' + str(counter) + '.jpg', img_mask_tmp)
            cv2.imwrite(Path + '/RGB_reference/image_' + str(counter) + '_rgb.jpg', img_rgb_tmp)
            
        
        else:
            print("non-defined chunk, skipped.")
print("Sorting complete.")<jupyter_output>Image height (Pixels):	 18175
Image width (Pixels):	 7167
Image channels:		 4
----------------------------------
Processing square  1
non-defined chunk, skipped.
Processing square  2
non-defined chunk, skipped.
Processing square  3
non-defined chunk, skipped.
Processing square  4
non-defined chunk, skipped.
Processing square  5
non-defined chunk, skipped.
Processing square  6
non-defined chunk, skipped.
Processing square  7
non-defined chunk, skipped.
Processing square  8
non-defined chunk, skipped.
Processing square  9
non-defined chunk, skipped.
Processing square  10
non-defined chunk, skipped.
Processing square  11
non-defined chunk, skipped.
Processing square  12
non-defined chunk, skipped.
Processing square  13
non-defined chunk, skipped.
Processing square  14
non-defined chunk, skipped.
Processing square  15
non-defined chunk, skipped.
Processing square  16
non-defined chunk, skipped.
Processing square  17
non-defined chunk, skipped.
Processing square  18
non-defined chunk, skipp[...]
{'fraction_non_alphanumeric': 0.1531088719587122, 'fraction_numerical': 0.02908167444908659, 'mean_word_length': 4.504057709648332, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '307373', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 4675, 'n_tokens_neox': 4422, 'n_words': 897, 'path': 'Orthomosaic_to_dataset/Image_splitter.ipynb', 'repo_name': 'Decclo/Ecobotix---Locating-Stresses-Of-Plants-From-A-UAV', 'size': '12207'}