如何裁剪轮廓的内部区域?
How to crop the internal area of a contour?
我正在研究视网膜眼底 images.The 图像由黑色背景上的圆形视网膜组成。使用 OpenCV,我设法获得了围绕整个圆形 Retina 的轮廓。我需要的是从黑色背景中裁剪出圆形视网膜。
您的问题不清楚您是要实际裁剪轮廓内定义的信息还是屏蔽掉与所选轮廓无关的信息。我将探讨在这两种情况下该怎么做。
屏蔽信息
假设您 运行 cv2.findContours
on your image, you will have received a structure that lists all of the contours available in your image. I'm also assuming that you know the index of the contour that was used to surround the object you want. Assuming this is stored in idx
, first use cv2.drawContours
将此轮廓的 填充 版本绘制到空白图像上,然后使用此图像索引到您的图像中提取出对象。此逻辑 屏蔽 任何不相关的信息,只保留重要的信息 - 这是在您选择的轮廓内定义的。执行此操作的代码如下所示,假设您的图像是存储在 img
:
中的灰度图像
import numpy as np
import cv2
img = cv2.imread('...', 0) # Read in your image
# contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x
_, contours, _ = cv2.findContours(...) # Your call to find the contours
idx = ... # The index of the contour that surrounds your object
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask
out = np.zeros_like(img) # Extract out the object and place into output image
out[mask == 255] = img[mask == 255]
# Show the output image
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
如果你真的想裁剪...
如果要裁剪图像,需要定义轮廓定义区域的最小跨度边界框。您可以找到边界框的左上角和右下角,然后使用索引裁剪出您需要的内容。代码会和以前一样,但是会有一个额外的裁剪步骤:
import numpy as np
import cv2
img = cv2.imread('...', 0) # Read in your image
# contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x
_, contours, _ = cv2.findContours(...) # Your call to find the contours
idx = ... # The index of the contour that surrounds your object
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask
out = np.zeros_like(img) # Extract out the object and place into output image
out[mask == 255] = img[mask == 255]
# Now crop
(y, x) = np.where(mask == 255)
(topy, topx) = (np.min(y), np.min(x))
(bottomy, bottomx) = (np.max(y), np.max(x))
out = out[topy:bottomy+1, topx:bottomx+1]
# Show the output image
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
裁剪代码的工作原理是,当我们定义掩码以提取轮廓定义的区域时,我们还会找到定义轮廓左上角的最小水平和垂直坐标。我们类似地找到定义轮廓左下角的最大水平和垂直坐标。然后我们使用这些坐标的索引来裁剪我们实际需要的内容。请注意,这会对 masked 图像执行裁剪 - 即删除除最大轮廓中包含的信息以外的所有内容的图像。
用 OpenCV 注释 3.x
需要注意的是,以上代码假定您使用的是 OpenCV 2.4.x。请注意,在 OpenCV 3.x 中,cv2.findContours
的定义已更改。具体来说,输出是一个三元素元组输出,其中第一个图像是源图像,而其他两个参数与 OpenCV 2.4.x 中的相同。因此,只需更改上面代码中的 cv2.findContours
语句即可忽略第一个输出:
_, contours, _ = cv2.findContours(...) # Your call to find contours
这是裁剪矩形 ROI 的另一种方法。主要思想是使用 Canny 边缘检测 找到视网膜的边缘,找到轮廓,然后使用 Numpy 切片提取 ROI。假设您有这样的输入图像:
提取的投资回报率
import cv2
# Load image, convert to grayscale, and find edges
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1]
# Find contour and sort by contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
# Find bounding box and extract ROI
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
break
cv2.imshow('ROI',ROI)
cv2.imwrite('ROI.png',ROI)
cv2.waitKey()
这是一个非常简单的方法。用透明度遮盖图像。
- 阅读图片
- 制作一个灰度版本。
- 大津门槛
- 将形态学打开和关闭应用于阈值图像作为掩码
- 将掩码放入输入的 alpha 通道
- 保存输出
输入
代码
import cv2
import numpy as np
# load image as grayscale
img = cv2.imread('retina.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold input image using otsu thresholding as mask and refine with morphology
ret, mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((9,9), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
# put mask into alpha channel of result
result = img.copy()
result = cv2.cvtColor(result, cv2.COLOR_BGR2BGRA)
result[:, :, 3] = mask
# save resulting masked image
cv2.imwrite('retina_masked.png', result)
输出
我正在研究视网膜眼底 images.The 图像由黑色背景上的圆形视网膜组成。使用 OpenCV,我设法获得了围绕整个圆形 Retina 的轮廓。我需要的是从黑色背景中裁剪出圆形视网膜。
您的问题不清楚您是要实际裁剪轮廓内定义的信息还是屏蔽掉与所选轮廓无关的信息。我将探讨在这两种情况下该怎么做。
屏蔽信息
假设您 运行 cv2.findContours
on your image, you will have received a structure that lists all of the contours available in your image. I'm also assuming that you know the index of the contour that was used to surround the object you want. Assuming this is stored in idx
, first use cv2.drawContours
将此轮廓的 填充 版本绘制到空白图像上,然后使用此图像索引到您的图像中提取出对象。此逻辑 屏蔽 任何不相关的信息,只保留重要的信息 - 这是在您选择的轮廓内定义的。执行此操作的代码如下所示,假设您的图像是存储在 img
:
import numpy as np
import cv2
img = cv2.imread('...', 0) # Read in your image
# contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x
_, contours, _ = cv2.findContours(...) # Your call to find the contours
idx = ... # The index of the contour that surrounds your object
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask
out = np.zeros_like(img) # Extract out the object and place into output image
out[mask == 255] = img[mask == 255]
# Show the output image
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
如果你真的想裁剪...
如果要裁剪图像,需要定义轮廓定义区域的最小跨度边界框。您可以找到边界框的左上角和右下角,然后使用索引裁剪出您需要的内容。代码会和以前一样,但是会有一个额外的裁剪步骤:
import numpy as np
import cv2
img = cv2.imread('...', 0) # Read in your image
# contours, _ = cv2.findContours(...) # Your call to find the contours using OpenCV 2.4.x
_, contours, _ = cv2.findContours(...) # Your call to find the contours
idx = ... # The index of the contour that surrounds your object
mask = np.zeros_like(img) # Create mask where white is what we want, black otherwise
cv2.drawContours(mask, contours, idx, 255, -1) # Draw filled contour in mask
out = np.zeros_like(img) # Extract out the object and place into output image
out[mask == 255] = img[mask == 255]
# Now crop
(y, x) = np.where(mask == 255)
(topy, topx) = (np.min(y), np.min(x))
(bottomy, bottomx) = (np.max(y), np.max(x))
out = out[topy:bottomy+1, topx:bottomx+1]
# Show the output image
cv2.imshow('Output', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
裁剪代码的工作原理是,当我们定义掩码以提取轮廓定义的区域时,我们还会找到定义轮廓左上角的最小水平和垂直坐标。我们类似地找到定义轮廓左下角的最大水平和垂直坐标。然后我们使用这些坐标的索引来裁剪我们实际需要的内容。请注意,这会对 masked 图像执行裁剪 - 即删除除最大轮廓中包含的信息以外的所有内容的图像。
用 OpenCV 注释 3.x
需要注意的是,以上代码假定您使用的是 OpenCV 2.4.x。请注意,在 OpenCV 3.x 中,cv2.findContours
的定义已更改。具体来说,输出是一个三元素元组输出,其中第一个图像是源图像,而其他两个参数与 OpenCV 2.4.x 中的相同。因此,只需更改上面代码中的 cv2.findContours
语句即可忽略第一个输出:
_, contours, _ = cv2.findContours(...) # Your call to find contours
这是裁剪矩形 ROI 的另一种方法。主要思想是使用 Canny 边缘检测 找到视网膜的边缘,找到轮廓,然后使用 Numpy 切片提取 ROI。假设您有这样的输入图像:
提取的投资回报率
import cv2
# Load image, convert to grayscale, and find edges
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1]
# Find contour and sort by contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
# Find bounding box and extract ROI
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
break
cv2.imshow('ROI',ROI)
cv2.imwrite('ROI.png',ROI)
cv2.waitKey()
这是一个非常简单的方法。用透明度遮盖图像。
- 阅读图片
- 制作一个灰度版本。
- 大津门槛
- 将形态学打开和关闭应用于阈值图像作为掩码
- 将掩码放入输入的 alpha 通道
- 保存输出
输入
代码
import cv2
import numpy as np
# load image as grayscale
img = cv2.imread('retina.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold input image using otsu thresholding as mask and refine with morphology
ret, mask = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel = np.ones((9,9), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
# put mask into alpha channel of result
result = img.copy()
result = cv2.cvtColor(result, cv2.COLOR_BGR2BGRA)
result[:, :, 3] = mask
# save resulting masked image
cv2.imwrite('retina_masked.png', result)