我在使用OpenCV的findContours(...)
方法查找单个通道图像中的轮廓时遇到了麻烦。图像实际上是一个numpy数组,其形状为(128, 128)
,元素的实际值介于[0.0,1.0]
之间。最初形状为(1,128,128,1)
,但我使用np.squeeze(...)
来摆脱第一个和最后一个维度。保留其中任何一个都不能解决我的问题。
我尝试过的事情:
image = np.squeeze(array) #using np.squeeze(array, [0]) won't help.
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(image, 1, 2)
以上代码导致以下异常:
error: (-215) scn == 3 || scn == 4 in function cv::cvtColor
我也尝试过:
如果我直接应用findContours(...)
,那么不使用cvtColor(...)
,我会收到其他错误:
error: (-210) [Start]FindContours supports only CV_8UC1 images when mode != CV_RETR_FLOODFILL otherwise supports CV_32SC1 images only in function cvStartFindContours_Impl
有些消息来源建议使用threshold
来获取findContours(...)
[1]所需的二进制图片
ret, thresh = cv2.threshold(image, 1, 255, 0)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
这也不会有任何帮助,我会收到抱怨CV_8UC1
支持的相同异常。
答案 0 :(得分:3)
图像实际上是一个numpy数组,其形状为
(128, 128)
,元素的实际值介于[0.0,1.0]
之间。
来自cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
的错误是由于您尝试将单个频道图像从BGR(3个频道)转换为灰度(1个频道)。您的图像已经是灰度图像,因此不需要执行此步骤。
来自cv2.findContours
的错误是由于数组中元素的错误数据类型造成的。文档说明了输入图像:
Source,一个8位单通道图像。非零像素被视为1。零像素保持为0,因此图像被视为二进制。您可以使用
compare
,inRange
,threshold
,adaptiveThreshold
,Canny
和其他人使用灰度或彩色图像创建二进制图像。如果mode等于RETR_CCOMP
或RETR_FLOODFILL
,则输入也可以是标签的32位整数图像(CV_32SC1
)。
要解决此问题,您需要将图片中的值缩放到范围[0.0,255.0]
,然后将结果转换为np.uint8
:
image_8bit = np.uint8(image * 255)
关于您的问题中的代码,还有其他一些问题或怪癖。
首先,在一个片段cv2.findContours
中返回2个值(OpenCV 2.x),在另一个片段中返回3个值(OpenCV 3.x)。你使用的是哪个版本?
您的第一个代码示例包含以下内容:
contours, hierarchy = cv2.findContours(image, 1, 2)
避免使用魔术数字。 1
对应cv2.RETR_LIST
,2
对应cv2.CHAIN_APPROX_SIMPLE
。由于RETR_LIST
模式不会生成任何层次结构,因此您可以忽略该返回值:
contours, _ = cv2.findContours(binarized, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
另一个问题很可能是最初你没有明确地对图像进行二值化(例如使用cv2.threshold
)。虽然这不会导致异常,但结果可能没有多大意义 - findContours
将像素分为两组 - 零,然后一切都非零。您很可能希望它们以不同方式进行分区。
threshold_level = 127 # Set as you need...
_, binarized = cv2.threshold(image_8bit, threshold_level, 255, cv2.THRESH_BINARY)
示例脚本(OpenCV 3.x):
import numpy as np
import cv2
# Generate random image matching your description:
# shape is (128,128), values are real numbers in range [0,1]
image = np.random.uniform(0, np.nextafter(1,2), (128,128))
# Scale and convert data type
image_8bit = np.uint8(image * 255)
threshold_level = 127 # Set as you need...
_, binarized = cv2.threshold(image_8bit, threshold_level, 255, cv2.THRESH_BINARY)
_, contours, hierarchy = cv2.findContours(binarized, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# ... processing the contours, etc.
答案 1 :(得分:1)
试试这个:
cv2.threshold(image, 1, 255, cv2.THRESH_BINARY,image)
im2, contours, hierarchy = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
答案 2 :(得分:0)
cv2.findContours函数接受阈值图像。由于您的输入图像是灰度图像,因此给出了错误。