消除图像区域之间的间隙
Remove gap between areas of image
我使用在线合并工具合并了两张肺部图像以显示完整图像。
问题在于,由于每张图片的背景都是黑色,所以我在显示的图片中的肺部之间出现了不需要的间隙。
我想知道是否有办法使用带有算法的代码或在线工具从图像中删除一个区域并缩小肺部之间的间隙。
我检查的另一种方法是将 OpenCV 与 Python 一起用于全景图像拼接,我将尝试将其作为连接图像的最后手段。
我想要的结果:
这是我在 Python/OpenCV 的评论中提到的一种方式。
- 读取输入并转换为灰度
- 二进制的阈值
- 获取外部轮廓
- 过滤轮廓以仅保留大轮廓并将边界框值放入列表中。还要计算边界框的最大宽度和最大高度。
- 设置所需的填充量
- 创建最大宽度和最大高度的黑色图像
- 按 x 值对边界框列表进行排序
- 从列表中获取第一项并对其进行裁剪和填充
- 创建一个最大高度和所需 pad 大小的黑色图像
- 与之前的填充作物水平连接
- 从列表中获取第二个项目并对其进行裁剪和填充
- 与之前填充的结果水平连接
- 根据需要在四周填充
- 保存输出
输入:
import cv2
import numpy as np
# load image
img = cv2.imread("lungs_mask.png", cv2.IMREAD_GRAYSCALE)
# threshold
thresh = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)[1]
# get the largest contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
# get bounding boxes of each contour if area large and put into list
cntr_list=[]
max_ht = 0
max_wd = 0
for cntr in contours:
area = cv2.contourArea(cntr)
if area > 10000:
x,y,w,h = cv2.boundingRect(cntr)
cntr_list.append([x,y,w,h])
if h > max_ht:
max_ht = h
if w > max_wd:
max_wd = w
# set padded
padding = 25
# create black image of size max_wd,max_ht
black = np.zeros((max_ht,max_wd), dtype=np.uint8)
# sort contours by x value
def takeFirst(elem):
return elem[0]
cntr_list.sort(key=takeFirst)
# Take first entry in sorted list and crop and pad
item = cntr_list[0]
x = item[0]
y = item[1]
w = item[2]
h = item[3]
crop = thresh[y:y+h, x:x+w]
result = black[0:max_ht, 0:w]
result[0:h, 0:w] = crop
# create center padding and concatenate
pad_center_img = np.zeros((max_ht,padding), dtype=np.uint8)
result = cv2.hconcat((result, pad_center_img))
# Take second entry in sorted list and crop, pad and concatenate
item = cntr_list[1]
x = item[0]
y = item[1]
w = item[2]
h = item[3]
crop = thresh[y:y+h, x:x+w]
temp = black[0:max_ht, 0:w]
temp[0:h, 0:w] = crop
result = cv2.hconcat((result, temp))
# Pad all around as desired
result = cv2.copyMakeBorder(result, 25, 25, 25, 25, borderType=cv2.BORDER_CONSTANT, value=(0))
# write result to disk
cv2.imwrite("lungs_mask_cropped.jpg", result)
# display it
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.waitKey(0)
结果:
概念:
使用cv2.findContours()
method, we will get an array of all the contours detected in the image specified. Normally, we would preprocess the image (for example, with the cv2.Canny()
方法),然后将其传递给cv2.findContours()
方法,但是由于我们现在拥有的图像是一个简单的二值图像,具有两个里面有非常明显的斑点,没有必要。
我们使用cv2.boundingBox()
方法找到每个轮廓的x, y, w, h
,以便我们可以从图像中切出该部分。
我们使用 x, y, w, h
检测到图像的两个切片,使用 cv2.copyMakeBorder()
, and concatenate them together with the np.hstack()
方法为每个切片应用边框。
代码:
import cv2
import numpy as np
img = cv2.imread("lungs.png")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours, _ = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
(x1, y1, w1, h1), (x2, y2, w2, h2) = sorted(map(cv2.boundingRect, contours))
lung_1 = cv2.copyMakeBorder(img[y1: y1 + h2, x1: x1 + w1], 20, 20, 20, 20, cv2.BORDER_CONSTANT)
lung_2 = cv2.copyMakeBorder(img[y2: y2 + h2, x2: x2 + w2], 20, 20, 20, 20, cv2.BORDER_CONSTANT)
cv2.imshow("result", np.hstack((lung_1, lung_2)))
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
备注:
- 在行:
lung_1 = cv2.copyMakeBorder(img[y1: y1 + h2, x1: x1 + w1], 20, 20, 20, 20, cv2.BORDER_CONSTANT)
注意我们使用了h2
而不是h1
,就好像我们要使用我们定义的h1
一样,np.hstack()
方法会抛出错误,因为阵列的不同高度。
sorted()
在
(x1, y1, w1, h1), (x2, y2, w2, h2) = sorted(map(cv2.boundingRect, contours))
就是把x, y, w, h
按照x
属性排序,这样肺从左到右串联起来。
我使用在线合并工具合并了两张肺部图像以显示完整图像。
问题在于,由于每张图片的背景都是黑色,所以我在显示的图片中的肺部之间出现了不需要的间隙。
我想知道是否有办法使用带有算法的代码或在线工具从图像中删除一个区域并缩小肺部之间的间隙。
我检查的另一种方法是将 OpenCV 与 Python 一起用于全景图像拼接,我将尝试将其作为连接图像的最后手段。
我想要的结果:
这是我在 Python/OpenCV 的评论中提到的一种方式。
- 读取输入并转换为灰度
- 二进制的阈值
- 获取外部轮廓
- 过滤轮廓以仅保留大轮廓并将边界框值放入列表中。还要计算边界框的最大宽度和最大高度。
- 设置所需的填充量
- 创建最大宽度和最大高度的黑色图像
- 按 x 值对边界框列表进行排序
- 从列表中获取第一项并对其进行裁剪和填充
- 创建一个最大高度和所需 pad 大小的黑色图像
- 与之前的填充作物水平连接
- 从列表中获取第二个项目并对其进行裁剪和填充
- 与之前填充的结果水平连接
- 根据需要在四周填充
- 保存输出
输入:
import cv2
import numpy as np
# load image
img = cv2.imread("lungs_mask.png", cv2.IMREAD_GRAYSCALE)
# threshold
thresh = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)[1]
# get the largest contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
# get bounding boxes of each contour if area large and put into list
cntr_list=[]
max_ht = 0
max_wd = 0
for cntr in contours:
area = cv2.contourArea(cntr)
if area > 10000:
x,y,w,h = cv2.boundingRect(cntr)
cntr_list.append([x,y,w,h])
if h > max_ht:
max_ht = h
if w > max_wd:
max_wd = w
# set padded
padding = 25
# create black image of size max_wd,max_ht
black = np.zeros((max_ht,max_wd), dtype=np.uint8)
# sort contours by x value
def takeFirst(elem):
return elem[0]
cntr_list.sort(key=takeFirst)
# Take first entry in sorted list and crop and pad
item = cntr_list[0]
x = item[0]
y = item[1]
w = item[2]
h = item[3]
crop = thresh[y:y+h, x:x+w]
result = black[0:max_ht, 0:w]
result[0:h, 0:w] = crop
# create center padding and concatenate
pad_center_img = np.zeros((max_ht,padding), dtype=np.uint8)
result = cv2.hconcat((result, pad_center_img))
# Take second entry in sorted list and crop, pad and concatenate
item = cntr_list[1]
x = item[0]
y = item[1]
w = item[2]
h = item[3]
crop = thresh[y:y+h, x:x+w]
temp = black[0:max_ht, 0:w]
temp[0:h, 0:w] = crop
result = cv2.hconcat((result, temp))
# Pad all around as desired
result = cv2.copyMakeBorder(result, 25, 25, 25, 25, borderType=cv2.BORDER_CONSTANT, value=(0))
# write result to disk
cv2.imwrite("lungs_mask_cropped.jpg", result)
# display it
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.waitKey(0)
结果:
概念:
使用
cv2.findContours()
method, we will get an array of all the contours detected in the image specified. Normally, we would preprocess the image (for example, with thecv2.Canny()
方法),然后将其传递给cv2.findContours()
方法,但是由于我们现在拥有的图像是一个简单的二值图像,具有两个里面有非常明显的斑点,没有必要。我们使用
cv2.boundingBox()
方法找到每个轮廓的x, y, w, h
,以便我们可以从图像中切出该部分。我们使用
x, y, w, h
检测到图像的两个切片,使用cv2.copyMakeBorder()
, and concatenate them together with thenp.hstack()
方法为每个切片应用边框。
代码:
import cv2
import numpy as np
img = cv2.imread("lungs.png")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours, _ = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
(x1, y1, w1, h1), (x2, y2, w2, h2) = sorted(map(cv2.boundingRect, contours))
lung_1 = cv2.copyMakeBorder(img[y1: y1 + h2, x1: x1 + w1], 20, 20, 20, 20, cv2.BORDER_CONSTANT)
lung_2 = cv2.copyMakeBorder(img[y2: y2 + h2, x2: x2 + w2], 20, 20, 20, 20, cv2.BORDER_CONSTANT)
cv2.imshow("result", np.hstack((lung_1, lung_2)))
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
备注:
- 在行:
lung_1 = cv2.copyMakeBorder(img[y1: y1 + h2, x1: x1 + w1], 20, 20, 20, 20, cv2.BORDER_CONSTANT)
注意我们使用了h2
而不是h1
,就好像我们要使用我们定义的h1
一样,np.hstack()
方法会抛出错误,因为阵列的不同高度。
sorted()
在
(x1, y1, w1, h1), (x2, y2, w2, h2) = sorted(map(cv2.boundingRect, contours))
就是把x, y, w, h
按照x
属性排序,这样肺从左到右串联起来。