【问题标题】:I have a python script that uses OpenCV, code works in python 2.7 but not python 3.7 and I am not sure why [duplicate]我有一个使用 OpenCV 的 python 脚本,代码在 python 2.7 中有效,但在 python 3.7 中无效,我不知道为什么[重复]
【发布时间】:2021-01-13 10:10:06
【问题描述】:

所以我正在做一个项目,有人给了我一些他们在 python 2.7 中创建的代码来实现它。然而,该项目在 python 3.7 上运行,当我尝试执行它时,我不断收到与标记函数相关的错误。有人可以查看它并告诉我缺少什么来执行该版本吗?我附上了用于测试功能的图像以及代码。

以下是我得到的错误:

Traceback (most recent call last):
  File "/home/pi/Downloads/distance_to_camera_2 (1).py", line 94, in <module>
    width_array=process_component(labels_im)
  File "/home/pi/Downloads/distance_to_camera_2 (1).py", line 71, in process_component
    x,y,w,h = cv2.boundingRect(cnts[0])
TypeError: Expected cv::UMat for argument 'array'

这是代码:

import numpy as np
import cv2
from matplotlib import pyplot as plt



# Find distance from camera to object using Python and OpenCV
def distance_to_camera(knownWidth, focalLength, perWidth):
    # compute and return the distance from the maker to the camera
    return (knownWidth * focalLength) / perWidth



KNOWN_WIDTH = 8
focalLength = 545
# put your image here
img = cv2.imread("/home/pi/Downloads/many_blob.png")
cv2.imshow("img", img)
cv2.waitKey(1000)
image = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)[1]  # ensure binary 127
cv2.imshow("image", image)
cv2.waitKey(1000)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(image,kernel,iterations = 5)
dilate=cv2.dilate(erosion,kernel,iterations = 5)
edged = cv2.Canny(dilate, 0, 128)
cv2.imshow("edged", edged)
cv2.waitKey(1000)

connectivity=8
num_labels,labels_im = cv2.connectedComponents(edged,connectivity)

# Function only for labels display  (debuging only)
def imshow_components(labels):
    # Map component labels to hue val
    label_hue = np.uint8(179*labels/np.max(labels))
    blank_ch = 255*np.ones_like(label_hue)
    labeled_img = cv2.merge([label_hue, blank_ch, blank_ch])

    # cvt to BGR for display
    labeled_img = cv2.cvtColor(labeled_img, cv2.COLOR_HSV2BGR)

    # set bg label to black
    labeled_img[label_hue==0] = 0
    #labeled_img[labels==0] = 0

    cv2.imshow('labeled.png', labeled_img)
    cv2.waitKey(1000)
    cv2.imwrite('labeled_img.png',labeled_img)
    #cv2.imwrite('label_hue.png',label_hue)

