[英]How to extract a specific section of an image using OpenCV in Python?
I am trying to extract a portion of an image by performing Canny edge detection. 我试图通过执行Canny边缘检测来提取图像的一部分。 I have succesfully created a mask of that object. 我成功地创建了该对象的蒙版。 But when I perform a bitwise_and
operation with the original image, to extract the foreground section, I am getting the following error . 但是当我对原始图像执行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
My code is as follows - 我的代码如下 -
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()
NOTE :- The code works fine if I try to perform the bitwise_and
with a grayscale version of the image. 注意: - 如果我尝试使用灰度版本的图像执行bitwise_and
,则代码可以正常工作。 However RGB,HSV or any other color spaces give the error above. 但是,RGB,HSV或任何其他颜色空间会产生上述错误。
Please help. 请帮忙。
EDIT 1 - The image in question is this - 编辑1 -有问题的图像是这样的 -
EDIT 2- 编辑2-
The following is the result after using Numpy method. 以下是使用Numpy方法后的结果。 As you can see, the extracted image is the same size as the orange but it does not contain the orange instead the mask itself. 如您所见,提取的图像与橙色的大小相同,但它不包含橙色而不是蒙版本身。
EDIT 3- @DanMašek and @lightalchemist , I could finally extract any foreground image. 编辑3- @DanMašek和@lightalchemist,我终于可以提取任何前景图像了。
Thank you 谢谢
The error is telling you that you are trying to perform the bitwise_and operation on matrices where the entries are not integers. 该错误告诉您正在尝试对条目不是整数的矩阵执行bitwise_and操作。 I believe the matrices also have to have the same number of channels. 我相信矩阵也必须具有相同数量的通道。 This is why it works with your grayscale image but not with the HSV image. 这就是为什么它适用于您的灰度图像,而不适用于HSV图像。
Instead of using bitwise_and, it is easier and more flexible to just use numpy matrix vectorization to perform the masking like so: 而不是使用bitwise_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
Note that if your mask is a single channel matrix instead of a 3 channel matrix, you would have to modify the code to be 请注意,如果您的掩码是单个通道矩阵而不是3通道矩阵,则必须修改代码
new_image[mask < 255, :] = 0
I used the code provided above but only altered the line where the cv2.bitwise_and()
is used: 我使用了上面提供的代码,但只更改了使用cv2.bitwise_and()
的行:
new_image = cv2.bitwise_and(img_rgb, img_rgb, mask = equalize)
This is what I got and what you expected (I guess): 这就是我得到的和你的预期(我猜):
EDIT 编辑
I get it, you want to mask your image with an image of contour having the greatest area. 我明白了,你想要用最大面积的轮廓图像来掩盖你的图像。 In the following additional snippet I have binarized the image containing the contour of greatest area to be used as mask. 在下面的附加片段中,我将包含最大区域轮廓的图像二值化,以用作遮罩。
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)
This is what I got: 这就是我得到的:
Compared to the image above you do not see those holes inside the object of interest. 与上图相比,您不会在感兴趣的对象内看到这些洞。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.