代码之家  ›  专栏  ›  技术社区  ›  Boudhayan Dev

如何在Python中使用OpenCV提取图像的特定部分?

  •  7
  • Boudhayan Dev  · 技术社区  · 7 年前

    我试图通过执行Canny边缘检测来提取图像的一部分。我成功地创建了该对象的掩码。但当我执行 bitwise_and 操作原始图像,提取前景部分,我得到以下错误。

    OpenCV Error: Assertion failed ((mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1)) in cv::binary_op, file C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp, line 241
        Traceback (most recent call last):
          File "C:\Users\Boudhayan Dev\Desktop\extraction.py", line 37, in <module>
            new_image = cv2.bitwise_and(img_rgb,img_rgb,mask=mask)
        cv2.error: C:\projects\opencv-python\opencv\modules\core\src\arithm.cpp:241: error: (-215) (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1) in function cv::binary_op
    

    我的代码如下-

    import cv2
    import numpy as np
    
    img_rgb = cv2.imread("3.jpg")
    cv2.namedWindow("Original Image",cv2.WINDOW_NORMAL)
    
    img = cv2.cvtColor(img_rgb,cv2.COLOR_RGB2HSV)
    img = cv2.bilateralFilter(img,9,105,105)
    r,g,b=cv2.split(img)
    equalize1= cv2.equalizeHist(r)
    equalize2= cv2.equalizeHist(g)
    equalize3= cv2.equalizeHist(b)
    equalize=cv2.merge((r,g,b))
    
    equalize = cv2.cvtColor(equalize,cv2.COLOR_RGB2GRAY)
    
    ret,thresh_image = cv2.threshold(equalize,0,255,cv2.THRESH_OTSU+cv2.THRESH_BINARY)
    equalize= cv2.equalizeHist(thresh_image)
    
    
    canny_image = cv2.Canny(equalize,250,255)
    canny_image = cv2.convertScaleAbs(canny_image)
    kernel = np.ones((3,3), np.uint8)
    dilated_image = cv2.dilate(canny_image,kernel,iterations=1)
    
    
    new,contours, hierarchy = cv2.findContours(dilated_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    contours= sorted(contours, key = cv2.contourArea, reverse = True)[:10]
    c=contours[0]
    print(cv2.contourArea(c))
    final = cv2.drawContours(img, [c], -1, (255,0, 0), 3)
    
    
    
    mask = np.zeros(img_rgb.shape,np.uint8)
    new_image = cv2.drawContours(mask,[c],0,255,-1,)
    new_image = cv2.bitwise_and(img_rgb,img_rgb,mask=mask)
    
    
    cv2.namedWindow("new",cv2.WINDOW_NORMAL)
    cv2.imshow("new",new_image)
    
    cv2.imshow("Original Image",img)
    cv2.waitKey() 
    

    注意:-如果我尝试执行 按位\u和 具有灰度版本的图像。但是,RGB、HSV或任何其他颜色空间会产生上述错误。

    请帮忙。


    编辑1- 问题的图像是-

    3.jpeg

    编辑2-

    下面是使用Numpy方法后的结果。如您所见,提取的图像与橙色大小相同,但它不包含橙色,而是包含遮罩本身。

    result

    编辑3- @丹·梅克和@LightAlchest,我终于可以提取任何前景图像了。

    result1

    result2

    非常感谢。

    2 回复  |  直到 7 年前
        1
  •  4
  •   Jeru Luke    7 年前

    我使用了上面提供的代码,但只修改了 cv2.bitwise_and() 使用时间:

    new_image = cv2.bitwise_and(img_rgb, img_rgb, mask = equalize)
    

    这就是我所得到的,也是你所期望的(我猜):

    enter image description here

    编辑

    我明白了,你想用一个面积最大的轮廓图像来遮罩你的图像。在下面的附加片段中,我对包含要用作遮罩的最大面积轮廓的图像进行了二值化。

    new_image = cv2.drawContours(mask,[c], -1, (255,255,255), -1)
    new_image_gray = cv2.cvtColor(new_image, cv2.COLOR_BGR2GRAY)
    ret, thresh1 = cv2.threshold(new_image_gray, 100, 255, cv2.THRESH_BINARY)
    final = cv2.bitwise_and(img_rgb, img_rgb, mask = thresh1)
    

    这就是我得到的:

    enter image description here

    与上面的图像相比,您看不到感兴趣对象内部的那些孔。

        2
  •  1
  •   lightalchemist    7 年前

    错误告诉您,您正在尝试对条目不是整数的矩阵执行按位与运算。我相信矩阵也必须有相同数量的通道。这就是为什么它适用于灰度图像,而不适用于HSV图像。

    与其使用bitwise\u and,不如使用numpy矩阵矢量化来执行如下掩蔽:

    mask = np.zeros_like(img_rgb, dtype=np.uint8)
    
    # I believe you want to draw the filled in contour on the mask
    # You code actually assigns the resulting mask to new_image
    # But that does not affect things as drawContours modifies mask in place
    mask = cv2.drawContours(mask, [c] ,0, 255, -1) 
    
    new_image = img_rgb.copy()
    new_image[mask < 255] = 0  # Set values not masked to be 0
    

    请注意,如果掩码是单通道矩阵而不是3通道矩阵,则必须将代码修改为

    new_image[mask < 255, :] = 0