Gau*_*til 17 python opencv image image-processing contour
我正在研究视网膜眼底图像.图像由黑色背景上的圆形视网膜组成.通过OpenCV,我设法获得了围绕整个圆形Retina的轮廓.我需要的是从黑色背景中裁剪出圆形视网膜.
ray*_*ica 34
在您的问题中,您是否想要实际裁剪轮廓中定义的信息或屏蔽与所选轮廓无关的信息,这一点尚不清楚.我将探讨在两种情况下应该做些什么.
假设您运行cv2.findContours
了图像,您将收到一个列出图像中所有可用轮廓的结构.我还假设您知道用于包围所需对象的轮廓索引.假设存储了此内容idx
,首先使用此轮廓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()
Run Code Online (Sandbox Code Playgroud)
如果要裁剪图像,则需要定义轮廓定义的区域的最小跨越边界框.您可以找到边界框的左上角和右下角,然后使用索引来裁剪出您需要的内容.代码将与之前相同,但会有一个额外的裁剪步骤:
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()
Run Code Online (Sandbox Code Playgroud)
裁剪代码的工作原理是,当我们定义遮罩以提取轮廓定义的区域时,我们还会找到定义轮廓左上角的最小水平和垂直坐标.我们同样找到了最大的水平和垂直坐标,它们定义了轮廓的左下角.然后,我们使用这些坐标的索引来裁剪我们实际需要的东西.请注意,这会对蒙版图像执行裁剪- 即删除除最大轮廓中包含的信息之外的所有内容的图像.
应该注意的是,上面的代码假设您使用的是OpenCV 2.4.x. 请注意,在OpenCV 3.x中,定义cv2.drawContours
已更改.具体来说,输出是三元素元组输出,其中第一个图像是源图像,而其他两个参数与OpenCV 2.4.x中的相同.因此,只需更改cv2.findContours
上面代码中的语句即可忽略第一个输出:
_, contours, _ = cv2.findContours(...) # Your call to find contours
Run Code Online (Sandbox Code Playgroud)
这是一个非常简单的方法。用透明度掩盖图像。
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)
Run Code Online (Sandbox Code Playgroud)
这是另一种裁剪矩形 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()
Run Code Online (Sandbox Code Playgroud)