如何去除乳房 X 光检查标签伪影
How to remove mammography tag artifacts
我有一个乳腺摄影图像数据集(迷你 DDSM)。这些图像显示了指示左侧或右侧妈妈的字母伪影以及其他对我的 ML 模型无用的信息,因此我想在训练模型之前整理此数据集。
本文基于
Otsu 的 Threshold,他们使用 Otsu 的二值化和开放在乳腺 X 线照相术上清洁图像(第 5 页,共 10 页):
Their results
到目前为止,我已经编码了:
im = io.imread('/content/drive/MyDrive/TFM/DDSMPNG/ALL2/0.jpg')
# thresholding
thresh = im > filters.threshold_otsu(im)
# opening with a disk structure
disk = morphology.disk(5)
opened = morphology.binary_opening(thresh,disk)
# plotting
plt.figure(figsize=(10, 10))
plt.subplot(131)
plt.imshow(im,cmap='gray')
plt.subplot(132)
plt.imshow(opened,cmap='gray')
plt.imsave('/content/drive/MyDrive/TFM/DDSMPNG/Blackened/0.jpg',opened)
这些是情节:
Results
我也试过用高一点的圆盘做开孔,好像去掉了比较白的小字神器,也把乳腺片裁剪了一点:
disk = morphology.disk(45)
opened = morphology.binary_opening(thresh,disk)
结果:
Result with disk shape (45,45)
我想我必须用二值化创建某种蒙版并将其应用于原始图像,但我是图像处理库的新手,我不确定如何获得结果
编辑 1:我尝试了@fmw42 的建议,但我遇到了一些问题(我在 Google Colab 上工作,不知道它是否有事可做...):
首先,在您的代码中以图片为例,它似乎无法正常工作,不知道为什么,我复制了您的代码,只是将图片的路径以及一些子图修改为查看结果:
# read image
img = cv2.imread('/content/drive/MyDrive/TFM/DDSMPNG/ALL2/0.jpg')
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw largest contour as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, cv2.FILLED)
# dilate mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (55,55))
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel)
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('/content/drive/MyDrive/TFM/DDSMPNG/Blackened/0.jpg', result)
# show resultls
plt.figure(figsize=(10, 10))
plt.subplot(141)
plt.imshow(thresh,cmap='gray')
plt.subplot(142)
plt.imshow(morph,cmap='gray')
plt.subplot(143)
plt.imshow(mask,cmap='gray')
plt.subplot(144)
plt.imshow(result,cmap='gray')
结果:
其次,对于其余图像,它似乎对大多数图像都有效,但它对乳房表面进行了一些裁剪:
在你的结果图像中,它似乎更加平滑,我该如何实现?
提前致谢!
编辑 2:@fmw42 解决方案工作正常,如果有人有同样的问题,您只需要使用形态过滤器的内核大小,直到图像表现得像他在答案中的结果。
非常感谢!
这是在 Python/OpenCV 中处理图像的一种方法。
- Read the input
- Convert to grayscale
- Otsu threshold
- Morphology processing
- Get largest contour from external contours
- Draw all contours as white filled on a black background except the largest as a mask and invert mask
- Apply the mask to the input image
- Save the results
输入:
import cv2
import numpy as np
# read image
img = cv2.imread("mammogram.png")
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# apply morphology dilate to compensate for otsu threshold not getting some areas
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (29,29))
morph = cv2.morphologyEx(morph, cv2.MORPH_DILATE, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
big_contour_area = cv2.contourArea(big_contour)
# draw all contours but the largest as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
for cntr in contours:
area = cv2.contourArea(cntr)
if area != big_contour_area:
cv2.drawContours(mask, [cntr], 0, 255, cv2.FILLED)
# invert mask
mask = 255 - mask
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('mammogram_thresh.jpg', thresh)
cv2.imwrite('mammogram_morph.jpg', morph)
cv2.imwrite('mammogram_mask.jpg', mask)
cv2.imwrite('mammogram_result.jpg', result)
# show resultls
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态学处理图像:
来自轮廓的蒙版图像:
结果图片:
备用
- Read the input
- Convert to grayscale
- Otsu threshold
- Morphology processing
- Get largest contour from external contours
- Draw largest as white filled on black background as a mask
- Dilate mask
- Apply the mask to the input image
- Save the results
输入:
import cv2
import numpy as np
# read image
img = cv2.imread("mammogram.png")
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw largest contour as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, cv2.FILLED)
# dilate mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (55,55))
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel)
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('mammogram_thresh.jpg', thresh)
cv2.imwrite('mammogram_morph2.jpg', morph)
cv2.imwrite('mammogram_mask2.jpg', mask)
cv2.imwrite('mammogram_result2.jpg', result)
# show resultls
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态学处理图像:
蒙版图片:
结果:
加法
这是应用于较大的 JPG 图片的第二种处理方法。我注意到它的宽度和高度大约是 6 倍。所以我将形态内核从 5 增加到 31 大约 6 倍。我还将图像边框四周修剪了 40 像素,然后添加回相同数量的黑色边框。
输入:
import cv2
import numpy as np
# read image
img = cv2.imread("mammogram.jpg")
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# shave 40 pixels all around
gray = gray[40:hh-40, 40:ww-40]
# add 40 pixel black border all around
gray = cv2.copyMakeBorder(gray, 40,40,40,40, cv2.BORDER_CONSTANT, value=0)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (31,31))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (31,31))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw largest contour as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, cv2.FILLED)
# dilate mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (305,305))
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel)
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('mammogram_thresh.jpg', thresh)
cv2.imwrite('mammogram_morph2.jpg', morph)
cv2.imwrite('mammogram_mask2.jpg', mask)
cv2.imwrite('mammogram_result2.jpg', result)
# show resultls
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态图像:
蒙版图片:
结果:
我有一个乳腺摄影图像数据集(迷你 DDSM)。这些图像显示了指示左侧或右侧妈妈的字母伪影以及其他对我的 ML 模型无用的信息,因此我想在训练模型之前整理此数据集。
本文基于 Otsu 的 Threshold,他们使用 Otsu 的二值化和开放在乳腺 X 线照相术上清洁图像(第 5 页,共 10 页):
Their results
到目前为止,我已经编码了:
im = io.imread('/content/drive/MyDrive/TFM/DDSMPNG/ALL2/0.jpg')
# thresholding
thresh = im > filters.threshold_otsu(im)
# opening with a disk structure
disk = morphology.disk(5)
opened = morphology.binary_opening(thresh,disk)
# plotting
plt.figure(figsize=(10, 10))
plt.subplot(131)
plt.imshow(im,cmap='gray')
plt.subplot(132)
plt.imshow(opened,cmap='gray')
plt.imsave('/content/drive/MyDrive/TFM/DDSMPNG/Blackened/0.jpg',opened)
这些是情节:
Results
我也试过用高一点的圆盘做开孔,好像去掉了比较白的小字神器,也把乳腺片裁剪了一点:
disk = morphology.disk(45)
opened = morphology.binary_opening(thresh,disk)
结果:
Result with disk shape (45,45)
我想我必须用二值化创建某种蒙版并将其应用于原始图像,但我是图像处理库的新手,我不确定如何获得结果
编辑 1:我尝试了@fmw42 的建议,但我遇到了一些问题(我在 Google Colab 上工作,不知道它是否有事可做...):
首先,在您的代码中以图片为例,它似乎无法正常工作,不知道为什么,我复制了您的代码,只是将图片的路径以及一些子图修改为查看结果:
# read image
img = cv2.imread('/content/drive/MyDrive/TFM/DDSMPNG/ALL2/0.jpg')
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw largest contour as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, cv2.FILLED)
# dilate mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (55,55))
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel)
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('/content/drive/MyDrive/TFM/DDSMPNG/Blackened/0.jpg', result)
# show resultls
plt.figure(figsize=(10, 10))
plt.subplot(141)
plt.imshow(thresh,cmap='gray')
plt.subplot(142)
plt.imshow(morph,cmap='gray')
plt.subplot(143)
plt.imshow(mask,cmap='gray')
plt.subplot(144)
plt.imshow(result,cmap='gray')
结果:
其次,对于其余图像,它似乎对大多数图像都有效,但它对乳房表面进行了一些裁剪:
在你的结果图像中,它似乎更加平滑,我该如何实现?
提前致谢!
编辑 2:@fmw42 解决方案工作正常,如果有人有同样的问题,您只需要使用形态过滤器的内核大小,直到图像表现得像他在答案中的结果。
非常感谢!
这是在 Python/OpenCV 中处理图像的一种方法。
- Read the input
- Convert to grayscale
- Otsu threshold
- Morphology processing
- Get largest contour from external contours
- Draw all contours as white filled on a black background except the largest as a mask and invert mask
- Apply the mask to the input image
- Save the results
输入:
import cv2
import numpy as np
# read image
img = cv2.imread("mammogram.png")
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# apply morphology dilate to compensate for otsu threshold not getting some areas
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (29,29))
morph = cv2.morphologyEx(morph, cv2.MORPH_DILATE, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
big_contour_area = cv2.contourArea(big_contour)
# draw all contours but the largest as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
for cntr in contours:
area = cv2.contourArea(cntr)
if area != big_contour_area:
cv2.drawContours(mask, [cntr], 0, 255, cv2.FILLED)
# invert mask
mask = 255 - mask
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('mammogram_thresh.jpg', thresh)
cv2.imwrite('mammogram_morph.jpg', morph)
cv2.imwrite('mammogram_mask.jpg', mask)
cv2.imwrite('mammogram_result.jpg', result)
# show resultls
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态学处理图像:
来自轮廓的蒙版图像:
结果图片:
备用
- Read the input
- Convert to grayscale
- Otsu threshold
- Morphology processing
- Get largest contour from external contours
- Draw largest as white filled on black background as a mask
- Dilate mask
- Apply the mask to the input image
- Save the results
输入:
import cv2
import numpy as np
# read image
img = cv2.imread("mammogram.png")
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw largest contour as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, cv2.FILLED)
# dilate mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (55,55))
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel)
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('mammogram_thresh.jpg', thresh)
cv2.imwrite('mammogram_morph2.jpg', morph)
cv2.imwrite('mammogram_mask2.jpg', mask)
cv2.imwrite('mammogram_result2.jpg', result)
# show resultls
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态学处理图像:
蒙版图片:
结果:
加法
这是应用于较大的 JPG 图片的第二种处理方法。我注意到它的宽度和高度大约是 6 倍。所以我将形态内核从 5 增加到 31 大约 6 倍。我还将图像边框四周修剪了 40 像素,然后添加回相同数量的黑色边框。
输入:
import cv2
import numpy as np
# read image
img = cv2.imread("mammogram.jpg")
hh, ww = img.shape[:2]
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# shave 40 pixels all around
gray = gray[40:hh-40, 40:ww-40]
# add 40 pixel black border all around
gray = cv2.copyMakeBorder(gray, 40,40,40,40, cv2.BORDER_CONSTANT, value=0)
# apply otsu thresholding
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU )[1]
# apply morphology close to remove small regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (31,31))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open to separate breast from other regions
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (31,31))
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
# get largest contour
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw largest contour as white filled on black background as mask
mask = np.zeros((hh,ww), dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, cv2.FILLED)
# dilate mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (305,305))
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel)
# apply mask to image
result = cv2.bitwise_and(img, img, mask=mask)
# save results
cv2.imwrite('mammogram_thresh.jpg', thresh)
cv2.imwrite('mammogram_morph2.jpg', morph)
cv2.imwrite('mammogram_mask2.jpg', mask)
cv2.imwrite('mammogram_result2.jpg', result)
# show resultls
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
阈值图像:
形态图像:
蒙版图片:
结果: