{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":364443,"sourceType":"datasetVersion","datasetId":159035},{"sourceId":2021025,"sourceType":"datasetVersion","datasetId":1209633}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import cv2\nimport numpy as np\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom tensorflow import keras\nimport os\nfrom keras.preprocessing.image import img_to_array\n\n# ---------------------------\n# Data loading and preprocessing\n# ---------------------------\npath = '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/'\n\ndef num(image):\n    val = 0\n    for i in range(len(image)):\n        if image[i] == '(':\n            while True:\n                i += 1\n                if image[i] == ')':\n                    break\n                val = (val * 10) + int(image[i])\n            break\n    return val\n\n# Initialize arrays for benign, normal and malignant tumors, real images and masks.\nX_b, y_b = np.zeros((437, 128, 128, 1)), np.zeros((437, 128, 128, 1))\nX_n, y_n = np.zeros((133, 128, 128, 1)), np.zeros((133, 128, 128, 1))\nX_m, y_m = np.zeros((210, 128, 128, 1)), np.zeros((210, 128, 128, 1))\n\nfor i, tumor_type in enumerate(os.listdir(path)):\n    for image in os.listdir(path + tumor_type + '/'):\n        p = os.path.join(path + tumor_type, image)\n        img = cv2.imread(p, cv2.IMREAD_GRAYSCALE)  # read as grayscale\n\n        img = cv2.resize(img, (128, 128))\n        pil_img = Image.fromarray(img)\n        \n        if image[-5] == ')':  # Real image case\n            if image[0] == 'b':\n                X_b[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'n':\n                X_n[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'm':\n                X_m[num(image) - 1] += img_to_array(pil_img)\n        else:  # Mask image case\n            if image[0] == 'b':\n                y_b[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'n':\n                y_n[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'm':\n                y_m[num(image) - 1] += img_to_array(pil_img)\n\n# Visualize some examples\nplt.figure(figsize=(20,10))\nfor i in range(5):\n    plt.subplot(2,5,i+1)\n    plt.imshow(X_b[i+1], cmap='gray')\n    plt.title('Real Image')\n    plt.axis('off')\nfor i in range(5):\n    plt.subplot(2,5,i+6)\n    plt.imshow(y_b[i+1], cmap='gray')\n    plt.title('Mask Image')\n    plt.axis('off')\nplt.show()\n\n# Create datasets for model training\nX = np.concatenate((X_b, X_n, X_m), axis=0)\ny = np.concatenate((y_b, y_n, y_m), axis=0)\nX /= 255.0\ny /= 255.0\ny[y > 1.0] = 1.0\n\nprint(X.shape, y.shape)\nprint(\"X range:\", X.min(), X.max())\nprint(\"y range:\", y.min(), y.max())\n\n# ---------------------------\n# Visualization of dataset samples\n# ---------------------------\nplt.figure(figsize=(10,30))\ni = 0\nwhile i < 16:\n    x = np.random.randint(0, 780)\n    plt.subplot(8,2,i+1)\n    plt.imshow(X[x], cmap='gray')\n    plt.title('Real Image')\n    plt.axis('off')\n    plt.subplot(8,2,i+2)\n    plt.imshow(y[x], cmap='gray')\n    plt.title('Mask Image')\n    plt.axis('off')\n    i += 2\nplt.show()\n\n# ---------------------------\n# Train-test split for U-Net training\n# ---------------------------\nfrom sklearn.model_selection import train_test_split\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.05, random_state=1)\nprint(\"Train:\", X_train.shape, y_train.shape)\nprint(\"Test:\", X_test.shape, y_test.shape)\n\n# ---------------------------\n# U-Net Model Creation (based on your provided architecture)\n# ---------------------------\nfrom keras.layers import Input, Conv2D, Dropout, Concatenate, MaxPooling2D, Conv2DTranspose\nfrom keras.models import Model\n\n# Contracting path\ninply = Input((128, 128, 1,))\nconv1 = Conv2D(2**6, (3,3), activation='relu', padding='same')(inply)\nconv1 = Conv2D(2**6, (3,3), activation='relu', padding='same')(conv1)\npool1 = MaxPooling2D((2,2), strides=2, padding='same')(conv1)\ndrop1 = Dropout(0.2)(pool1)\n\nconv2 = Conv2D(2**7, (3,3), activation='relu', padding='same')(drop1)\nconv2 = Conv2D(2**7, (3,3), activation='relu', padding='same')(conv2)\npool2 = MaxPooling2D((2,2), strides=2, padding='same')(conv2)\ndrop2 = Dropout(0.2)(pool2)\n\nconv3 = Conv2D(2**8, (3,3), activation='relu', padding='same')(drop2)\nconv3 = Conv2D(2**8, (3,3), activation='relu', padding='same')(conv3)\npool3 = MaxPooling2D((2,2), strides=2, padding='same')(conv3)\ndrop3 = Dropout(0.2)(pool3)\n\nconv4 = Conv2D(2**9, (3,3), activation='relu', padding='same')(drop3)\nconv4 = Conv2D(2**9, (3,3), activation='relu', padding='same')(conv4)\npool4 = MaxPooling2D((2,2), strides=2, padding='same')(conv4)\ndrop4 = Dropout(0.2)(pool4)\n\n# Bottleneck layer\nconvm = Conv2D(2**10, (3,3), activation='relu', padding='same')(drop4)\nconvm = Conv2D(2**10, (3,3), activation='relu', padding='same')(convm)\n\n# Expanding path\ntran5 = Conv2DTranspose(2**9, (2,2), strides=2, padding='valid', activation='relu')(convm)\nconc5 = Concatenate()([tran5, conv4])\nconv5 = Conv2D(2**9, (3,3), activation='relu', padding='same')(conc5)\nconv5 = Conv2D(2**9, (3,3), activation='relu', padding='same')(conv5)\ndrop5 = Dropout(0.1)(conv5)\n\ntran6 = Conv2DTranspose(2**8, (2,2), strides=2, padding='valid', activation='relu')(drop5)\nconc6 = Concatenate()([tran6, conv3])\nconv6 = Conv2D(2**8, (3,3), activation='relu', padding='same')(conc6)\nconv6 = Conv2D(2**8, (3,3), activation='relu', padding='same')(conv6)\ndrop6 = Dropout(0.1)(conv6)\n\ntran7 = Conv2DTranspose(2**7, (2,2), strides=2, padding='valid', activation='relu')(drop6)\nconc7 = Concatenate()([tran7, conv2])\nconv7 = Conv2D(2**7, (3,3), activation='relu', padding='same')(conc7)\nconv7 = Conv2D(2**7, (3,3), activation='relu', padding='same')(conv7)\ndrop7 = Dropout(0.1)(conv7)\n\ntran8 = Conv2DTranspose(2**6, (2,2), strides=2, padding='valid', activation='relu')(drop7)\nconc8 = Concatenate()([tran8, conv1])\nconv8 = Conv2D(2**6, (3,3), activation='relu', padding='same')(conc8)\nconv8 = Conv2D(2**6, (3,3), activation='relu', padding='same')(conv8)\ndrop8 = Dropout(0.1)(conv8)\n\n# Final layer – note: using 'relu' here per your original code,\n# but for binary segmentation you might consider 'sigmoid'\noutly = Conv2D(1, (1,1), activation='relu', padding='same')(drop8)\nmodel = Model(inputs=inply, outputs=outly, name='U-net')\nkeras.utils.plot_model(model, './model_plot.png', show_shapes=True)\n\n# ---------------------------\n# Loss and Training for U-Net\n# ---------------------------\nfrom keras.metrics import MeanIoU\nmodel.compile(loss='mean_squared_error', optimizer=keras.optimizers.Adam(learning_rate=0.00005))\nprint(model.summary())\n\nfrom keras.callbacks import ModelCheckpoint\ncheckp = ModelCheckpoint('./cancer_image_model.h5', monitor='val_loss', save_best_only=True, verbose=1)\n\nhistory = model.fit(X_train, y_train, epochs=100, batch_size=32, validation_data=(X_test, y_test), callbacks=[checkp])\n\nplt.figure(figsize=(20,7))\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.legend(['training loss', 'validation loss'])\nplt.xlabel('Epochs')\nplt.ylabel('Losses')\nplt.title('Losses vs Epochs', fontsize=15)\nplt.show()\n\n# ---------------------------\n# Metaheuristic Threshold Optimization (Simulated Annealing)\n# ---------------------------\n# Define a function to compute the Dice coefficient for a single pair.\ndef dice_coefficient(y_true, y_pred, smooth=1e-6):\n    y_true_f = y_true.flatten()\n    y_pred_f = y_pred.flatten()\n    intersection = np.sum(y_true_f * y_pred_f)\n    return (2. * intersection + smooth) / (np.sum(y_true_f) + np.sum(y_pred_f) + smooth)\n\n# Compute average Dice over the validation set for a given threshold.\ndef compute_average_dice(model, X_val, y_val, threshold):\n    preds = model.predict(X_val)\n    preds_bin = (preds > threshold).astype(np.float32)\n    dice_scores = []\n    for i in range(len(y_val)):\n        dice = dice_coefficient(y_val[i], preds_bin[i])\n        dice_scores.append(dice)\n    return np.mean(dice_scores)\n\ndef optimize_threshold(model, X_val, y_val, init_threshold=0.5, n_iter=50, init_temp=0.1, cooling_rate=0.95):\n    current_threshold = init_threshold\n    current_score = compute_average_dice(model, X_val, y_val, current_threshold)\n    best_threshold = current_threshold\n    best_score = current_score\n    temp = init_temp\n    for i in range(n_iter):\n        new_threshold = current_threshold + np.random.uniform(-0.05, 0.05)\n        new_threshold = np.clip(new_threshold, 0.0, 1.0)\n        new_score = compute_average_dice(model, X_val, y_val, new_threshold)\n        if new_score > current_score:\n            accept = True\n        else:\n            accept_prob = np.exp((new_score - current_score) / temp)\n            accept = np.random.rand() < accept_prob\n        if accept:\n            current_threshold = new_threshold\n            current_score = new_score\n            if new_score > best_score:\n                best_score = new_score\n                best_threshold = new_threshold\n        temp *= cooling_rate\n        print(f\"Iteration {i+1}: Proposed Threshold {new_threshold:.3f}, Dice Score {new_score:.4f}, Best Threshold {best_threshold:.3f} (Score {best_score:.4f})\")\n    return best_threshold, best_score\n\n# Optimize threshold on the U-Net validation set (X_test, y_test)\n# Note: if desired, you could further split X_test/y_test for threshold optimization.\nfrom keras.models import load_model\nlocalize = load_model('./cancer_image_model.h5')\nbest_threshold, best_dice = optimize_threshold(localize, X_test, y_test, init_threshold=0.5, n_iter=50, init_temp=0.1, cooling_rate=0.95)\nprint(f\"Optimized Threshold: {best_threshold:.3f}, Best Average Dice: {best_dice:.4f}\")\n\n# ---------------------------\n# U-Net Predictions with Optimized Threshold\n# ---------------------------\ny_pred = localize.predict(X_test)\n# Binarize predictions using the optimized threshold:\ny_pred_bin = (y_pred > best_threshold).astype(np.float32)\n\nprint(\"Prediction shape:\", y_pred_bin.shape)\n\nplt.figure(figsize=(20,80))\ni = 0\nx = 0\nwhile i < 45:\n    plt.subplot(15,3,i+1)\n    plt.imshow(X_test[x], cmap='gray')\n    plt.title('Real Medical Image')\n    plt.axis('off')\n    plt.subplot(15,3,i+2)\n    plt.imshow(y_test[x], cmap='gray')\n    plt.title('Ground Truth')\n    plt.axis('off')\n    plt.subplot(15,3,i+3)\n    plt.imshow(y_pred_bin[x], cmap='gray')\n    plt.title('Predicted Mask')\n    plt.axis('off')\n    x += 1\n    i += 3\nplt.show()\n\n# ---------------------------\n# Classifier (using the predicted masks)\n# ---------------------------\ninfo = ['benign', 'normal', 'malignant']\n\n# Create datasets for classification from original images (without masks)\nX_cls = []\ny_cls = []\nlabel_num = -1\nfor label_class in os.listdir(path):\n    new_path = path + label_class\n    label_num += 1\n    for img in os.listdir(new_path):\n        if 'mask' not in img:\n            y_cls.append(label_num)\n            x_img = cv2.imread(new_path + '/' + img, cv2.IMREAD_GRAYSCALE)\n            X_cls.append(img_to_array(Image.fromarray(cv2.resize(x_img, (128,128)))))\n\nX_cls = np.array(X_cls)\ny_cls = np.array(y_cls)\nX_cls /= 255.0\nfrom keras.utils import to_categorical\ny_cls = to_categorical(y_cls)\nprint(X_cls.shape, y_cls.shape)\n\nplt.imshow(X_cls[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Load the U-Net model to predict masks for classification\nlocalize = load_model('./cancer_image_model.h5')\nM = localize.predict(X_cls)\nprint(\"Mask prediction range:\", M.min(), M.max())\n\nplt.imshow(M[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Data distribution visualization\nimport pandas\nimport seaborn\nseaborn.histplot(data=pandas.DataFrame({'id': [info[p] for p in np.argmax(y_cls, axis=1)]}), x='id')\nplt.title('Distribution of Classes', fontsize=15)\nplt.show()\n\n# Train-test split for classification\nfrom sklearn.model_selection import train_test_split\nX_train_cls, X_test_cls, y_train_cls, y_test_cls = train_test_split(M, y_cls, test_size=0.1, shuffle=True, random_state=1)\nprint(X_train_cls.shape, y_train_cls.shape)\nprint(X_test_cls.shape, y_test_cls.shape)\n\n# Visualize some classification training samples\nfrom numpy.random import randint\nplt.figure(figsize=(20,20))\ni = 0\nSIZE = X_train_cls.shape[0]\nwhile i < 25:\n    x_rand = randint(0, SIZE)\n    plt.subplot(5,5,i+1)\n    plt.imshow(X_train_cls[x_rand], cmap='gray')\n    plt.title(f'{info[np.argmax(y_train_cls[x_rand])]}', fontsize=15)\n    plt.axis('off')\n    i += 1\nplt.show()\n\n# Data augmentation for classifier\nfrom keras.preprocessing.image import ImageDataGenerator\ntrain_gen = ImageDataGenerator(horizontal_flip=True, rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, zoom_range=[0.80, 1.00])\ntrain_gen.fit(X_train_cls)\npointer = train_gen.flow(X_train_cls, y_train_cls)\ntrainX, trainy = pointer.next()\n\nplt.figure(figsize=(20,20))\ni = 0\nwhile i < 25:\n    plt.subplot(5,5,i+1)\n    plt.imshow(trainX[i], cmap='gray')\n    plt.title(f'{info[np.argmax(trainy[i])]}', fontsize=15)\n    plt.axis('off')\n    i += 1\nplt.show()\n\n# Define CNN classifier model\nfrom keras.layers import BatchNormalization, Flatten, Dense, LeakyReLU\nfrom keras.models import Sequential\nfrom keras.optimizers import Adam\n\ndef conv_block(filterx):\n    model = Sequential()\n    model.add(Conv2D(filterx, (3,3), strides=1, padding='same', kernel_regularizer='l2'))\n    model.add(BatchNormalization())\n    model.add(Dropout(0.2))\n    model.add(LeakyReLU())\n    model.add(MaxPooling2D())\n    return model\n\ndef dens_block(hiddenx):\n    model = Sequential()\n    model.add(Dense(hiddenx, kernel_regularizer='l2'))\n    model.add(BatchNormalization())\n    model.add(Dropout(0.2))\n    model.add(LeakyReLU())\n    return model\n\ndef cnn(filter1, filter2, filter3, filter4, hidden1):\n    model = Sequential([\n        Input((128,128,1,)),\n        conv_block(filter1),\n        conv_block(filter2),\n        conv_block(filter3),\n        conv_block(filter4),\n        Flatten(),\n        dens_block(hidden1),\n        Dense(3, activation='softmax')\n    ])\n    model.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.0005), metrics=['accuracy'])\n    return model\n\nclassifier = cnn(32, 64, 128, 256, 32)\nclassifier.summary()\n\nfrom keras.utils import plot_model\nplot_model(classifier, 'cancer_classify.png', show_shapes=True)\n\n# Train the classifier\nfrom keras.callbacks import ModelCheckpoint\ncheckp_cls = ModelCheckpoint('./valid_classifier.h5', monitor='val_loss', save_best_only=True, verbose=1)\nhistory_cls = classifier.fit(train_gen.flow(X_train_cls, y_train_cls, batch_size=64), epochs=400, validation_data=(X_test_cls, y_test_cls), callbacks=[checkp_cls])\n\nplt.figure(figsize=(20,5))\nplt.plot(history_cls.history['loss'])\nplt.plot(history_cls.history['val_loss'])\nplt.legend(['training_loss', 'validation_loss'])\nplt.xlabel('Epochs')\nplt.ylabel('Losses')\nplt.title('Classifier Loss vs Epochs', fontsize=15)\nplt.show()\n\n# Evaluate classifier performance\nfrom sklearn.metrics import accuracy_score, confusion_matrix, classification_report\nclassifier = keras.models.load_model('./valid_classifier.h5')\ny_pred_cls = classifier.predict(X_test_cls)\ny_pred_cls = np.argmax(y_pred_cls, axis=1)\ny_test_cls_labels = np.argmax(y_test_cls, axis=1)\n\nprint('Accuracy :', accuracy_score(y_test_cls_labels, y_pred_cls))\nprint(classification_report(y_test_cls_labels, y_pred_cls, target_names=info))\n\ncm = confusion_matrix(y_test_cls_labels, y_pred_cls)\nplt.figure(figsize=(12,12))\nax = seaborn.heatmap(cm, cmap=plt.cm.Greens, annot=True, square=True, xticklabels=info, yticklabels=info)\nax.set_ylabel('Actual', fontsize=40)\nax.set_xlabel('Predicted', fontsize=40)\nplt.show()\n\n# ---------------------------\n# Overall Task: Mask Prediction then Classification\n# ---------------------------\nimage_path = [\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (110).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (100).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (101).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (107).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/normal/normal (101).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/normal/normal (111).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/normal/normal (106).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/malignant/malignant (115).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/malignant/malignant (111).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/malignant/malignant (110).png',\n]\n\n# Load models\nclassifier = keras.models.load_model('./valid_classifier.h5')\nlocalize = keras.models.load_model('./cancer_image_model.h5')\n\n# Load test images\ntestX = []\nfor img in image_path:\n    testX.append(img_to_array(Image.fromarray(cv2.resize(cv2.imread(img, cv2.IMREAD_GRAYSCALE), (128,128)))))\ntestX = np.array(testX)\ntestX /= 255.0\n\nprint(testX.shape)\nprint(f'Minimum : {testX.min()}')\nprint(f'Maximum : {testX.max()}')\n\nplt.imshow(testX[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Predict mask and optionally binarize using optimized threshold\npredY = localize.predict(testX)\npredY_bin = (predY > best_threshold).astype(np.float32)\n\nplt.imshow(predY_bin[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Use the predicted (or binarized) mask for classification\npred_label = classifier.predict(predY_bin)\nprint(np.argmax(pred_label, axis=1))\n\nplt.figure(figsize=(10,40))\ni = 0\nj = 0\nwhile i < 20:\n    plt.subplot(10,2,i+1)\n    plt.imshow(testX[j], cmap='gray')\n    plt.title('Original Image', fontsize=15)\n    plt.axis('off')\n    plt.subplot(10,2,i+2)\n    plt.imshow(predY_bin[j], cmap='gray')\n    plt.title(f'{info[np.argmax(pred_label[j])]}', fontsize=15)\n    plt.axis('off')\n    j += 1\n    i += 2\nplt.show()\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-03-12T17:26:21.802435Z","iopub.execute_input":"2025-03-12T17:26:21.802932Z","iopub.status.idle":"2025-03-12T17:26:35.600802Z","shell.execute_reply.started":"2025-03-12T17:26:21.802892Z","shell.execute_reply":"2025-03-12T17:26:35.599001Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom tensorflow import keras\nimport os\nfrom keras.preprocessing.image import img_to_array\n\n# ---------------------------\n# Data loading and preprocessing\n# ---------------------------\npath = '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/'\n\ndef num(image):\n    val = 0\n    for i in range(len(image)):\n        if image[i] == '(':\n            while True:\n                i += 1\n                if image[i] == ')':\n                    break\n                val = (val * 10) + int(image[i])\n            break\n    return val\n\n# Initialize arrays for benign, normal and malignant tumors, for real images and their masks.\nX_b, y_b = np.zeros((437, 128, 128, 1)), np.zeros((437, 128, 128, 1))\nX_n, y_n = np.zeros((133, 128, 128, 1)), np.zeros((133, 128, 128, 1))\nX_m, y_m = np.zeros((210, 128, 128, 1)), np.zeros((210, 128, 128, 1))\n\nfor i, tumor_type in enumerate(os.listdir(path)):\n    for image in os.listdir(path + tumor_type + '/'):\n        p = os.path.join(path + tumor_type, image)\n        img = cv2.imread(p, cv2.IMREAD_GRAYSCALE)  # read as grayscale\n        img = cv2.resize(img, (128, 128))\n        pil_img = Image.fromarray(img)\n        \n        # The naming convention distinguishes real images vs. masks.\n        if image[-5] == ')':  # Real image case\n            if image[0] == 'b':\n                X_b[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'n':\n                X_n[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'm':\n                X_m[num(image) - 1] += img_to_array(pil_img)\n        else:  # Mask image case\n            if image[0] == 'b':\n                y_b[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'n':\n                y_n[num(image) - 1] += img_to_array(pil_img)\n            if image[0] == 'm':\n                y_m[num(image) - 1] += img_to_array(pil_img)\n\n# Visualize a few examples of real images and corresponding masks\nplt.figure(figsize=(20,10))\nfor i in range(5):\n    plt.subplot(2,5,i+1)\n    plt.imshow(X_b[i+1], cmap='gray')\n    plt.title('Real Image')\n    plt.axis('off')\nfor i in range(5):\n    plt.subplot(2,5,i+6)\n    plt.imshow(y_b[i+1], cmap='gray')\n    plt.title('Mask Image')\n    plt.axis('off')\nplt.show()\n\n# Create combined datasets for training the U-Net\nX = np.concatenate((X_b, X_n, X_m), axis=0)\ny = np.concatenate((y_b, y_n, y_m), axis=0)\nX /= 255.0\ny /= 255.0\ny[y > 1.0] = 1.0\n\nprint(\"Dataset shapes:\", X.shape, y.shape)\nprint(\"X range:\", X.min(), X.max())\nprint(\"y range:\", y.min(), y.max())\n\n# ---------------------------\n# Visualization of dataset samples\n# ---------------------------\nplt.figure(figsize=(10,30))\ni = 0\nwhile i < 16:\n    idx = np.random.randint(0, X.shape[0])\n    plt.subplot(8,2,i+1)\n    plt.imshow(X[idx], cmap='gray')\n    plt.title('Real Image')\n    plt.axis('off')\n    plt.subplot(8,2,i+2)\n    plt.imshow(y[idx], cmap='gray')\n    plt.title('Mask Image')\n    plt.axis('off')\n    i += 2\nplt.show()\n\n# ---------------------------\n# Train-test split for U-Net training\n# ---------------------------\nfrom sklearn.model_selection import train_test_split\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.05, random_state=1)\nprint(\"Train shapes:\", X_train.shape, y_train.shape)\nprint(\"Test shapes:\", X_test.shape, y_test.shape)\n\n# ---------------------------\n# U-Net Model Creation\n# ---------------------------\nfrom keras.layers import Input, Conv2D, Dropout, Concatenate, MaxPooling2D, Conv2DTranspose\nfrom keras.models import Model\n\n# Contracting path\ninply = Input((128, 128, 1,))\nconv1 = Conv2D(2**6, (3,3), activation='relu', padding='same')(inply)\nconv1 = Conv2D(2**6, (3,3), activation='relu', padding='same')(conv1)\npool1 = MaxPooling2D((2,2), strides=2, padding='same')(conv1)\ndrop1 = Dropout(0.2)(pool1)\n\nconv2 = Conv2D(2**7, (3,3), activation='relu', padding='same')(drop1)\nconv2 = Conv2D(2**7, (3,3), activation='relu', padding='same')(conv2)\npool2 = MaxPooling2D((2,2), strides=2, padding='same')(conv2)\ndrop2 = Dropout(0.2)(pool2)\n\nconv3 = Conv2D(2**8, (3,3), activation='relu', padding='same')(drop2)\nconv3 = Conv2D(2**8, (3,3), activation='relu', padding='same')(conv3)\npool3 = MaxPooling2D((2,2), strides=2, padding='same')(conv3)\ndrop3 = Dropout(0.2)(pool3)\n\nconv4 = Conv2D(2**9, (3,3), activation='relu', padding='same')(drop3)\nconv4 = Conv2D(2**9, (3,3), activation='relu', padding='same')(conv4)\npool4 = MaxPooling2D((2,2), strides=2, padding='same')(conv4)\ndrop4 = Dropout(0.2)(pool4)\n\n# Bottleneck layer\nconvm = Conv2D(2**10, (3,3), activation='relu', padding='same')(drop4)\nconvm = Conv2D(2**10, (3,3), activation='relu', padding='same')(convm)\n\n# Expanding path\ntran5 = Conv2DTranspose(2**9, (2,2), strides=2, padding='valid', activation='relu')(convm)\nconc5 = Concatenate()([tran5, conv4])\nconv5 = Conv2D(2**9, (3,3), activation='relu', padding='same')(conc5)\nconv5 = Conv2D(2**9, (3,3), activation='relu', padding='same')(conv5)\ndrop5 = Dropout(0.1)(conv5)\n\ntran6 = Conv2DTranspose(2**8, (2,2), strides=2, padding='valid', activation='relu')(drop5)\nconc6 = Concatenate()([tran6, conv3])\nconv6 = Conv2D(2**8, (3,3), activation='relu', padding='same')(conc6)\nconv6 = Conv2D(2**8, (3,3), activation='relu', padding='same')(conv6)\ndrop6 = Dropout(0.1)(conv6)\n\ntran7 = Conv2DTranspose(2**7, (2,2), strides=2, padding='valid', activation='relu')(drop6)\nconc7 = Concatenate()([tran7, conv2])\nconv7 = Conv2D(2**7, (3,3), activation='relu', padding='same')(conc7)\nconv7 = Conv2D(2**7, (3,3), activation='relu', padding='same')(conv7)\ndrop7 = Dropout(0.1)(conv7)\n\ntran8 = Conv2DTranspose(2**6, (2,2), strides=2, padding='valid', activation='relu')(drop7)\nconc8 = Concatenate()([tran8, conv1])\nconv8 = Conv2D(2**6, (3,3), activation='relu', padding='same')(conc8)\nconv8 = Conv2D(2**6, (3,3), activation='relu', padding='same')(conv8)\ndrop8 = Dropout(0.1)(conv8)\n\n# Final layer – note: using 'relu' here as in your original code.\noutly = Conv2D(1, (1,1), activation='relu', padding='same')(drop8)\nmodel = Model(inputs=inply, outputs=outly, name='U-net')\n\n# Uncomment the next line if Graphviz is installed; otherwise you can comment it out.\nkeras.utils.plot_model(model, './model_plot.png', show_shapes=True)\n\n# ---------------------------\n# Loss and Training for U-Net\n# ---------------------------\nfrom keras.metrics import MeanIoU\nmodel.compile(loss='mean_squared_error', optimizer=keras.optimizers.Adam(learning_rate=0.00005))\nprint(model.summary())\n\nfrom keras.callbacks import ModelCheckpoint\ncheckp = ModelCheckpoint('./cancer_image_model.h5', monitor='val_loss', save_best_only=True, verbose=1)\n\nhistory = model.fit(X_train, y_train, epochs=100, batch_size=32, validation_data=(X_test, y_test), callbacks=[checkp])\n\nplt.figure(figsize=(20,7))\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.legend(['training loss', 'validation loss'])\nplt.xlabel('Epochs')\nplt.ylabel('Losses')\nplt.title('Losses vs Epochs', fontsize=15)\nplt.show()\n\n# ---------------------------\n# Metaheuristic Threshold Optimization (Simulated Annealing)\n# ---------------------------\n# Function to compute the Dice coefficient for a single pair.\ndef dice_coefficient(y_true, y_pred, smooth=1e-6):\n    y_true_f = y_true.flatten()\n    y_pred_f = y_pred.flatten()\n    intersection = np.sum(y_true_f * y_pred_f)\n    return (2. * intersection + smooth) / (np.sum(y_true_f) + np.sum(y_pred_f) + smooth)\n\n# Function to compute average Dice over the validation set for a given threshold.\ndef compute_average_dice(model, X_val, y_val, threshold):\n    preds = model.predict(X_val)\n    preds_bin = (preds > threshold).astype(np.float32)\n    dice_scores = []\n    for i in range(len(y_val)):\n        dice = dice_coefficient(y_val[i], preds_bin[i])\n        dice_scores.append(dice)\n    return np.mean(dice_scores)\n\ndef optimize_threshold(model, X_val, y_val, init_threshold=0.5, n_iter=50, init_temp=0.1, cooling_rate=0.95):\n    current_threshold = init_threshold\n    current_score = compute_average_dice(model, X_val, y_val, current_threshold)\n    best_threshold = current_threshold\n    best_score = current_score\n    temp = init_temp\n    for i in range(n_iter):\n        new_threshold = current_threshold + np.random.uniform(-0.05, 0.05)\n        new_threshold = np.clip(new_threshold, 0.0, 1.0)\n        new_score = compute_average_dice(model, X_val, y_val, new_threshold)\n        if new_score > current_score:\n            accept = True\n        else:\n            accept_prob = np.exp((new_score - current_score) / temp)\n            accept = np.random.rand() < accept_prob\n        if accept:\n            current_threshold = new_threshold\n            current_score = new_score\n            if new_score > best_score:\n                best_score = new_score\n                best_threshold = new_threshold\n        temp *= cooling_rate\n        print(f\"Iteration {i+1}: Proposed Threshold {new_threshold:.3f}, Dice Score {new_score:.4f}, Best Threshold {best_threshold:.3f} (Score {best_score:.4f})\")\n    return best_threshold, best_score\n\n# Reload the best U-Net model\nfrom keras.models import load_model\nlocalize = load_model('./cancer_image_model.h5')\n\n# Optimize threshold on the U-Net validation set (X_test, y_test)\nbest_threshold, best_dice = optimize_threshold(localize, X_test, y_test, init_threshold=0.5, n_iter=50, init_temp=0.1, cooling_rate=0.95)\nprint(f\"Optimized Threshold: {best_threshold:.3f}, Best Average Dice: {best_dice:.4f}\")\n\n# ---------------------------\n# Compare Default vs. Optimized Threshold Performance\n# ---------------------------\n# Compute the average Dice score using the default threshold (0.5)\ndefault_threshold = 0.5\ndefault_dice = compute_average_dice(localize, X_test, y_test, default_threshold)\nprint(\"Default Threshold (0.5) Average Dice Score: {:.4f}\".format(default_dice))\nprint(\"Optimized Threshold: {:.3f} with Average Dice Score: {:.4f}\".format(best_threshold, best_dice))\n\n# ---------------------------\n# Visualize Predictions Side by Side\n# ---------------------------\n# Obtain predictions using both thresholds\ny_pred = localize.predict(X_test)\ny_pred_default = (y_pred > default_threshold).astype(np.float32)\ny_pred_optimized = (y_pred > best_threshold).astype(np.float32)\n\nnum_images = 3  # Number of samples to display\nplt.figure(figsize=(15, 5 * num_images))\nfor i in range(num_images):\n    # Original Input Image\n    plt.subplot(num_images, 3, i*3 + 1)\n    plt.imshow(X_test[i].squeeze(), cmap='gray')\n    plt.title(\"Input Image\")\n    plt.axis('off')\n    \n    # Prediction with Default Threshold (0.5)\n    plt.subplot(num_images, 3, i*3 + 2)\n    plt.imshow(y_pred_default[i].squeeze(), cmap='gray')\n    plt.title(\"Prediction (Th=0.5)\")\n    plt.axis('off')\n    \n    # Prediction with Optimized Threshold\n    plt.subplot(num_images, 3, i*3 + 3)\n    plt.imshow(y_pred_optimized[i].squeeze(), cmap='gray')\n    plt.title(\"Prediction (Th={:.2f})\".format(best_threshold))\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show()\n\n# ---------------------------\n# Classification Section (Using Predicted Masks)\n# ---------------------------\ninfo = ['benign', 'normal', 'malignant']\n\n# Create datasets for classification from original images (without masks)\nX_cls = []\ny_cls = []\nlabel_num = -1\nfor label_class in os.listdir(path):\n    new_path = path + label_class\n    label_num += 1\n    for img in os.listdir(new_path):\n        if 'mask' not in img:\n            y_cls.append(label_num)\n            x_img = cv2.imread(new_path + '/' + img, cv2.IMREAD_GRAYSCALE)\n            X_cls.append(img_to_array(Image.fromarray(cv2.resize(x_img, (128,128)))))\n\nX_cls = np.array(X_cls)\ny_cls = np.array(y_cls)\nX_cls /= 255.0\nfrom keras.utils import to_categorical\ny_cls = to_categorical(y_cls)\nprint(\"Classification dataset shapes:\", X_cls.shape, y_cls.shape)\n\nplt.imshow(X_cls[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Load the U-Net model to predict masks for classification\nlocalize = load_model('./cancer_image_model.h5')\nM = localize.predict(X_cls)\nprint(\"Mask prediction range:\", M.min(), M.max())\n\nplt.imshow(M[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Data distribution visualization\nimport pandas\nimport seaborn\nseaborn.histplot(data=pandas.DataFrame({'id': [info[p] for p in np.argmax(y_cls, axis=1)]}), x='id')\nplt.title('Distribution of Classes', fontsize=15)\nplt.show()\n\n# Train-test split for classification\nfrom sklearn.model_selection import train_test_split\nX_train_cls, X_test_cls, y_train_cls, y_test_cls = train_test_split(M, y_cls, test_size=0.1, shuffle=True, random_state=1)\nprint(\"Classification Train shapes:\", X_train_cls.shape, y_train_cls.shape)\nprint(\"Classification Test shapes:\", X_test_cls.shape, y_test_cls.shape)\n\n# Visualize some classification training samples\nfrom numpy.random import randint\nplt.figure(figsize=(20,20))\ni = 0\nSIZE = X_train_cls.shape[0]\nwhile i < 25:\n    x_rand = randint(0, SIZE)\n    plt.subplot(5,5,i+1)\n    plt.imshow(X_train_cls[x_rand], cmap='gray')\n    plt.title(f'{info[np.argmax(y_train_cls[x_rand])]}', fontsize=15)\n    plt.axis('off')\n    i += 1\nplt.show()\n\n# Data augmentation for classifier\nfrom keras.preprocessing.image import ImageDataGenerator\ntrain_gen = ImageDataGenerator(horizontal_flip=True, rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, zoom_range=[0.80, 1.00])\ntrain_gen.fit(X_train_cls)\npointer = train_gen.flow(X_train_cls, y_train_cls)\ntrainX, trainy = pointer.next()\n\nplt.figure(figsize=(20,20))\ni = 0\nwhile i < 25:\n    plt.subplot(5,5,i+1)\n    plt.imshow(trainX[i], cmap='gray')\n    plt.title(f'{info[np.argmax(trainy[i])]}', fontsize=15)\n    plt.axis('off')\n    i += 1\nplt.show()\n\n# Define CNN classifier model\nfrom keras.layers import BatchNormalization, Flatten, Dense, LeakyReLU\nfrom keras.models import Sequential\nfrom keras.optimizers import Adam\n\ndef conv_block(filterx):\n    model = Sequential()\n    model.add(Conv2D(filterx, (3,3), strides=1, padding='same', kernel_regularizer='l2'))\n    model.add(BatchNormalization())\n    model.add(Dropout(0.2))\n    model.add(LeakyReLU())\n    model.add(MaxPooling2D())\n    return model\n\ndef dens_block(hiddenx):\n    model = Sequential()\n    model.add(Dense(hiddenx, kernel_regularizer='l2'))\n    model.add(BatchNormalization())\n    model.add(Dropout(0.2))\n    model.add(LeakyReLU())\n    return model\n\ndef cnn(filter1, filter2, filter3, filter4, hidden1):\n    model = Sequential([\n        Input((128,128,1,)),\n        conv_block(filter1),\n        conv_block(filter2),\n        conv_block(filter3),\n        conv_block(filter4),\n        Flatten(),\n        dens_block(hidden1),\n        Dense(3, activation='softmax')\n    ])\n    model.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.0005), metrics=['accuracy'])\n    return model\n\nclassifier = cnn(32, 64, 128, 256, 32)\nclassifier.summary()\n\nfrom keras.utils import plot_model\nplot_model(classifier, 'cancer_classify.png', show_shapes=True)\n\n# Train the classifier\nfrom keras.callbacks import ModelCheckpoint\ncheckp_cls = ModelCheckpoint('./valid_classifier.h5', monitor='val_loss', save_best_only=True, verbose=1)\nhistory_cls = classifier.fit(train_gen.flow(X_train_cls, y_train_cls, batch_size=64), epochs=400, validation_data=(X_test_cls, y_test_cls), callbacks=[checkp_cls])\n\nplt.figure(figsize=(20,5))\nplt.plot(history_cls.history['loss'])\nplt.plot(history_cls.history['val_loss'])\nplt.legend(['training_loss', 'validation_loss'])\nplt.xlabel('Epochs')\nplt.ylabel('Losses')\nplt.title('Classifier Loss vs Epochs', fontsize=15)\nplt.show()\n\n# Evaluate classifier performance\nfrom sklearn.metrics import accuracy_score, confusion_matrix, classification_report\nclassifier = keras.models.load_model('./valid_classifier.h5')\ny_pred_cls = classifier.predict(X_test_cls)\ny_pred_cls = np.argmax(y_pred_cls, axis=1)\ny_test_cls_labels = np.argmax(y_test_cls, axis=1)\n\nprint('Classifier Accuracy :', accuracy_score(y_test_cls_labels, y_pred_cls))\nprint(classification_report(y_test_cls_labels, y_pred_cls, target_names=info))\n\ncm = confusion_matrix(y_test_cls_labels, y_pred_cls)\nplt.figure(figsize=(12,12))\nax = seaborn.heatmap(cm, cmap=plt.cm.Greens, annot=True, square=True, xticklabels=info, yticklabels=info)\nax.set_ylabel('Actual', fontsize=40)\nax.set_xlabel('Predicted', fontsize=40)\nplt.show()\n\n# ---------------------------\n# Overall Task: Mask Prediction then Classification\n# ---------------------------\nimage_path = [\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (110).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (100).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (101).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/benign/benign (107).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/normal/normal (101).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/normal/normal (111).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/normal/normal (106).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/malignant/malignant (115).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/malignant/malignant (111).png',\n    '../input/breast-ultrasound-images-dataset/Dataset_BUSI_with_GT/malignant/malignant (110).png',\n]\n\n# Load models\nclassifier = keras.models.load_model('./valid_classifier.h5')\nlocalize = keras.models.load_model('./cancer_image_model.h5')\n\n# Load test images for overall task\ntestX = []\nfor img in image_path:\n    testX.append(img_to_array(Image.fromarray(cv2.resize(cv2.imread(img, cv2.IMREAD_GRAYSCALE), (128,128)))))\ntestX = np.array(testX)\ntestX /= 255.0\n\nprint(\"Test images shape:\", testX.shape)\nprint(f'Minimum: {testX.min()}')\nprint(f'Maximum: {testX.max()}')\n\nplt.imshow(testX[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Predict mask and binarize using optimized threshold\npredY = localize.predict(testX)\npredY_bin = (predY > best_threshold).astype(np.float32)\n\nplt.imshow(predY_bin[0], cmap='gray')\nplt.axis('off')\nplt.show()\n\n# Use the predicted mask for classification\npred_label = classifier.predict(predY_bin)\nprint(\"Predicted Class Labels:\", np.argmax(pred_label, axis=1))\n\nplt.figure(figsize=(10,40))\ni = 0\nj = 0\nwhile i < 20:\n    plt.subplot(10,2,i+1)\n    plt.imshow(testX[j], cmap='gray')\n    plt.title('Original Image', fontsize=15)\n    plt.axis('off')\n    plt.subplot(10,2,i+2)\n    plt.imshow(predY_bin[j], cmap='gray')\n    plt.title(f'{info[np.argmax(pred_label[j])]}', fontsize=15)\n    plt.axis('off')\n    j += 1\n    i += 2\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-12T17:43:04.142040Z","iopub.execute_input":"2025-03-12T17:43:04.142475Z","iopub.status.idle":"2025-03-12T17:43:19.022152Z","shell.execute_reply.started":"2025-03-12T17:43:04.142445Z","shell.execute_reply":"2025-03-12T17:43:19.020484Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}