Please remember the code below preprocessing of the image. Here I remove unnecessary part of the image  - 
```
def remove_white_space(image):

    # # Load the input image
    # image = cv2.imread('/kaggle/input/dataset-hand/sample_train/M009/B0.jpg')
    
    try : 
        # Convert the input image to grayscale
        gray_1 = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    except:
        gray_1=image

    # Apply adaptive thresholding to separate the foreground from the background
    thresh_1 = cv2.adaptiveThreshold(gray_1, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)

    # Apply morphological operations to remove small noise regions and fill gaps
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
    closed_1 = cv2.morphologyEx(thresh_1, cv2.MORPH_CLOSE, kernel)

    # Find contours in the preprocessed image
    contours_1, hierarchy_1 = cv2.findContours(closed_1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Select the largest contour as the contour of the handwritten region
    largest_contour_idx_1 = 0
    largest_contour_area_1 = 0
    for i, contour in enumerate(contours_1):
        contour_area = cv2.contourArea(contour)
        if contour_area > largest_contour_area_1:
            largest_contour_area_1 = contour_area
            largest_contour_idx_1 = i
    handwritten_contour_1 = contours_1[largest_contour_idx_1]

    # Estimate the bounding box of the handwritten region
    x1, y1, w1, h1 = cv2.boundingRect(handwritten_contour_1)
    handwritten_region1 = image[y1+30:y1+h1-30, x1+30:x1+w1-30]


    ## 2nd time preprocessing
    try: 
        # Convert the input image to grayscale
        gray_2 = cv2.cvtColor(handwritten_region1, cv2.COLOR_BGR2GRAY)
    except : 
        gray_2 = handwritten_region1

    # Apply adaptive thresholding to separate the foreground from the background
    thresh_2 = cv2.adaptiveThreshold(gray_2, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)

    # Apply morphological operations to remove small noise regions and fill gaps
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
    closed_2 = cv2.morphologyEx(thresh_2, cv2.MORPH_CLOSE, kernel)

    # Find contours in the preprocessed image
    contours_2, hierarchy_2 = cv2.findContours(closed_2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Select the largest contour as the contour of the handwritten region
    largest_contour_idx_2 = 0
    largest_contour_area_2 = 0
    for i, contour in enumerate(contours_2):
        contour_area = cv2.contourArea(contour)
        if contour_area > largest_contour_area_2:
            largest_contour_area_2 = contour_area
            largest_contour_idx_2 = i
    handwritten_contour_2 = contours_2[largest_contour_idx_2]

    # Estimate the bounding box of the handwritten region
    x2, y2, w2, h2 = cv2.boundingRect(handwritten_contour_2)
    handwritten_region2 = handwritten_region1[y2:y2+h2, x2:x2+w2]

    # Final bounding box of the handwritten region
    # handwritten_region3 = handwritten_region1[y1:y1+h1, x1:x1+w2]
    w3=x2+w2
    handwritten_region3 = handwritten_region1[0:0+h1, 0:0+w3]
    
    # Threshold the image
    thresh = cv2.threshold(handwritten_region3, 100, 255, cv2.THRESH_BINARY)[1]

    # Invert the image
    inverted = cv2.bitwise_not(thresh)

    return inverted
``` 
Okay?

My assignment is -
"given 2 images , you have to classify that is written by same person or not if it is same person then output will be 1 else output will be 0".  
For that problem 
I have one folder of dataset . In that folder(dataset) I have 1352 of subfolders, each subfolder define different person's handwritting. each folder have 4 or 5 or 6 handwritting of that person. 
so make a model from scratch , how to read folder and how to make the model .
okay ? 
Is that problem is clear for you , if you have any question tell me?
I give you a hints you can use siamese model for that.
use the above code tp preprocess of each image. After preprocessing, when you make the pairs for the problem you have to pairs closest positive and closest negative images. For that part you can use any advance techniques but if you can not use any advance teniques then use below method. When you are going to pair images make sure that positive images (i.e. in that image text is written by same person) or negative images (i.e. in that image text is written by different person)  width should be less than 600 or grater than 600. use get the size by img.shape[1]. okay? 

I give you an example -
" Suppose subfolder1 has images A0.jpg, A1.jpg, A2.jpg, A3.jpg . You preprocess the image and found the shape of the images like - (100x467), (98x784),(90x675), (105x562). Then you see than 2 image width is greter than 600 and 2 is less than 600. So you can a group of [A0.jpg,A3.jpg] and [A1.jpg, A2.jpg]. 
Suppose subfolder2 has images A0.jpg, A1.jpg, A2.jpg, A3.jpg . You preprocess the image and found the shape of the images like - (100x703), (98x899),(90x512), (105x900). Then you see than 3 image width is greter than 600 and 1 is less than 600. So you can a group of [A0.jpg, A1.jpg, A3.jpg] and [A2.jpg]. 
And when you pair the images you can make positive image (subfolder1/A0.jpg, subfolder1/A3.jpg), (subfolder1/A1.jpg, subfolder1/A2.jpg), (subfolder2/A0.jpg, subfolder2/A1.jpg), (subfolder2/A0.jpg, subfolder2/A3.jpg), (subfolder2/A1.jpg, subfolder2/A3.jpg). 
for negative image : whose width is less than 600 [ (subfolder1/A0.jpg, subfolder2/A0.jpg) or  (subfolder1/A0.jpg, subfolder2/A1.jpg) or (subfolder1/A0.jpg, subfolder2/A3.jpg) {choose any one of them for subfolder1/A0.jpg }, (subfolder1/A3.jpg, subfolder2/A0.jpg) or  (subfolder1/A3.jpg, subfolder2/A1.jpg) or (subfolder1/A3.jpg, subfolder2/A3.jpg){choose any one of them for subfolder1/A3.jpg }] and whose width is grater than 600 [(subfolder1/A1.jpg, subfolder2/A2.jpg){There is only one large image so choose that only}, (subfolder1/A2.jpg, subfolder2/A2.jpg)]. Now combine these two. "