def process_component(labels):
    width = np.zeros(np.max(labels))
    for i in range(1,np.max(labels)+1):
        tmp_im= labels.copy()
        tmp_im[:] = 0
        tmp_im[labels==i] = 255
        file="imlabel_%d.png"%(i, )
        cv2.imwrite(file,tmp_im)
        tmp_im = tmp_im.astype(np.uint8)
        cnts = cv2.findContours(tmp_im, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

        # bounding box of the countour
        x,y,w,h = cv2.boundingRect(cnts[0])
        width[i-1] = w
        tmp_im=cv2.rectangle(tmp_im,(x,y),(x+w,y+h),(255,0,0),2)
        # center = center of the bounding box
        center=(x+w/2,y+h/2)
        cv2.circle(tmp_im, center, 3, (255,0,0), 2, 8, 0)

        cv2.imshow(file, tmp_im)
        cv2.waitKey(1000)
    return width

width_array=process_component(labels_im)
imshow_components(labels_im)
cv2.imwrite('labels_img.png',labels_im)

for i in range(1,np.max(labels_im)+1):
    w=width_array[i-1]
    #marker = find_marker(image)
    dist_cm = distance_to_camera(KNOWN_WIDTH, focalLength, w)
    print("distance en cm = %d",dist_cm)

这是我第一次在堆栈溢出上发帖,所以如果我应该发布其他任何内容来帮助我,请告诉我。

这是我一直在尝试使用的图像: https://i.stack.imgur.com/ONhUA.png

【问题讨论】:

  • 我没有弄乱 OpenCV,所以我不能帮你。但是,您应该删除任何不相关的行以使其更具可读性,最后尝试将您的代码分解到问题所在。尝试将其重新组织为 how to draw an image in OpenCV 或类似的内容以适合您的问题。祝你好运,我相信你会克服这个障碍。欢迎使用 StackOverflow,它是一个很好的资源。
  • 快速注意底部的print 声明应该是print("distance en cm = %d" % dist_cm)。使用%(取模)将dist_cm 放在字符串中%d 字符处。
  • 感谢@Crispy,编辑了代码,这样绒毛就不再存在了
  • Python 2.7 和 3.7 之间的 OpenCV 版本是否相同? cv2.findContours 的输出取决于它是版本 3 还是版本 4,将有两个输出或三个输出。我高度怀疑您在两个 Python 环境之间没有匹配的 OpenCV 版本。对于每个环境,请import cv2; print(cv2.__version__) 告诉我们它为 Python 2.7 和 3.7 打印的内容。
  • @rayryeng 好提示。您可能必须重构代码以使用 Python3.7 的库版本,某些特性/功能可能会被贬值。我建议先从最小的部分重建您的程序,然后以这种方式获得帮助。在你这样做之前尝试放置打印语句以找出程序出错的地方。我没有太多时间,但我会采用您的代码并尝试使其正常工作。现在,请尽量在新文件中逐步重新创建脚本。让它一块一块地工作。

标签: python opencv


【解决方案1】:

这是避免在 Python/OpenCV 中 findContours() 的返回值中正确访问轮廓项问题的一种方法。

findContours 有两种可能的返回值数量,具体取决于您使用的 OpenCV 版本。所以要访问在返回值列表中可以找到轮廓的位置:

替换

contours,hierarchy = cv2.findContours(tmp_im, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

和
contours,hierarchy = cv2.findContours(tmp_im, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

第二行表示如果返回值列表中元素个数为2,则使用返回值列表中的第一个返回值contours[0],否则使用第二个返回值contours[1]得到到等高线

【讨论】:

    【解决方案2】:

    当您调用cv2.boundingRect(cnts) 时,cnts 的值是错误的。我四处阅读,这是因为您使用的版本已过时。现在似乎从cv2.findContours(...) 返回了更多信息,因此您只需提取它即可。

    def process_component():变化

    contours,hierarchy = cv2.findContours(tmp_im, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cnts = contours[0]
    

    其次,当您使用cv2.circle(...) 绘制圆圈时,您正在传递一个浮点元组。 cv2.circle(...) 显然不能使用浮点数,因此首先将元组中的每个值转换为 int。您可能希望在转换为 int 之前对这些浮点数进行四舍五入。

    def process_component():变化

    center = ( int(x+w/2), int(y+h/2) )
    # Or use the rounded version below.
    # center = ( int(round(x+w/2)), int(round(y+h/2)) )
    cv2.circle(tmp_im, center, 3, (255,0,0), 2, 8, 0)
    

    这是包含这些实现的脚本。

    import os
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    
    def distance_to_camera(knownWidth, focalLength, perWidth):
        """ 
        Find distance between camera and object with OpenCV.
        Return the distance from the maker (object?) to the camera.
        """ 
        return (knownWidth * focalLength) / perWidth
    
    
    
    def imshow_components(labels):
        """ Display labels: For debugging purposes"""
        # Map component labels to hue val
        label_hue = np.uint8(179*labels/np.max(labels))
        blank_ch = 255*np.ones_like(label_hue)
        labeled_img = cv2.merge([label_hue, blank_ch, blank_ch])
    
        # cvt to BGR for display
        labeled_img = cv2.cvtColor(labeled_img, cv2.COLOR_HSV2BGR)
    
        # set bg label to black
        labeled_img[label_hue==0] = 0
        #labeled_img[labels==0] = 0
    
        cv2.imshow('labeled.png', labeled_img)
        cv2.waitKey(1000)
        cv2.imwrite('labeled_img.png',labeled_img)
        #cv2.imwrite('label_hue.png',label_hue)
    
    
    
    def process_component(labels):
        """ 
        Describe what happens here.
        width of ____ is ___.
        Find contours of ___ for ___.
        etc. Write what happens in this __docstr__
        return the ______.
        """
        
        width = np.zeros(np.max(labels)) 
        
        for i in range(1,np.max(labels)+1):
            
            tmp_im= labels.copy()
            tmp_im[:] = 0
            tmp_im[labels==i] = 255
            
            file="imlabel_%d.png"%(i, )
            cv2.imwrite(file,tmp_im)
            tmp_im = tmp_im.astype(np.uint8)
    
            ##########################
            # Here was the first issue. https://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html
            contours,hierarchy = cv2.findContours(tmp_im, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
            cnts = contours[0]
    
            x,y,w,h = cv2.boundingRect(cnts)
            ##########################
    
            width[i-1] = w
            tmp_im=cv2.rectangle(tmp_im,(x,y),(x+w,y+h),(255,0,0),2)
            
    
            ##########################
            # HERE IS THE NEXT ISSUE. 
            # Fixed it. The center tuple (x, y) cannot be of type floats apparently. Convert each value to an int after division.
            # center = center of the bounding box
            center=(int(x+w/2),int(y+h/2))
    
            cv2.circle(tmp_im, center, 3, (255,0,0), 2, 8, 0)
            ##########################
    
            cv2.imshow(file, tmp_im)
            cv2.waitKey(1000)
            
            
        return width
    
    
    
    
    def main():
        """ Call this function to run the program. Put some detail in here. """
        
        # Get the path to the filename. (Im on windows right now)
        filename =  "many_blob.png"
        path = os.path.join(os.getcwd(), filename)
        
        
        # What are these?
        KNOWN_WIDTH = 8
        focalLength = 545
        
        # Read the path as an cv2 image and show it. Wait 1 sec.  
        img = cv2.imread(path)
        cv2.imshow("img", img)
        cv2.waitKey(1000)
        
        # Do something else here. I dont know what, sorry idk about cv2
        image = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)[1]  # ensure binary 127
        cv2.imshow("image", image)
        cv2.waitKey(1000)
        
        # Do something with parameters that will affect the image.
        kernel = np.ones((5,5),np.uint8)
        erosion = cv2.erode(image,kernel,iterations = 5)
        dilate=cv2.dilate(erosion,kernel,iterations = 5)
        edged = cv2.Canny(dilate, 0, 128)
        
        # Show the affected image.
        cv2.imshow("edged", edged)
        cv2.waitKey(1000)
        
        # idk.
        connectivity=8
        num_labels,labels_im = cv2.connectedComponents(edged,connectivity)
        
        # Do something here.
        width_array=process_component(labels_im)
        imshow_components(labels_im)
        cv2.imwrite('labels_img.png',labels_im)
        
        
        
        # do some more things here.
        for i in range(1,np.max(labels_im)+1):
            w=width_array[i-1]
            #marker = find_marker(image)
            dist_cm = distance_to_camera(KNOWN_WIDTH, focalLength, w)
            print("distance en cm = %d",dist_cm)
    
    
    
    
            
            
            
        
            
    if __name__ == '__main__':
        """ If this file is executed, run the main function. """
        
        main()
        
        
        
        
    

    【讨论】:

    • 非常感谢,这完美地解决了我的问题。现在我知道如果再次发生这种情况应该寻找什么:)
    • 没问题。您将从调试代码中学到很多东西。只需在您的代码中添加print 语句以找出一切开始出错、丢失或不正确的数据的位置,然后谷歌最简单的错误代码,您通常会找到一个可以解决您的问题的 stackoverflow 线程,或者检查库文档。
    猜你喜欢
    • 2016-02-24
    • 2015-05-05
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 2019-12-21
    • 2020-08-09
    相关资源
    最近更新 更多