OpenCv(Python)中单通道图像的FindContours

时间:2018-04-21 15:38:03

标签: python numpy opencv

我在使用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支持的相同异常。

3 个答案:

答案 0 :(得分:3)

  

图像实际上是一个numpy数组,其形状为(128, 128),元素的实际值介于[0.0,1.0]之间。

来自cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)的错误是由于您尝试将单个频道图像从BGR(3个频道)转换为灰度(1个频道)。您的图像已经是灰度图像,因此不需要执行此步骤。

来自cv2.findContours的错误是由于数组中元素的错误数据类型造成的。文档说明了输入图像:

  

Source,一个8位单通道图像。非零像素被视为1。零像素保持为0,因此图像被视为二进制。您可以使用compareinRangethresholdadaptiveThresholdCanny和其他人使用灰度或彩色图像创建二进制图像。如果mode等于RETR_CCOMPRETR_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_LIST2对应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函数接受阈值图像。由于您的输入图像是灰度图像,因此给出了错误。