opencv无法提取图像中的最大轮廓
opencv can't extract biggest contour in image
考虑这张图片:
我只想提取代表图像中最大轮廓的数字,但 opencv 总是显示原始图像和小于数字的小轮廓。所以当我运行这个函数
def contouTreat(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="left-to-right")
cv2.drawContours(image, cnts, -1, (0, 255, 0), 3)
#cv2_imshow(image)
ROI_number = 0
arr=[]
v=True
for c in cnts:
area = cv2.contourArea(c)
if area != image.shape[1]*image.shape[0]:
x,y,w,h = cv2.boundingRect(c)
#if minc != x:
x,y,w,h = cv2.boundingRect(c)
#if area < 800 and area > 200:
#if area < 1620 and h>58 and w <50:
#if h>(70*image.shape[1])/100 and w>(60*image.shape[0])/100 :
if v:
ROI = image[y:y+h, x:x+w]
print(h)
print(w)
cv2_imshow(ROI)
return None
image=cv2.imread("/content/téléchargement (2).png")
contouTreat(image)
我得到了这个结果:
您在同一张图像上绘制轮廓,因此使用两个绘制的轮廓可以获得更大的 ROI。
建议的解决方案:
在填充零的临时图像上绘制每个轮廓,并从临时图像中裁剪 ROI。
创建用零填充的临时图像:
tmp_im = np.zeros_like(image)
绘制一个白色填充的轮廓,并将其用作遮罩:
cv2.drawContours(tmp_im, [c], 0, (255, 255, 255), cv2.FILLED) # Draw white contour on black image
tmp_im = cv2.bitwise_and(image, tmp_im) # Apply bitwise with `image` - required in case there are black regions inside the contour.
在轮廓周围画绿线(可能不需要):
cv2.drawContours(tmp_im, [c], -1, (0, 255, 0), 3) # Draw green line around the contour
裁剪 ROI:
ROI = tmp_im[y:y + h, x:x + w]
完整代码示例:
import numpy as np
import cv2
from imutils import contours
def contouTreat(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="left-to-right")
cv2.drawContours(image, cnts, -1, (0, 255, 0), 3)
#cv2_imshow(image)
ROI_number = 0
arr = []
v = True
for c in cnts:
area = cv2.contourArea(c)
if area != image.shape[1] * image.shape[0]:
x,y,w,h = cv2.boundingRect(c)
if v:
tmp_im = np.zeros_like(image)
cv2.drawContours(tmp_im, [c], 0, (255, 255, 255), cv2.FILLED) # Draw white contour on black image
tmp_im = cv2.bitwise_and(image, tmp_im) # Apply bitwise with `image` - required in case there are black regions inside the contour.
cv2.drawContours(tmp_im, [c], -1, (0, 255, 0), 3) # Draw green line around the contour
ROI = tmp_im[y:y + h, x:x + w]
print(h)
print(w)
cv2.imshow('ROI' + str(ROI_number), ROI)
ROI_number += 1
return None
image = cv2.imread("telechargement.png")
contouTreat(image)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
ROI0:
ROI1:
考虑这张图片:
我只想提取代表图像中最大轮廓的数字,但 opencv 总是显示原始图像和小于数字的小轮廓。所以当我运行这个函数
def contouTreat(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="left-to-right")
cv2.drawContours(image, cnts, -1, (0, 255, 0), 3)
#cv2_imshow(image)
ROI_number = 0
arr=[]
v=True
for c in cnts:
area = cv2.contourArea(c)
if area != image.shape[1]*image.shape[0]:
x,y,w,h = cv2.boundingRect(c)
#if minc != x:
x,y,w,h = cv2.boundingRect(c)
#if area < 800 and area > 200:
#if area < 1620 and h>58 and w <50:
#if h>(70*image.shape[1])/100 and w>(60*image.shape[0])/100 :
if v:
ROI = image[y:y+h, x:x+w]
print(h)
print(w)
cv2_imshow(ROI)
return None
image=cv2.imread("/content/téléchargement (2).png")
contouTreat(image)
我得到了这个结果:
您在同一张图像上绘制轮廓,因此使用两个绘制的轮廓可以获得更大的 ROI。
建议的解决方案:
在填充零的临时图像上绘制每个轮廓,并从临时图像中裁剪 ROI。
创建用零填充的临时图像:
tmp_im = np.zeros_like(image)
绘制一个白色填充的轮廓,并将其用作遮罩:
cv2.drawContours(tmp_im, [c], 0, (255, 255, 255), cv2.FILLED) # Draw white contour on black image tmp_im = cv2.bitwise_and(image, tmp_im) # Apply bitwise with `image` - required in case there are black regions inside the contour.
在轮廓周围画绿线(可能不需要):
cv2.drawContours(tmp_im, [c], -1, (0, 255, 0), 3) # Draw green line around the contour
裁剪 ROI:
ROI = tmp_im[y:y + h, x:x + w]
完整代码示例:
import numpy as np
import cv2
from imutils import contours
def contouTreat(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
(cnts, _) = contours.sort_contours(cnts, method="left-to-right")
cv2.drawContours(image, cnts, -1, (0, 255, 0), 3)
#cv2_imshow(image)
ROI_number = 0
arr = []
v = True
for c in cnts:
area = cv2.contourArea(c)
if area != image.shape[1] * image.shape[0]:
x,y,w,h = cv2.boundingRect(c)
if v:
tmp_im = np.zeros_like(image)
cv2.drawContours(tmp_im, [c], 0, (255, 255, 255), cv2.FILLED) # Draw white contour on black image
tmp_im = cv2.bitwise_and(image, tmp_im) # Apply bitwise with `image` - required in case there are black regions inside the contour.
cv2.drawContours(tmp_im, [c], -1, (0, 255, 0), 3) # Draw green line around the contour
ROI = tmp_im[y:y + h, x:x + w]
print(h)
print(w)
cv2.imshow('ROI' + str(ROI_number), ROI)
ROI_number += 1
return None
image = cv2.imread("telechargement.png")
contouTreat(image)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
ROI0:
ROI1: