{"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":"gpu","dataSources":[{"sourceId":61446,"databundleVersionId":6962461,"sourceType":"competition"},{"sourceId":7386499,"sourceType":"datasetVersion","datasetId":4293370}],"dockerImageVersionId":30636,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!rm -rf /kaggle/working/*\n\nimport cv2\nimport gc\nimport matplotlib.pyplot as plot\nimport numpy as np\nimport pandas as pd\nimport pickle\nimport tensorflow as tf\n\nfrom collections import deque\nfrom glob import glob\nfrom itertools import starmap\n\n\n# https://www.kaggle.com/code/adaluodao/inference-1024-ensemble-512-1024を参考にしました。\n\nCLIP_MIN_RATIO = 0  # 0.001\nCLIP_MAX_RATIO = 0  # 0.001\nCANDIDATE_RATIO = 0.005\nBLOCK_THRESHOLD = 100\n\nPATCH_WIDTH = 128\nPATCH_HEIGHT = 128\nPATCH_DEPTH = 32\n\n\nmodel = tf.keras.models.load_model('../input/models/model-0.h5')\n\n\ndef rle_encode(img):\n    pixels = img.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\n\ndef submit(data_folder_path, submission_file):\n    data_paths = tuple(sorted(glob(f\"{data_folder_path}/images/*.tif\")))\n\n    depth = len(data_paths)\n    height, width = np.shape(cv2.imread(data_paths[0], cv2.IMREAD_GRAYSCALE))\n\n    def get_min_max():\n        values = np.zeros((depth, height, width), dtype=np.uint8)\n        for i in range(depth):\n            values[i] = cv2.imread(data_paths[i], cv2.IMREAD_GRAYSCALE)\n\n        values = np.ravel(values)\n        index_min = int((len(values) - 1) * CLIP_MIN_RATIO)\n        index_max = int((len(values) - 1) * (1 - CLIP_MAX_RATIO))\n\n        return np.partition(values, index_min)[index_min] / 255, np.partition(values, index_max)[index_max] / 255\n\n    min, max = get_min_max()\n    print(f\"depth = {depth}\\theight = {height}\\twidth = {width}\\tmin = {min}\\tmax = {max}\")\n\n    def get_predict():\n        result = np.zeros(tuple(starmap(lambda patch_size, size: int(patch_size * np.ceil(size / patch_size)),\n                                        ((PATCH_DEPTH, depth), (PATCH_HEIGHT, height), (PATCH_WIDTH, width)))),\n                          dtype=np.uint16)\n\n        for i in range(0, depth, PATCH_DEPTH):\n            print(f\"z = {i}\")\n            volumetric_image = np.stack(tuple(map(lambda path: (cv2.imread(path, cv2.IMREAD_GRAYSCALE) / 256).astype(np.float32) if path is not None else np.zeros((height, width), dtype=np.float32),\n                                                  map(lambda index: data_paths[index] if index < depth else None,\n                                                      range(i, i + PATCH_DEPTH)))))\n            volumetric_image = np.pad(volumetric_image, ((0, PATCH_DEPTH - np.shape(volumetric_image)[0]), (0, np.shape(result)[1] - np.shape(volumetric_image)[1]), (0, np.shape(result)[2] - np.shape(volumetric_image)[2])))\n\n            # クリッピング\n            volumetric_image[volumetric_image > max] = max\n            volumetric_image[volumetric_image < min] = min\n\n            # 正則化\n            volumetric_image = (volumetric_image - min) / (max - min)\n\n            for j in range(0, height, PATCH_HEIGHT):\n                for k in range(0, width, PATCH_WIDTH):\n                    x = np.reshape(volumetric_image[:, j: j + PATCH_HEIGHT, k: k + PATCH_WIDTH], (1, PATCH_DEPTH, PATCH_HEIGHT, PATCH_WIDTH, 1))\n                    y = model.predict_on_batch(x)\n\n                    result[i: i + PATCH_DEPTH, j: j + PATCH_HEIGHT, k: k + PATCH_WIDTH] = np.reshape((y * 65535).astype(np.uint16), (PATCH_DEPTH, PATCH_HEIGHT, PATCH_WIDTH))\n\n                    del y, x\n                    gc.collect()\n\n            del volumetric_image\n            gc.collect()\n\n        return result[0: depth, 0: height, 0: width]\n\n    def get_candidate(predict):\n        values = np.ravel(predict)\n        index = int((len(values) - 1) * CANDIDATE_RATIO)\n        threshold = np.partition(values, -index)[-index]\n        \n        result = predict >= threshold\n\n        print(f\"threshold = {threshold / 65535}\\tratio = {np.count_nonzero(result) / (depth * height * width)}\")\n\n        return result\n    \n    def get_blood_vessel(candidate):\n        checked = np.zeros((depth, height, width), dtype=np.uint8)\n        deltas = tuple(filter(lambda x: x != (0, 0, 0),\n                              map(lambda x: (x[0] - 1, x[1] - 1, x[2] - 1),\n                                  zip(*np.where(np.ones((3, 3, 3)))))))\n\n        result = np.zeros((depth, height, width), dtype=np.uint8)\n\n        for start_z, start_y, start_x in zip(*np.where(candidate)):\n            if checked[start_z, start_y, start_x]:\n                continue\n\n            block = np.zeros((depth, height, width), dtype=np.uint8)\n\n            stack = deque()\n            stack.append((start_z, start_y, start_x))\n\n            block[start_z, start_y, start_x] = checked[start_z, start_y, start_x] = True\n\n            n = 1\n            while stack:\n                z, y, x = stack.pop()\n\n                for delta_x, delta_y, delta_z in deltas:\n                    next_z = z + delta_z\n                    next_y = y + delta_y\n                    next_x = x + delta_x\n\n                    if not (0 <= next_z < depth and 0 <= next_y < height and 0 <= next_x < width):\n                        continue\n\n                    if not candidate[next_z, next_y, next_x]:\n                        continue\n\n                    if block[next_z, next_y, next_x]:\n                        continue\n\n                    block[next_z, next_y, next_x] = checked[next_z, next_y, next_x] = True\n                    stack.append((next_z, next_y, next_x))\n\n                    n += 1\n\n            if n >= BLOCK_THRESHOLD:\n                result |= block\n\n                print(f\"n = {n}\\tratio = {np.count_nonzero(result) / (depth * height * width)}\")\n\n        return result\n\n    predict = get_predict()\n\n    # with open(f\"{data_folder_path.split('/')[-1]}_predict.pickle\", mode='wb') as f:\n    #     pickle.dump(predict, f)\n\n    candidate = get_candidate(predict)\n\n    del predict\n    gc.collect()\n\n    # with open(f\"{data_folder_path.split('/')[-1]}_candidate.pickle\", mode='wb') as f:\n    #     pickle.dump(candidate, f)\n\n    blood_vessel = get_blood_vessel(candidate)\n\n    del candidate\n    gc.collect()\n\n    # with open(f\"{data_folder_path.split('/')[-1]}.pickle\", mode='wb') as f:\n    #     pickle.dump(blood_vessel, f)\n\n    for i in range(depth):\n        image = blood_vessel[i]\n\n        print(f\"{data_folder_path.split('/')[-1]}_{data_paths[i].split('/')[-1].split('.')[0]},{rle_encode(image) if np.count_nonzero(image) else '1 0'}\", file=submission_file)\n\n    del blood_vessel\n    gc.collect()\n\n\nwith open('submission.csv', mode='w') as f:\n    print('id,rle', file=f)\n\n    for data_folder_path in sorted(glob('../input/blood-vessel-segmentation/test/*')):\n        submit(data_folder_path, f)\n\n    # submit('../input/blood-vessel-segmentation/train/kidney_1_dense', f)\n    # submit('../input/blood-vessel-segmentation/train/kidney_3_sparse', f)\n    # submit('../input/blood-vessel-segmentation/train/kidney_2', f)\n\n\n# submission_data_frame = pd.read_csv('/kaggle/working/submission.csv')\n# submission_data_frame.head()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-01-17T21:44:26.375030Z","iopub.execute_input":"2024-01-17T21:44:26.375587Z","iopub.status.idle":"2024-01-17T21:44:39.049671Z","shell.execute_reply.started":"2024-01-17T21:44:26.375536Z","shell.execute_reply":"2024-01-17T21:44:39.047627Z"},"trusted":true},"execution_count":null,"outputs":[]}]}