将双端队列保存到 csv 数据框中

Save deque into csv data frame

我正在使用 opencv 处理跟踪元素视频(基本上是计算 hsv 阈值处理后的元素数量)。我有一个 deque 缓冲区来存储质心位置。我选择了 64 的有限缓冲区(30 fps 时约 2 秒,可能更长)。我的目标是将数据以我以后可以随时使用的格式保存到 .csv 文件中(见下文)。此外,我正在计算检测到的区域的数量。格式类似于

cX  cY  number
444 265   19
444 265   19
444 264   19
444 264   19
...

其中cX为最大元素在X方向的质心,cY为Y方向的质心,以及检测到的区域数。列命名不是主要目标,但它会很好。

出于显示目的,我需要将质心设置为 tuple。我使用 appendleft:

让它们逐帧增长
center_points = deque(maxlen=64)
object_number = deque(maxlen=64)
iteration_counter = 1

    while True


        # read video frames..
        # do stuff...
        # get contours
            my_cnts = cv2.findContours(...)
        # get largest object
            c = max(my_cnts, key=cv2.contourArea)
            ((x, y), radius) = cv2.minEnclosingCircle(c)
            M = cv2.moments(c)
            big_center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
# count object number as int name it 'num'

center_points.appendleft(big_center)
object_number.appendleft(num)

现在,当缓冲区已满时,我想将数据保存到文件中):

# Convert to array to save
    # Wait until the iteration number is divisible by the buffer length
    if(iteration_number % 64 == 0):
        print("Saving on iteration..." + str(iteration_number))
        array_to_save = np.array([center_points, object_number]).T


        with open(filename,'a') as outfile:
            np.savetxt(outfile, array_to_save,
                       delimiter=',', fmt='%s')
# Add 1 to the counter
    iteration_number = iteration_number + 1

问题

上面的代码可以运行并编写如下内容:

(444 265) 19
(444 265) 19
(444 264) 19
(444 263) 19

我想做类似 np.array(center_points) 的事情并将其绑定到 object_number。我在尺寸方面遇到了麻烦(例如,(64,2) 和 (64) 不兼容)。我试过 np.appendnp.stack 但找不到正确的数据格式设置方式。

否则,我可以按原样保留代码,但我想以某种方式去掉第 1 列和第 2 列上的括号并保存该对象(已在 array_to_save 上尝试过正则表达式但没有成功)。所有三列都应为数字或保存为字符串,但在稍后阅读时很容易检索为数字。

更新

根据我试过的评论

array_to_save = np.concatenate([np.array(center_points), object_number[:, None]])
    TypeError: sequence index must be integer, not 'tuple'

我也试过了

array_to_save = np.concatenate([np.array(center_points), np.array(object_number)[:, None]])
    ValueError: all the input array dimensions except for the concatenation axis must match exactly

我认为,您遇到的部分困难是 np.savetxt() 不适用于 numpy 数组中的元组。我已经开发了一些测试代码,我认为它们复制了您问题的关键方面并为它们提供了解决方案:

import numpy as np
from collections import deque

# Create test data
center_points = deque(maxlen=64)
number = deque(maxlen=64)
for i in range(10):
    big_center = (i*3,i*100)
    center_points.appendleft(big_center)
    number.appendleft(19)

# Write the test data

array_to_save = np.array([center_points,number]).T
print (array_to_save)
with open("test.txt","w") as outfile:
    outfile.write("\n".join([" ".join([str(a[0]),str(a[1]),str(b)]) for a,b in
        array_to_save]))

# Re-read the test data
center_points2 = deque(maxlen=64)
number2 = deque(maxlen=64)

with open("test.txt","r") as infile:
    for line in infile:
        x = [int(xx) for xx in line.split()]
        center_points2.append((x[0],x[1]))
        number2.append(x[2])
    new_array = np.array([center_points2,number2]).T

print (new_array)

当运行时,这段代码输出如下,表明原来的array_to_save与读回的new_array相同:

[[(27, 900) 19]
 [(24, 800) 19]
 [(21, 700) 19]
 [(18, 600) 19]
 [(15, 500) 19]
 [(12, 400) 19]
 [(9, 300) 19]
 [(6, 200) 19]
 [(3, 100) 19]
 [(0, 0) 19]]
[[(27, 900) 19]
 [(24, 800) 19]
 [(21, 700) 19]
 [(18, 600) 19]
 [(15, 500) 19]
 [(12, 400) 19]
 [(9, 300) 19]
 [(6, 200) 19]
 [(3, 100) 19]
 [(0, 0) 19]]

文件test.txt如下:

27 900 19
24 800 19
21 700 19
18 600 19
15 500 19
12 400 19
9 300 19
6 200 19
3 100 19
0 0 19

这个版本的文件读写代码比调用np.savetxt()稍微复杂一点,但是它显式地处理了元组。

更新

或者,如果您希望在 numpy 数组中进行所有操作,您可以使用:

import numpy as np
from collections import deque

# Create test data
center_points = deque(maxlen=64)
number = deque(maxlen=64)
for i in range(10):
    big_center = (i*3,i*100)
    center_points.appendleft(big_center)
    number.appendleft(19)

print (center_points)
print (number)

# Write the test data

x, y = zip(*center_points)
array_to_save = np.array([x,y,number]).T
print (array_to_save)
np.savetxt("test.txt", array_to_save, fmt="%d")

# Re-read the test data
new_array = np.loadtxt("test.txt", dtype=int)
print (new_array)

center_points2 = deque(zip(new_array.T[0],new_array.T[1]),maxlen=64)
number2 = deque(new_array.T[2],maxlen=64)
print (center_points2)
print (number2)

这使用 Transpose/Unzip Function (inverse of zip)? 中描述的方法将每个元组的两个元素分成两个列表,然后包含在 number 列表中的单个 numpy 数组可以使用 savetxt() 保存并使用 loadtxt() 重新加载。

print() 调用只是为了说明程序结束时使用的数据与它开始时使用的数据完全相同。它们产生以下输出:

deque([(27, 900), (24, 800), (21, 700), (18, 600), (15, 500), (12, 400), (9, 300), (6, 200), (3, 100), (0, 0)], maxlen=64)
deque([19, 19, 19, 19, 19, 19, 19, 19, 19, 19], maxlen=64)
[[ 27 900  19]
 [ 24 800  19]
 [ 21 700  19]
 [ 18 600  19]
 [ 15 500  19]
 [ 12 400  19]
 [  9 300  19]
 [  6 200  19]
 [  3 100  19]
 [  0   0  19]]
[[ 27 900  19]
 [ 24 800  19]
 [ 21 700  19]
 [ 18 600  19]
 [ 15 500  19]
 [ 12 400  19]
 [  9 300  19]
 [  6 200  19]
 [  3 100  19]
 [  0   0  19]]
deque([(27, 900), (24, 800), (21, 700), (18, 600), (15, 500), (12, 400), (9, 300), (6, 200), (3, 100), (0, 0)], maxlen=64)
deque([19, 19, 19, 19, 19, 19, 19, 19, 19, 19], maxlen=64)

您可以 concatenate 沿列维度的数组,以便从 (X, 2)(X,) 数组创建 (X, 3) 数组。为了准备好进行串联,所有数组都需要具有相同的维数,因此您需要向平面数组添加一个额外的维度 object_number(X,) -> (X, 1)。这可以通过 object_number[:, np.newaxis]object_number[:, None] 完成。那么完整的解决方案是:

np.concatenate([np.array(center_points),
                np.array(object_number)[:, None]], axis=-1)