OpenCV中的例程检测方框的代码报错问题修改

#!/usr/bin/env python

'''
Simple "Square Detector" program.

Loads several images sequentially and tries to find squares in each image.
'''

# Python 2/3 compatibility
from __future__ import print_function
import sys
PY3 = sys.version_info[0] == 3

if PY3:
    xrange = range

import numpy as np
import cv2 as cv


def angle_cos(p0, p1, p2):
    d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
    return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )

def find_squares(img):
    img = cv.GaussianBlur(img, (5, 5), 0)
    squares = []
    for gray in cv.split(img):
        for thrs in xrange(0, 255, 26):
            if thrs == 0:
                bin = cv.Canny(gray, 0, 50, apertureSize=5)
                bin = cv.dilate(bin, None)
            else:
                _retval, bin = cv.threshold(gray, thrs, 255, cv.THRESH_BINARY)
            contours, _hierarchy = cv.findContours(bin, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
            for cnt in contours:
                cnt_len = cv.arcLength(cnt, True)
                cnt = cv.approxPolyDP(cnt, 0.02*cnt_len, True)
                if len(cnt) == 4 and cv.contourArea(cnt) > 1000 and cv.isContourConvex(cnt):
                    cnt = cnt.reshape(-1, 2)
                    max_cos = np.max([angle_cos( cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4] ) for i in xrange(4)])
                    if max_cos < 0.1:
                        squares.append(cnt)
    return squares

def main():
    from glob import glob
    for fn in glob('../data/pic*.png'):
        img = cv.imread(fn)
        squares = find_squares(img)
        cv.drawContours( img, squares, -1, (0, 255, 0), 3 )
        cv.imshow('squares', img)
        ch = cv.waitKey()
        if ch == 27:
            break

    print('Done')


if __name__ == '__main__':
    print(__doc__)
    main()
    cv.destroyAllWindows()

修改项:
OpenCV版本不同,cv.findContours函数的返回值结构与您的代码不匹配。在较新版本的OpenCV中,cv.findContours函数只返回两个值:轮廓和层级信息,而不再返回二进制图像。

要解决这个问题,您需要修改您的代码,只获取轮廓信息,而不再获取不再返回二进制图像。在函数 find_squares 中,修改以下这行代码:

bin, contours, _hierarchy = cv.findContours(bin, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)

将其修改为:

contours, _hierarchy = cv.findContours(bin, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)

这样,您的代码将只获取轮廓信息,而不再尝试解包二进制图像,从而避免了 “not enough values to unpack” 错误。修改后的代码应该如下所示:

def find_squares(img):
    img = cv.GaussianBlur(img, (5, 5), 0)
    squares = []
    for gray in cv.split(img):
        for thrs in range(0, 255, 26):
            if thrs == 0:
                bin = cv.Canny(gray, 0, 50, apertureSize=5)
                bin = cv.dilate(bin, None)
            else:
                _retval, bin = cv.threshold(gray, thrs, 255, cv.THRESH_BINARY)
            contours, _hierarchy = cv.findContours(bin, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
            for cnt in contours:
                cnt_len = cv.arcLength(cnt, True)
                cnt = cv.approxPolyDP(cnt, 0.02*cnt_len, True)
                if len(cnt) == 4 and cv.contourArea(cnt) > 1000 and cv.isContourConvex(cnt):
                    cnt = cnt.reshape(-1, 2)
                    max_cos = np.max([angle_cos(cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4]) for i in range(4)])
                    if max_cos < 0.1:
                        squares.append(cnt)
    return squares

这应该解决了 “not enough values to unpack” 错误,使您的代码能够正常运行。

代码解析:

def find_squares(img):
    img = cv.GaussianBlur(img, (5, 5), 0)
    squares = []
    for gray in cv.split(img):

这段代码定义了一个名为 find_squares 的函数,该函数接受一个图像 img 作为输入参数。函数开始对输入图像进行高斯模糊处理,以减少噪声,这是为了更好地处理后续的图像处理步骤。然后,它创建了一个空列表 squares,以存储找到的正方形的坐标。

接下来的部分是一个循环,该循环遍历图像的灰度通道:

        for thrs in range(0, 255, 26):

这个循环在0到255的范围内,每隔26进行迭代,以查找不同阈值下的轮廓。

            if thrs == 0:
                bin = cv.Canny(gray, 0, 50, apertureSize=5)
                bin = cv.dilate(bin, None)
            else:
                _retval, bin = cv.threshold(gray, thrs, 255, cv.THRESH_BINARY)

在循环中,首先检查阈值 thrs 是否为0。如果是0,它会执行Canny边缘检测,并将结果存储在名为 bin 的二进制图像中。然后,它对二进制图像进行膨胀操作。膨胀是一种形态学操作,用于增强图像中的边缘。

如果阈值 thrs 不为0,它将执行阈值二值化操作,将灰度图像转换为二进制图像。这两种方法用于查找图像中的边缘和轮廓。

            contours, _hierarchy = cv.findContours(bin, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)

接下来,它使用 cv.findContours 函数查找二进制图像中的轮廓。该函数返回轮廓列表 contours 和层次信息(在这里未使用)。

            for cnt in contours:

接下来是另一个循环,它遍历找到的轮廓。

                cnt_len = cv.arcLength(cnt, True)

对于每个轮廓,它计算轮廓的长度。

                cnt = cv.approxPolyDP(cnt, 0.02 * cnt_len, True)

然后,它使用多边形逼近方法(cv.approxPolyDP)将轮廓近似为更简单的多边形。这是为了找到具有更少顶点的多边形,以帮助确定是否是正方形。

                if len(cnt) == 4 and cv.contourArea(cnt) > 1000 and cv.isContourConvex(cnt):

接下来,它检查轮廓是否包含4个顶点,是否具有足够大的面积,以及它是否是凸多边形。这些条件用于确定找到的多边形是否是正方形。

                    cnt = cnt.reshape(-1, 2)
                    max_cos = np.max([angle_cos(cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4]) for i in range(4)])

如果满足上述条件,它将多边形的坐标重塑为一维数组,然后计算多边形的角度。

                    if max_cos < 0.1:
                        squares.append(cnt)

最后,它检查多边形的角度是否接近于直角(cosine值小于0.1),如果是,就将该多边形添加到 squares 列表中。

    return squares

最后,函数返回包含找到的正方形坐标的 squares 列表。

这个函数的目的是在图像中查找正方形轮廓,并返回这些轮廓的坐标。您可以在您的代码中调用这个函数,然后进一步处理或标记找到的正方形。

你可能感兴趣的:(opencv,人工智能,计算机视觉)