Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有没有更快的方法来求形状的周长?_Python_Numpy_Opencv_Image Processing_Scipy - Fatal编程技术网

Python 有没有更快的方法来求形状的周长?

Python 有没有更快的方法来求形状的周长?,python,numpy,opencv,image-processing,scipy,Python,Numpy,Opencv,Image Processing,Scipy,我有一张图片显示了一些物体,其中一个物体总是在另一个物体里面。 背景总是黑色的 我想知道两个物体的周长,然后找到一个解决方案。 我使用filterkernel获得每个像素的4邻域。然后我计算像素周围的零像素数。这给出了形状的长度(以像素为单位)。我只计算在这种情况下,如果中心像素是所需的颜色 from scipy import misc, ndimage import numpy as np import time def get_circumference(arr, only=50, re

我有一张图片显示了一些物体,其中一个物体总是在另一个物体里面。 背景总是黑色的

我想知道两个物体的周长,然后找到一个解决方案。 我使用filterkernel获得每个像素的4邻域。然后我计算像素周围的零像素数。这给出了形状的长度(以像素为单位)。我只计算在这种情况下,如果中心像素是所需的颜色

from scipy import misc, ndimage
import numpy as np
import time

def get_circumference(arr, only=50, repl=50):
    def c_length(values):
        # 3rd value is the pixel
        if values[2] == only:
            return sum([x == 0 or (repl == 0 and x != only) for x in values[[0,1,3,4]]])
        return 0

    fp = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
    res = ndimage.generic_filter(arr, c_length, footprint=fp)

    return np.sum(res, axis=None)

x = ndimage.imread("image.png", mode='L')

tic = time.time()
inner = get_circumference(x, only=255, repl=0)
outer = get_circumference(x, only=128, repl=128)
print("Inner object: {}, outer object: {}, took: {}".format(inner, outer, time.time() - tic))
给我:

Inner object: 510, outer object: 1054, took: 0.8387038707733154
它很好用。但是它非常慢。 单个图像大约需要500到1000毫秒。 因为我需要对几千张图片执行此操作,这将花费太多时间

有没有办法加快速度?我知道,图像将始终包含三种颜色,内部部分将始终被外部部分完全包围。此外,形状永远不会跨越图像边界

当然,实际计算周长有不同的方法。 只要给出一个像素,就有两种可能的解决方案:1或4。 第一种方法仅计算像素数,即单个像素作为单个周长单位进行计数。在后一种情况下,对像素的实际边缘进行计数。 在我的解决方案中,我使用后一种方法来计算周长。 如果仅通过边缘检测和直方图进行计数,则将得到第一个解

这是另一个例子,其中这种差异实际上也可以手动计算:

它由8个灰色像素和一个白色像素组成。 因此,外周长为3+3+3+3=12,内周长为4。
通过直方图进行像素计数,外部为8,内部为1。

您可以通过使用形态学腐蚀来解决这一问题,这将改变相邻像素较低的像素的颜色。然后比较两幅图像是否相等,得到以下结果

这些操作应该在OpenCV中可用,并且运行速度比Python代码快得多

还要注意,计算给定颜色的像素数只是计算直方图


更新:

我们更容易做到:

  • 以柱状图为例
  • 侵蚀
  • 再看一次柱状图
计数之间的差异是轮廓像素的数量。一次就可以得到灰色和白色的计数

使用我的超级复制优化功能

Histogram: 0.250 ms
Erosion:   0.050 ms
Histogram: 0.250 ms
Total:     0.550 ms
更好的是:

取图像及其腐蚀的平均值,然后取直方图。轮廓像素以中间灰度值显示

Erosion:   0.060 ms
Average:   0.020 ms
Histogram: 0.230 ms
Total:     0.310 ms

现在的瓶颈是(从文件中)读取图像。

如果使用,则可以同时检测给定图像的两个对象的周长。如果图像是自然的,这会有点棘手,但对于其他方法,例如基于区域和形态学的方法,情况就是这样。

我使用
OpenCV
进行图像处理,而
这个问题对于
OpenCV
来说并不难

  • 读取图像并转换为灰色
  • 灰色的门槛
  • 在经过阈值处理的二值图像上查找轮廓
  • 计算每个轮廓的弧长(周长)和面积(如果需要)

  • 阈值为120:


    阈值为200:



    酷问题!您是否有针对给定图像的“正确答案”以供验证?图像在大小和格式方面是否具有代表性?你能提供一个或两个其他的样本图像吗?请同时提供正确的答案?@MarkSetchell我更新了计数方法,并添加了另一个例子(一个非常极端的例子)。请告诉我大图像的正确答案是什么?你的解看起来很好,显然速度更快,但周长的计算是不同的。但我知道有几种方法可以计算像素化物体的周长,人们无法真正计算图像中圆的精确周长值。就像那些椭圆一样。累积错误必须存在。在对轮廓进行do近似后,值可能会接近。
    Th: 120.0
    Length: 869.578
    Area: 53932.000
    Time: 0.002293109893798828s
    
    Th: 200.0
    Length: 423.990
    Area: 11892.000
    Time: 0.0015425682067871094s
    
    ## -------------------------------------
    #!/usr/bin/python3
    # 2018.01.16 10:23:47 CST
    # 2018.01.16 12:30:20 CST
    """
    Env: Python 3.5 + OpenCV 3.3
    """
    import numpy as np
    import cv2
    import time
    
    def findArc(img, th):
        res = img.copy()
        print("Th: {}".format(th))
    
        ts = time.time()
        ## convert to gray 
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
        ## threshold the gray 
        th, threshed = cv2.threshold(gray, th, 255,  cv2.THRESH_BINARY)
    
        ## Find contours on the binary threshed image 
        cnts = cv2.findContours(threshed, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
    
        ## calcualte 
        for cnt in cnts:
            arclen = cv2.arcLength(cnt, True)
            area = cv2.contourArea(cnt)
            cv2.drawContours(res, [cnt], -1, (0,255,0), 3, cv2.LINE_AA)
            print("Length: {:.3f}\nArea: {:.3f}".format(arclen, area))
    
        print("Time: {}s".format(time.time()-ts))
    
        cv2.imshow("res", res)
        cv2.waitKey();cv2.destroyAllWindows()
        cv2.imwrite("res_{}.png".format(th), res)
    
    
    img = cv2.imread("img03.png")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    findArc(img, 120)
    findArc(img, 200)