有两个轮廓cv2.findContour只找到一个

2024-03-29 13:59:19 发布

您现在位置:Python中文网/ 问答频道 /正文

cv2.findContours对二进制图像效果更好。所以我对输入图像input image设置阈值

我得到了这个阈值图像 thresholded image

然后,我一直试图找到并裁剪这两个轮廓。因此,我看到一个小的黑色块的轮廓之一

result

当我尝试不同的样品时,我看到了预期的结果。我的目的是找到白色带的上下两侧

enter image description here 这是一个最小的可重复的例子

import cv2
import numpy as np
frame = cv2.imread('frame8.png')

frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(frame, cv2.COLOR_RGB2HSV)
lower_limit = np.array([0, 0, 94])
upper_limit = np.array([255, 255, 255])
mask = cv2.inRange(hsv, lower_limit, upper_limit)  #created a mask to remove background
mask_inv = cv2.bitwise_not(mask)
bg = cv2.bitwise_and(frame, frame, mask=mask)
fg = cv2.bitwise_and(frame, frame, mask=mask_inv)
gray = cv2.cvtColor(bg,cv2.COLOR_RGB2GRAY)
thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)[1] #findContours function works better with binary images
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) #remove noise
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
cv2.imshow('thres',thresh)
cntrs = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
area_thresh = 5000
cnt = 0
for c in cntrs:
    area = cv2.contourArea(c)
    if area > area_thresh:
        cnt= cnt + 1
    if cnt > 0:
        rect = cv2.minAreaRect(c) #minArearect returns - ( center (x,y), (width, height), angle of rotation ).
        box = cv2.boxPoints(rect) # The function finds the four vertices of a rotated rectangle.
        box = np.int0(box) #converting numbers to integer
        # crop image inside bounding box
        centerX = rect[0][0]
        centerY = rect[0][1]
        W = rect[1][0] #width of contour
        H = rect[1][1] #height of contour
        Xs = [i[0] for i in box]
        Ys = [i[1] for i in box]
        x1 = min(Xs)
        x2 = max(Xs)
        y1 = min(Ys)
        y2 = max(Ys)
        angle = rect[2]
        rotated = False
        if angle < -45:
            angle += 90
            rotated = True
        center = (round(centerX), round(centerY))
        size = (int((x2 - x1)), int( (y2 - y1)))
        M = cv2.getRotationMatrix2D((size[0] / 2, size[1] / 2), angle, 1.0)
        cropped = cv2.getRectSubPix(frame, size, center) #crop contour
        cropped = cv2.warpAffine(cropped, M, size) #rotate contour using 2D-RotationMatrix
        croppedW = W if not rotated else H
        croppedH = H if not rotated else W
        image = cv2.getRectSubPix(
            cropped, (int(croppedW ), int(croppedH)), (size[0] / 2, size[1] / 2)) #crop contour
        for x in range(0, image.shape[0]):
            for y in range(0, image.shape[1]):
                if image[x, y, 0] > 50 or image[x, y, 1] > 50 or image[x, y, 2] > 50:
                    image[x, y, 0] = 0
                    image[x, y, 1] = 0
                    image[x, y, 2] = 0
        if croppedH > croppedW:
            if cnt == 1:
                output1 = image[0:image.shape[0], 0: image.shape[1]]
            if cnt == 2:
                output2 = image[0:image.shape[0], 0: image.shape[1]]
cv2.imshow('output2',output2)
cv2.imshow('output1',output1)
cv2.waitKey(0)

Tags: inrectimageboxforsizeifmask
1条回答
网友
1楼 · 发布于 2024-03-29 13:59:19

对于您提供的图像,此代码运行良好:

import matplotlib.pyplot as plt
import cv2
import numpy as np
frame= cv2.imread('frame8.png')

frame_gray= cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
clahe= cv2.createCLAHE(clipLimit=0.9,tileGridSize=(8,8))
frame_gray_1= clahe.apply(frame_gray)

ret, otsu= cv2.threshold(frame_gray_1,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

kernel = np.ones((2,2),np.uint8)
otsu = cv2.morphologyEx(otsu, cv2.MORPH_OPEN, kernel, iterations = 2) 
otsu = cv2.dilate(otsu, kernel, iterations = 4) 

h, w = frame.shape[:2]
mask = np.zeros((h, w), np.uint8)

contours, hierarchy = cv2.findContours(otsu, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
contours_sorted = sorted(contours, key=lambda x: cv2.contourArea(x), reverse= True)
cv2.drawContours(mask, [contours_sorted[0], contours_sorted[1]],-1, 255, -1)
res_img= cv2.bitwise_and(frame, frame, mask= mask)

绘制“res_img”:

plt.imshow(cv2.cvtColor(res_img, cv2.COLOR_BGR2RGB))
plt.show()

Here's the result.

也可以尝试其他样品

相关问题 更多 >