python - 乳房 X 线照片中最大轮廓的 OpenCV 分割
问题描述
这可能有点过于“笼统”的问题,但我如何执行灰度图像分割并保持最大轮廓?我正在尝试从乳房 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 图像:
蒙版图片:
结果:
推荐阅读
- c# - 当我们将pdf存储在blob中时,MSSQL是否存储文件名?
- python - 无法导入 mysql.connect
- android - 了解不同尺寸和像素密度设备上的 android ImageView
- typescript - TS 索引类型 - 当接口中使用索引类型时,编译器无法解析精确值
- java - 如何使用某些单词分隔可以是动态的字符串
- python - 在 Python 中使用正则表达式匿名电子邮件地址
- django - 如何在 Django Rest Framework 中记录 4XX Http 状态的请求和响应?
- c++ - 不应该使用来自匿名命名空间的函数或来自另一个文件的静态函数会报错吗?
- c++ - 如何拥有 unordered_multimaps 的 unordered_multimap
- javascript - VScode 在匹配之前和之后替换正则表达式