乳房 X 线照片中最大轮廓的 OpenCV 分割
OpenCV Segmentation of Largest contour in Breast Mammograms
这个问题可能有点太“笼统”了,但是如何进行灰度图像分割并保持最大轮廓呢?我试图从乳房 X 线照片中去除背景噪音(即标签),但我没有成功。这是原始图像:
首先,我应用了 AGCWD 算法(基于论文“Efficient Contrast Enhancement Using Adaptive Gamma Correction With Weighting Distribution”)以获得更好的图像像素对比度,如下所示:
之后,我尝试执行以下步骤:
使用 OpenCV 的 KMeans 聚类算法进行图像分割:
enhanced_image_cpy = enhanced_image.copy()
reshaped_image = np.float32(enhanced_image_cpy.reshape(-1, 1))
number_of_clusters = 10
stop_criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.1)
ret, labels, clusters = cv2.kmeans(reshaped_image, number_of_clusters, None, stop_criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
clusters = np.uint8(clusters)
Canny 边缘检测:
removed_cluster = 1
canny_image = np.copy(enhanced_image_cpy).reshape((-1, 1))
canny_image[labels.flatten() == removed_cluster] = [0]
canny_image = cv2.Canny(canny_image,100,200).reshape(enhanced_image_cpy.shape)
show_images([canny_image])
查找并绘制等高线:
initial_contours_image = np.copy(canny_image)
initial_contours_image_bgr = cv2.cvtColor(initial_contours_image, cv2.COLOR_GRAY2BGR)
_, thresh = cv2.threshold(initial_contours_image, 50, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(initial_contours_image_bgr, contours, -1, (255,0,0), cv2.CHAIN_APPROX_SIMPLE)
show_images([initial_contours_image_bgr])
这是我绘制 44004 个轮廓后图像的样子:
我不确定如何才能得到一个大轮廓,而不是 44004 个小轮廓。关于如何修复我的方法的任何想法,或者关于使用替代方法摆脱右上角标签的任何想法。
提前致谢!
这是 Python OpenCV
中的一种方法
阅读图片
- 阈值和反转使边框为黑色
- 去除图片的边框如下(方便后面得到相关轮廓):
- 计算每列中非零像素的数量,找到计数大于 0 的第一列和最后一列
- 计算每行中非零像素的数量,并找到计数大于 0 的第一行和最后一行
- 裁剪图像以去除边框
- 裁剪 thresh1 并反转以制作 thresh2
- 从thresh2获取外部轮廓
- 找到最大的轮廓并画成黑色背景上的白色填充作为遮罩
- 将裁剪图像中蒙版为黑色的所有像素设为黑色
- 保存结果-
输入:
import cv2
import numpy as np
# read image
img = cv2.imread('xray3.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold and invert
thresh1 = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
thresh1 = 255 - thresh1
# remove borders
# count number of white pixels in columns as new 1D array
count_cols = np.count_nonzero(thresh1, axis=0)
# get first and last x coordinate where black
first_x = np.where(count_cols>0)[0][0]
last_x = np.where(count_cols>0)[0][-1]
print(first_x,last_x)
# count number of white pixels in rows as new 1D array
count_rows = np.count_nonzero(thresh1, axis=1)
# get first and last y coordinate where black
first_y = np.where(count_rows>0)[0][0]
last_y = np.where(count_rows>0)[0][-1]
print(first_y,last_y)
# crop image
crop = img[first_y:last_y+1, first_x:last_x+1]
# crop thresh1 and invert
thresh2 = thresh1[first_y:last_y+1, first_x:last_x+1]
thresh2 = 255 - thresh2
# get external contours and keep largest one
contours = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# make mask from contour
mask = np.zeros_like(thresh2 , dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, -1)
# make crop black everywhere except where largest contour is white in mask
result = crop.copy()
result[mask==0] = (0,0,0)
# write result to disk
cv2.imwrite("xray3_thresh1.jpg", thresh1)
cv2.imwrite("xray3_crop.jpg", crop)
cv2.imwrite("xray3_thresh2.jpg", thresh2)
cv2.imwrite("xray3_mask.jpg", mask)
cv2.imwrite("xray3_result.png", result)
# display it
cv2.imshow("thresh1", thresh1)
cv2.imshow("crop", crop)
cv2.imshow("thresh2", thresh2)
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
阈值 1 图片:
裁剪图像:
阈值 2 图片:
蒙版图片:
结果:
这个问题可能有点太“笼统”了,但是如何进行灰度图像分割并保持最大轮廓呢?我试图从乳房 X 线照片中去除背景噪音(即标签),但我没有成功。这是原始图像:
首先,我应用了 AGCWD 算法(基于论文“Efficient Contrast Enhancement Using Adaptive Gamma Correction With Weighting Distribution”)以获得更好的图像像素对比度,如下所示:
之后,我尝试执行以下步骤:
使用 OpenCV 的 KMeans 聚类算法进行图像分割:
enhanced_image_cpy = enhanced_image.copy()
reshaped_image = np.float32(enhanced_image_cpy.reshape(-1, 1))
number_of_clusters = 10
stop_criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.1)
ret, labels, clusters = cv2.kmeans(reshaped_image, number_of_clusters, None, stop_criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
clusters = np.uint8(clusters)
Canny 边缘检测:
removed_cluster = 1
canny_image = np.copy(enhanced_image_cpy).reshape((-1, 1))
canny_image[labels.flatten() == removed_cluster] = [0]
canny_image = cv2.Canny(canny_image,100,200).reshape(enhanced_image_cpy.shape)
show_images([canny_image])
查找并绘制等高线:
initial_contours_image = np.copy(canny_image)
initial_contours_image_bgr = cv2.cvtColor(initial_contours_image, cv2.COLOR_GRAY2BGR)
_, thresh = cv2.threshold(initial_contours_image, 50, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(initial_contours_image_bgr, contours, -1, (255,0,0), cv2.CHAIN_APPROX_SIMPLE)
show_images([initial_contours_image_bgr])
这是我绘制 44004 个轮廓后图像的样子:
我不确定如何才能得到一个大轮廓,而不是 44004 个小轮廓。关于如何修复我的方法的任何想法,或者关于使用替代方法摆脱右上角标签的任何想法。
提前致谢!
这是 Python OpenCV
中的一种方法阅读图片
- 阈值和反转使边框为黑色
- 去除图片的边框如下(方便后面得到相关轮廓):
- 计算每列中非零像素的数量,找到计数大于 0 的第一列和最后一列
- 计算每行中非零像素的数量,并找到计数大于 0 的第一行和最后一行
- 裁剪图像以去除边框
- 裁剪 thresh1 并反转以制作 thresh2
- 从thresh2获取外部轮廓
- 找到最大的轮廓并画成黑色背景上的白色填充作为遮罩
- 将裁剪图像中蒙版为黑色的所有像素设为黑色
- 保存结果-
输入:
import cv2
import numpy as np
# read image
img = cv2.imread('xray3.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold and invert
thresh1 = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
thresh1 = 255 - thresh1
# remove borders
# count number of white pixels in columns as new 1D array
count_cols = np.count_nonzero(thresh1, axis=0)
# get first and last x coordinate where black
first_x = np.where(count_cols>0)[0][0]
last_x = np.where(count_cols>0)[0][-1]
print(first_x,last_x)
# count number of white pixels in rows as new 1D array
count_rows = np.count_nonzero(thresh1, axis=1)
# get first and last y coordinate where black
first_y = np.where(count_rows>0)[0][0]
last_y = np.where(count_rows>0)[0][-1]
print(first_y,last_y)
# crop image
crop = img[first_y:last_y+1, first_x:last_x+1]
# crop thresh1 and invert
thresh2 = thresh1[first_y:last_y+1, first_x:last_x+1]
thresh2 = 255 - thresh2
# get external contours and keep largest one
contours = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# make mask from contour
mask = np.zeros_like(thresh2 , dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, -1)
# make crop black everywhere except where largest contour is white in mask
result = crop.copy()
result[mask==0] = (0,0,0)
# write result to disk
cv2.imwrite("xray3_thresh1.jpg", thresh1)
cv2.imwrite("xray3_crop.jpg", crop)
cv2.imwrite("xray3_thresh2.jpg", thresh2)
cv2.imwrite("xray3_mask.jpg", mask)
cv2.imwrite("xray3_result.png", result)
# display it
cv2.imshow("thresh1", thresh1)
cv2.imshow("crop", crop)
cv2.imshow("thresh2", thresh2)
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
阈值 1 图片:
裁剪图像:
阈值 2 图片:
蒙版图片:
结果: