{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"\n<h2 style=\"text-align: center; font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: underline; text-transform: none; letter-spacing: 2px; color: #BF2C58; background-color: #ffffff;\">🫁🫀 Stain Transfer ( generalization ) 🫀🫁</h2>\n<h5 style=\"text-align: center; font-family: Verdana; font-size: 12px; font-style: normal; font-weight: bold; text-decoration: None; text-transform: none; letter-spacing: 1px; color: black; background-color: #ffffff;\">CREATED BY: COCO-Chanel <br><br>\nAll credit to belongs to the original author GRAY98!</h5>\n\n\n\n<br>\n\n---\n\n<br>\n\n<center><div class=\"alert alert-block alert-danger\" style=\"margin: 2em; line-height: 1.7em; font-family: Verdana;\">\n    <b style=\"font-size: 18px;\">🛑 &nbsp; WARNING:</b><br><br>\n    <b>1. currently in Processing 현재진행중!!! </b><br>\n    <b>2. Creating inference results based on staining. 염색에 따른 추론 진행중!!! </b><br>\n    \n    \n</div></center>\n\n<center><div class=\"alert alert-block alert-warning\" style=\"margin: 2em; line-height: 1.7em; font-family: Verdana;\">\n    <b style=\"font-size: 18px;\">👏 &nbsp; If this article was helpful면 &nbsp; 👏</b><br><br><b style=\"font-size: 22px; color: darkorange\">please VOTE!</b><br><br> If you vote, I think it will be a lot of help and support for me to do this work. 😅\n</div></center>\n\n<center><div class=\"alert alert-block alert-warning\" style=\"margin: 2em; line-height: 1.7em; font-family: Verdana;\">\n    <b style=\"font-size: 18px;\">👏 &nbsp; 이 글이 도움이 되셨다면 &nbsp; 👏</b><br><br><b style=\"font-size: 22px; color: darkorange\">투표 부탁드려요!</b><br><br> 투표 해주신다면 제가 이러한 작업을 하는데 많은 도움과 응원이 될 것 같습니다 😅\n</div></center>\n\n","metadata":{}},{"cell_type":"markdown","source":"<p id=\"toc\"></p>\n\n<br><br>\n\n<h1 style=\"font-family: Verdana; font-size: 24px; font-style: normal; font-weight: bold; text-decoration: none; text-transform: none; letter-spacing: 3px; color: #BF2C58; background-color: #ffffff;\">Content List ( 콘텐츠 목록 )</h1>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#imports\">0&nbsp;&nbsp;&nbsp;&nbsp;Introduction ( 소개 )</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#nor\">1&nbsp;&nbsp;&nbsp;&nbsp;Normalization ( 염색 표준화 )</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#set\">2&nbsp;&nbsp;&nbsp;&nbsp;Augmentation ( 데이터 증강 )</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#hel\">3&nbsp;&nbsp;&nbsp;&nbsp;Analysis ( 다른 데이터 분석 )</a></h3>\n\n---\n\n<h3 style=\"text-indent: 10vw; font-family: Verdana; font-size: 20px; font-style: normal; font-weight: normal; text-decoration: none; text-transform: none; letter-spacing: 2px; color: navy; background-color: #ffffff;\"><a href=\"#cre\">4&nbsp;&nbsp;&nbsp;&nbsp;Etc ( 기타 )</a></h3>\n","metadata":{}},{"cell_type":"markdown","source":"## 1. Introduction ( 소개 )\n<a id='imports'></a>\nYou may have discovered that the data of \"HPA\" (training set) is little different from the data of \"Hubmap\" (test set). Not just pixel_size and img_height, their color is dissimilar because of the difference of stain protocols. It is a very common problem when you handle histopathology images from different datasets.\n\nIn this notebook, I want to share a \"Vahadane\" stain normalization method for H&E stained histopathology images, but I am not sure it works in this dataset. ","metadata":{}},{"cell_type":"markdown","source":"\"HPA\"(훈련 세트)의 데이터가 \"Hubmap\"(테스트 세트)의 데이터가 다르다고 보여집니다.(크기,색상,구도)\n\n크기(pixel_size와 img_height) 뿐만 아니라 얼룩 프로토콜의 차이로 인해 색상이 다릅니다. 이와 같은 색상의 문제는 다른 데이터(프로토콜) 세트에서 조직 병리학 이미지를 처리할 때 매우 일반적인 문제입니다.\n\n이 노트북에서 H&E 염색 조직병리학 이미지에 대한 \"Vahadane\" 염색 정규화 방법을 공유하려고 합니다. 이방법이 이 데이터 세트에서 작동하는지 확신할 수 없지만 시도해보겠습니다.","metadata":{}},{"cell_type":"code","source":"# import background library\n# 기본적인 라이브러리 불러오기\n\nimport pandas as pd\nimport os\nimport numpy as np\n\nimport seaborn as sns\nimport tifffile\nimport cv2\n\nBASE_DIR = \"../input/hubmap-organ-segmentation\"\nsampled_ids = [24782, 24522, 19360, 29238, 27232, 18792, 30424, 21812]\n\ntrain_df = pd.read_csv(os.path.join('/kaggle/input/hubmap-organ-segmentation', \"train.csv\"))","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-08-11T12:27:01.851335Z","iopub.execute_input":"2022-08-11T12:27:01.852071Z","iopub.status.idle":"2022-08-11T12:27:04.039151Z","shell.execute_reply.started":"2022-08-11T12:27:01.851931Z","shell.execute_reply":"2022-08-11T12:27:04.037701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# difference between train data and test data\n# 훈련 데이터와 테스트 데이터의 차이점\n\nfrom skimage import io\nimport matplotlib.pyplot as plt\n\ntrain_img = io.imread('/kaggle/input/hubmap-organ-segmentation/train_images/10392.tiff')\ntrain_img2 = io.imread('/kaggle/input/hubmap-organ-segmentation/train_images/10610.tiff')\n\ntest_img = io.imread(\"/kaggle/input/hubmap-organ-segmentation/test_images/10078.tiff\")\n\nplt.figure(figsize=(15,10))\nplt.subplot(131)\nplt.title(\"train\")\nplt.imshow(train_img)\nplt.subplot(132)\nplt.title(\"train2\")\nplt.imshow(train_img2)\nplt.subplot(133)\nplt.title('test')\nplt.imshow(test_img)","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:27:04.041965Z","iopub.execute_input":"2022-08-11T12:27:04.042531Z","iopub.status.idle":"2022-08-11T12:27:09.356065Z","shell.execute_reply.started":"2022-08-11T12:27:04.042474Z","shell.execute_reply":"2022-08-11T12:27:09.355094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Basically, the appearance of the training data images is different, but the training data and test data'appearance are also different.\n\n기본적으로 훈련데이터 이미지끼리의 모습도 다르기도 하지만, 훈련데이터와 테스트데이터의 모습도 다릅니다.","metadata":{}},{"cell_type":"code","source":"# mask and image processing function\n# 이미지 및 마스크 처리 함수\n\ndef rle2mask(mask_rle, shape):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n    s = mask_rle.split()\n    starts, lengths = [\n        np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])\n    ]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = 1\n    return img.reshape(shape).T\n\n\ndef read_image(image_id, scale=None, verbose=1):\n    image = tifffile.imread(\n        os.path.join(BASE_DIR, f\"train_images/{image_id}.tiff\")\n    )\n    if len(image.shape) == 5:\n        image = image.squeeze().transpose(1, 2, 0)\n    \n    mask = rle2mask(\n        train_df[train_df[\"id\"] == image_id][\"rle\"].values[0], \n        (image.shape[1], image.shape[0])\n    )\n    \n    if verbose:\n        print(f\"[{image_id}] Image shape: {image.shape}\")\n        print(f\"[{image_id}] Mask shape: {mask.shape}\")\n    \n    if scale:\n        new_size = (image.shape[1] // scale, image.shape[0] // scale)\n        image = cv2.resize(image, new_size)\n        mask = cv2.resize(mask, new_size)\n        \n        if verbose:\n            print(f\"[{image_id}] Resized Image shape: {image.shape}\")\n            print(f\"[{image_id}] Resized Mask shape: {mask.shape}\")\n        \n    return image, mask\n\n\ndef plot_image_and_mask(image, mask, image_id, cmap):\n    plt.figure(figsize=(16, 10))\n    \n    plt.subplot(1, 3, 1)\n    plt.imshow(image)\n    plt.grid(visible=False)\n    plt.title(f\"Image {image_id}\", fontsize=18)\n    \n    plt.subplot(1, 3, 2)\n    plt.imshow(image)\n    plt.grid(visible=False)\n    plt.imshow(mask, cmap=cmap, alpha=0.5)\n    plt.title(f\"Image {image_id} + mask\", fontsize=18)    \n    \n    plt.subplot(1, 3, 3)\n    plt.grid(visible=False)\n    plt.imshow(mask, cmap=cmap)\n    plt.title(f\"Mask\", fontsize=18)    \n\n    plt.show()\n    ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-11T12:27:09.358152Z","iopub.execute_input":"2022-08-11T12:27:09.358944Z","iopub.status.idle":"2022-08-11T12:27:09.375070Z","shell.execute_reply.started":"2022-08-11T12:27:09.358902Z","shell.execute_reply":"2022-08-11T12:27:09.373623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sampled_images = []\nsampled_masks = []\n\nfor sampled_id in sampled_ids:\n    tmp_image, tmp_mask = read_image(sampled_id, scale=20, verbose=0)\n    sampled_images.append(tmp_image)\n    sampled_masks.append(tmp_mask)\n\ndef get_image_masks_with_id(sampled_ids):\n    sampled_images = []\n    sampled_masks = []\n\n    for sampled_id in sampled_ids:\n        tmp_image, tmp_mask = read_image(sampled_id, scale=20, verbose=0)\n        sampled_images.append(tmp_image)\n        sampled_masks.append(tmp_mask)\n    \n    return sampled_images, sampled_masks","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-11T12:27:09.378363Z","iopub.execute_input":"2022-08-11T12:27:09.379186Z","iopub.status.idle":"2022-08-11T12:27:12.571624Z","shell.execute_reply.started":"2022-08-11T12:27:09.379145Z","shell.execute_reply":"2022-08-11T12:27:12.570544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Normalization ( 염색 표준화 )\n<a id='nor'></a>\n\nIf you prefer to know more theoretical thing about stain normalization, I recommend this [paper](https://ieeexplore.ieee.org/abstract/document/7460968) and the [intelligible version](https://hackmd.io/@peter554/staintools)","metadata":{}},{"cell_type":"markdown","source":"얼룩 정규화에 더 알고 싶다면 위에 paper(논문)과 설명버전을 참고해주세요.","metadata":{}},{"cell_type":"code","source":"# Install staining processing library\n# 염색 처리 라이브러리 설치\n!pip install staintools\n!pip install spams","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-08-11T12:27:12.573167Z","iopub.execute_input":"2022-08-11T12:27:12.573598Z","iopub.status.idle":"2022-08-11T12:29:37.483330Z","shell.execute_reply.started":"2022-08-11T12:27:12.573566Z","shell.execute_reply":"2022-08-11T12:29:37.482013Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Reading test images and training images\n# 테스트 이미지와 훈련이미지 읽어오기 \n\nimport staintools\n\ntarget = staintools.read_image(\"/kaggle/input/hubmap-organ-segmentation/test_images/10078.tiff\")\nto_transform = staintools.read_image(\"/kaggle/input/hubmap-organ-segmentation/train_images/10392.tiff\")\nto_transform2 = staintools.read_image(\"/kaggle/input/hubmap-organ-segmentation/train_images/10610.tiff\")\n\nplt.subplot(121)\nplt.imshow(target)\nplt.subplot(122)\nplt.imshow(to_transform)","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:29:37.484979Z","iopub.execute_input":"2022-08-11T12:29:37.485402Z","iopub.status.idle":"2022-08-11T12:29:39.700673Z","shell.execute_reply.started":"2022-08-11T12:29:37.485361Z","shell.execute_reply":"2022-08-11T12:29:39.699384Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Standardize brightness (optional, can improve the tissue mask calculation)\n# 밝기 표준화(선택 사항, 조직 마스크 계산을 개선해준다)\n\ntarget = staintools.LuminosityStandardizer.standardize(target)\nto_transform = staintools.LuminosityStandardizer.standardize(to_transform)\nto_transform2 = staintools.LuminosityStandardizer.standardize(to_transform2)\n\n# Stain normalize ( Call the dyeing function and fit it according to the target you want to dye)\n# 염색 표준화( 염색 함수를 부르고, 염색하고자 하는 타켓에 맞춰 세팅)\n\nnormalizer = staintools.StainNormalizer(method='vahadane')\nnormalizer.fit(target)\n\n# Transform the image to be replaced with a fitted staining function\n# 맞춰진 염색 함수로 바꿀 이미지를 변형\ntransformed1 = normalizer.transform(to_transform)\ntransformed2 = normalizer.transform(to_transform2)\n\nplt.subplot(121)\nplt.imshow(transformed1)\nplt.subplot(122)\nplt.imshow(transformed2)","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:29:39.702275Z","iopub.execute_input":"2022-08-11T12:29:39.702683Z","iopub.status.idle":"2022-08-11T12:30:32.322316Z","shell.execute_reply.started":"2022-08-11T12:29:39.702649Z","shell.execute_reply":"2022-08-11T12:30:32.320849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Doesn't it look pretty similar to the staining protocol for the test image? Of course, this is not the professional judgment of a pathologist.","metadata":{}},{"cell_type":"markdown","source":"테스트 이미지의 염색 프로토콜과 꽤 비슷해지지 않았나요? 물론 병리학자의 전문적인 판단은 아닙니다.","metadata":{}},{"cell_type":"code","source":"# another approach ( method = mecenko)\n# 메소드를 변경해서 적용해보기\n\nnormalizer = staintools.StainNormalizer(method='macenko')\nnormalizer.fit(target)\ntransformed3 = normalizer.transform(to_transform)\n\nplt.imshow(transformed3)","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:30:32.324220Z","iopub.execute_input":"2022-08-11T12:30:32.324659Z","iopub.status.idle":"2022-08-11T12:31:05.665063Z","shell.execute_reply.started":"2022-08-11T12:30:32.324625Z","shell.execute_reply":"2022-08-11T12:31:05.663825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 3. Augmentation ( 데이터 증강 )\n<a id='set'></a>","metadata":{}},{"cell_type":"code","source":"# Stain augment ( test data )\n# 테스트 데이터 염색 증강\naugmentor = staintools.StainAugmentor(method='vahadane', sigma1=0.4, sigma2=0.4)\naugmentor.fit(target)\n\naugmented_images = []\nfor _ in range(10):\n    augmented_image = augmentor.pop()\n    augmented_images.append(augmented_image)\n\n# Plot\ntitles = [\"Augmented\"] * 10\nstaintools.plot_image_list(augmented_images, width=5,  show=0)","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:31:05.666485Z","iopub.execute_input":"2022-08-11T12:31:05.666854Z","iopub.status.idle":"2022-08-11T12:31:31.402285Z","shell.execute_reply.started":"2022-08-11T12:31:05.666821Z","shell.execute_reply":"2022-08-11T12:31:31.400973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Stain augment ( fit test stain-style to train dataset )\n# 염색 증강 ( 테스트 데이터셋의 염색을 훈련데이터셋에 적용 )\naugmentor2 = staintools.StainAugmentor(method='vahadane', sigma1=0.4, sigma2=0.4)\naugmentor2.fit(transformed3)\n\naugmented_images2 = []\nfor _ in range(10):\n    augmented_image = augmentor2.pop()\n    augmented_images2.append(augmented_image)\n\n# Plot\ntitles = [\"Augmented\"] * 10\nstaintools.plot_image_list(augmented_images2, width=5,  show=0)","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:31:31.405518Z","iopub.execute_input":"2022-08-11T12:31:31.405888Z","iopub.status.idle":"2022-08-11T12:32:15.204524Z","shell.execute_reply.started":"2022-08-11T12:31:31.405856Z","shell.execute_reply":"2022-08-11T12:32:15.203075Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It is very similar to the dyeing style of the test image set.\nOf course, detailed problems (not visible because it is dark, the white background changes as well) are problems that need to be solved.","metadata":{}},{"cell_type":"markdown","source":"테스트 이미지셋의 염색 스타일과 굉장히 비슷해졌습니다.\n물론 세부적인 문제들 ( 어두워서 안보임, 하얀 배경도 같이 변함 )은 해결해야되는 문제입니다.","metadata":{}},{"cell_type":"markdown","source":"### 4. Analysis ( 다른 데이터 분석 )\n<a id='hel'></a>","metadata":{}},{"cell_type":"code","source":"mask_10392 = rle2mask(train_df[train_df[\"id\"]==10392]['rle'].values[0], (3000, 3000))","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:36:18.832103Z","iopub.execute_input":"2022-08-11T12:36:18.832551Z","iopub.status.idle":"2022-08-11T12:36:18.844539Z","shell.execute_reply.started":"2022-08-11T12:36:18.832516Z","shell.execute_reply":"2022-08-11T12:36:18.843189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(dpi=400)\nplt.subplot(121)\nplt.imshow(transformed1)\nplt.subplot(122)\nplt.imshow(mask_10392, cmap='gray')","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:36:23.572253Z","iopub.execute_input":"2022-08-11T12:36:23.572713Z","iopub.status.idle":"2022-08-11T12:36:30.764605Z","shell.execute_reply.started":"2022-08-11T12:36:23.572676Z","shell.execute_reply":"2022-08-11T12:36:30.763457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It is quite clear that tumor regions are darker. ","metadata":{}},{"cell_type":"markdown","source":"종양 영역이 더 어둡다는 것은 매우 확실해보입니다.","metadata":{}},{"cell_type":"code","source":"# Spleen original training dataset\n# 비장의 기존 훈련 데이터셋\n\nids_sampled = train_df[(train_df[\"organ\"] == \"spleen\") & (train_df[\"sex\"] == \"Male\")].sample(6).id.tolist()\n\nsampled_images, sampled_masks = get_image_masks_with_id(ids_sampled)\n\nplt.figure(figsize=(16, 16))\nfor ind, (tmp_id, tmp_image, tmp_mask) in enumerate(zip(ids_sampled, sampled_images, sampled_masks)):\n    plt.subplot(3, 3, ind + 1)\n    plt.imshow(tmp_image)\n    plt.imshow(tmp_mask, cmap=\"hot\", alpha=0.5)\n    plt.title(f\"Male Spleen: {tmp_id}\")\n    plt.axis(\"off\")","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:36:30.766190Z","iopub.execute_input":"2022-08-11T12:36:30.766747Z","iopub.status.idle":"2022-08-11T12:36:34.437024Z","shell.execute_reply.started":"2022-08-11T12:36:30.766712Z","shell.execute_reply":"2022-08-11T12:36:34.435765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Spleen stain transfer training dataset\n# 비장의 염색변형 훈련 데이터셋\n\nplt.figure(figsize=(16, 16))\nfor ind, (tmp_id, tmp_image, tmp_mask) in enumerate(zip(ids_sampled, sampled_images, sampled_masks)):\n    plt.subplot(3, 3, ind + 1)\n    \n    plt.imshow(normalizer.transform(tmp_image))\n    plt.imshow(tmp_mask, cmap=\"hot\", alpha=0.5)\n    plt.title(f\"Male Spleen: {tmp_id}\")\n    plt.axis(\"off\")","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:36:34.438521Z","iopub.execute_input":"2022-08-11T12:36:34.439394Z","iopub.status.idle":"2022-08-11T12:36:35.803736Z","shell.execute_reply.started":"2022-08-11T12:36:34.439348Z","shell.execute_reply":"2022-08-11T12:36:35.802412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The appearance of the stained data looks much like the appearance of the test dataset.","metadata":{}},{"cell_type":"markdown","source":"염색된 데이터들의 모습이 테스트 데이터셋의 모습과 훨씬 비슷해 보입니다.\n","metadata":{}},{"cell_type":"markdown","source":"### 5. etc\n<a id='cre'></a>","metadata":{}},{"cell_type":"code","source":"# we can also transfer test set to training set\n# 훈련세트의 스타일을 테스트 데이터셋에 적용할 수도 있습니다.\n \nto_transform = staintools.read_image(\"/kaggle/input/hubmap-organ-segmentation/test_images/10078.tiff\")\ntarget = staintools.read_image(\"/kaggle/input/hubmap-organ-segmentation/train_images/10392.tiff\")\n\n# Standardize brightness (optional, can improve the tissue mask calculation)\ntarget = staintools.LuminosityStandardizer.standardize(target)\nto_transform = staintools.LuminosityStandardizer.standardize(to_transform)\n\n# Stain normalize\nnormalizer = staintools.StainNormalizer(method='vahadane')\nnormalizer.fit(target)\ntransformed4 = normalizer.transform(to_transform)\nplt.imshow(transformed4)","metadata":{"execution":{"iopub.status.busy":"2022-08-11T12:36:35.806237Z","iopub.execute_input":"2022-08-11T12:36:35.807427Z","iopub.status.idle":"2022-08-11T12:37:05.678228Z","shell.execute_reply.started":"2022-08-11T12:36:35.807381Z","shell.execute_reply":"2022-08-11T12:37:05.677068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"If you have any good comments or suggestions, please feel free to tell us! thank you!","metadata":{}}]}