【问题标题】:ValueError: sequence too large; cannot be greater than 32ValueError:序列太大;不能大于 32
【发布时间】:2019-01-23 11:49:54
【问题描述】:

我写了这段代码:

from Crypto.Cipher import AES
import numpy as np
import cv2, base64

BLOCK_SIZE = 16
PADDING = '{'

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)

secret = "youwanttoknowmysecretdontyouhaha"
cipher = AES.new(secret)

video = cv2.VideoCapture(0)
a = 0

while True:
    a = a + 1

    check, frame = video.read()

    encrypted = EncodeAES(cipher, str(frame))

    img = DecodeAES(cipher, encrypted)

    cv2.imshow("Capturing", np.ndarray(img))
    key = cv2.waitKey(1)

    if key == ord('q'):
        break

但它并没有像预期的那样工作。

我想让它播放我的实时摄像头,但它给了我以下错误:

Traceback(最近一次调用最后一次):文件“tester.py”,第 28 行,在 cv2.imshow("Capturing", np.ndarray(img)) ValueError: sequence too large;不能大于 32

我真的很想知道我做错了什么,不要只给我解决方案,而是请解释一下,我还在学习

编辑

我使用 python 2.7

编辑

以下代码有效,但我在主机将加密发送到另一台计算机的程序中使用它。在这种情况下你不能使用frame.dtype

from Crypto.Cipher import AES
import numpy as np
import cv2, base64

BLOCK_SIZE = 16
PADDING = '{'

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)

secret = "youwanttoknowmysecretdontyouhaha"
cipher = AES.new(secret)

video = cv2.VideoCapture(0)
a = 0

while True:
    a = a + 1

    check, frame = video.read()

    encrypted = EncodeAES(cipher, frame.tobytes())

    decrypted = DecodeAES(cipher, encrypted)

    img = np.frombuffer(decrypted, dtype=frame.dtype).reshape(frame.shape)

    cv2.imshow("Capturing", img)
    key = cv2.waitKey(1)

    if key == ord("q"):
        break

video.release()

但是我可以将 frame.dtype 发送到另一台计算机。

当我将frame.dtypeframe_shape的加密形式发送到计算机并解密并在那里使用时,我收到以下错误

img = np.frombuffer(decod_ed, dtype=img_dtype).reshape(img_shape)
TypeError: data type "ûÿùùÖÿùÖÿùÖÿÖÖÿÖÖÿÜÜÖøøÜ£ÜÖ£ÜÖÜÜÖÜÜÖÿÜÜÿÜÜÿÜøÖø£øøøøøøØ£ÿØ£ÿØ£ÿƒ×ÜØ×Ü׃øØƒÖøØùØØùØØùƒ£ÿ×øùƒ£ÿƒ£ÿƒøÜƒøÜíØ£íØ£íØ£óרóרóרóƒøóƒøúá£óƒøáƒøáƒø×ƒø×ƒø£ƒø£ƒø£ƒø£ƒøƒ×ÜáƒøúíøúíøÑáøÑáøñ×øÑƒ£ñØ×Ñ׃ñáƒñáƒóíØíá£áó£ƒíø×áÜ×áÜøƒÖ£áÜ£ƒø£ƒøƒØ£ƒØ£áרá×ØØØ£ØØ£×רƒƒ×ƒƒ×××Ø×ƒø×ƒø£ƒø£ƒø£×Ø£×Ø£×Ø£×ØØá£Øá£ØíøØíøáó£áó£×ó£ØíøÜƒøù£ÿôÜÿôÜÿÿÜÜÿÜÜøøøØØØíƒ×óáƒíƒ×íƒ×óáƒóáƒñúƒñúƒªÑíñúƒñúƒñúƒúó×úó×úó×úó×óó£óó£úñøúñøúúØññ×óñ×óñ×óúƒóúƒóóíóóíóúƒñÑíóªááñ××ñ××ñ××úƒáÑí׺á׺á£ñƒ£ñƒáúƒáúƒññúóóíúíáúíáííáññúññúññúñÑíñÑíóúƒñÑíñÑíñÑíóÑíóÑíóúƒóúƒñÑíñÑíñÑíóúƒáúƒóÑíóÑíáúƒƒó×áúƒóÑíóÑíóÑíáúƒáúƒƒó׃ó××íØØíøØíøØóÖØóÖØíø£áÜáá܃ƒÖíƒÖƒØùØ×òƒáùØáùÜØöÜØöÜØöÖ×òÿØöù£ôù£ôûÜöûÜööÜööÜöÆøöÆøööÜööÜöûÜööÿÆûùôûùôÿûòûöôÆöôöûòöûòöûòöûòÆöôÉòæÉòæÉûÉÉûÉÅòÅÅòÅæòÅÉöÄÉöÄÉöÄÉöÄÅôìÉÆîÅæïææïÉÉèÉÅåÉÅåîÅåèìäçîâåïéêîüêîüçï~çï~àïÇàïÇë|å|" not understood

【问题讨论】:

  • 很可能图像的形状类似于 (480, 640, 3) 而解密图像的形状是 (921600)...您需要将数组重新整形为正确的形状
  • 不要使用ndarray。使用np.array(img)ndarray的第一个参数是形状,不能超过32个元素。在这种情况下查看文档。
  • @hpaulj 如果我用np.array(img) 替换np.ndarray(img) 我得到这个错误:TypeError: mat data type = 18 is not supported
  • 好的,img is a special kind of object, buffer or bytestring, that requires a kind of decoding that np.array` 无法处理。无论如何,它肯定不符合ndarrayshape 参数。
  • 如果它在另一台计算机上,也有重复的代码。但这并不重要。无论如何,dtype 和形状也需要序列化/反序列化。对于他们来说,你可以简单地使用 str。

标签: python numpy opencv


【解决方案1】:

我假设 frame[SciPy.Docs]: numpy.ndarray。有2个问题。下面是一个例子:

code00.py

#!/usr/bin/env python3

import sys
from Crypto.Cipher import AES
import numpy as np
import cv2
import base64


BLOCK_SIZE = 16
PADDING = b"{"

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING

EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)

CIPHER_MODE = AES.MODE_CBC
SECRET = b"youwanttoknowmysecretdontyouhaha"


def main():

    img0 = cv2.imread("c:/valmand.png")
    encrypt_cipher = AES.new(SECRET, CIPHER_MODE)  # Python 2: AES.new(SECRET)
    print("Original image data - Type: {:}, Size: {:d}, Attrs: {:}".format(type(img0), img0.size, img0.shape))
    img_stream_wrong = str(img0).encode()
    print("\nWrong img0 stream length: {:}".format(len(img_stream_wrong)))
    print("\nWrong img0 stream: {:}".format(img_stream_wrong))
    img_stream = img0.tobytes()
    print("\nCorrect img0 stream length: {:}".format(len(img_stream)))
    encrypted = EncodeAES(encrypt_cipher, img_stream)
    print("\nEncrypted length: {:d}".format(len(encrypted)))
    decrypt_cipher = AES.new(SECRET, CIPHER_MODE)  # Python 2: AES.new(SECRET)
    decrypted = DecodeAES(decrypt_cipher, encrypted)
    print("\nDecrypted length: {:d}".format(len(decrypted)))
    img1 = np.frombuffer(decrypted, dtype=img0.dtype).reshape(img0.shape)
    print("\nFinal image data - Type: {:}, Size: {:d}, Attrs: {:}".format(type(img1), img1.size, img1.shape))
    #cv2.imshow("Capturing", img1)


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

注意事项

  • 我将示例简化为仅加载图像
  • 由于我没有在 Python 2 上安装所有必需的软件包,因此我使用了 Python 3。这就是为什么需要一些与问题无关的更改:
    • 字符串切换到字节
    • AES 变化:
      • AES.new 签名已更改 ([ReadTheDocs.PyCryptodome]: AES)
      • 相同的密码在用于加密后不能用于解密,所以创建另一个具有相同属性的密码(也许有一些更简洁的方法,但我没有花太多时间)李>
  • 错误

    • 如所见,在 ndarray 上应用 str 会为该 ndarray 提供用户友好的表示,而不是其内容,因此它将语法正确,但语义错误
      • 要解决此问题,应使用其 tobytes 方法正确序列化数组
    • 相反,当尝试反序列化时,ndarray 构造函数在字节流上被调用,(它被静默转换为 tuple ints - 构造函数期望的 - 与流具有相同的长度)

      • 这里的问题是构造函数不接受大于32的序列:

        >>> np.ndarray([0] * 32)
        array([], shape=(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
              dtype=float64)
        >>> np.ndarray([0] * 33)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: sequence too large; cannot be greater than 32
        
      • 要修复它,应该使用[SciPy.Docs]: numpy.frombuffer。为了使新的 ndarray 与原来的一样,还需要 2 个东西(需要来自原来的数据):

        • 应该指定它的dtype(默认是float,我们需要uint8
        • 需要重塑

输出

e:\Work\Dev\StackOverflow\q054326620>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code00.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Original image data - Type: <class 'numpy.ndarray'>, Size: 1493331, Attrs: (799, 623, 3)

Wrong img0 stream length: 629

Wrong img0 stream: b'[[[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n ...\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]\n\n [[255 255 255]\n  [255 255 255]\n  [255 255 255]\n  ...\n  [255 255 255]\n  [255 255 255]\n  [255 255 255]]]'

Correct img0 stream length: 1493331

Encrypted length: 1991128

Decrypted length: 1493331

Final image data - Type: <class 'numpy.ndarray'>, Size: 1493331, Attrs: (799, 623, 3)

@EDIT0

显然,存在一些兼容性问题。我使用 Python 3pycrpytodome 3.7.2 开发了答案。我升级到最新版本 (3.7.3),我还在 Python 2 上安装了它,上面的代码可以正常工作。这是我在控制台中得到的:

>>> from Crypto.Cipher import AES
>>> AES
<module 'Crypto.Cipher.AES' from 'e:\Work\Dev\VEnvs\py_064_02.07.15_test0\lib\site-packages\Crypto\Cipher\AES.pyc'>
>>> AES.new("")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: new() takes at least 2 arguments (1 given)
>>> import Crypto
>>> Crypto.__version__
'3.7.3'

所以,您可能有一个非常旧的 pycryptodome 版本。无论如何,我盲目地发布您的代码所需的更改,以合并修复(while 循环):

# The rest of your code (exactly as in the question)

while True:
    a = a + 1

    check, frame = video.read()

    original_meta = frame.dtype.name, frame.shape

    encrypted_meta = EncodeAES(cipher, bytes(original_meta))
    encrypted_data = EncodeAES(cipher, frame.tobytes())

    # Here is the separation

    decrypted_meta = DecodeAES(cipher, encrypted_meta)
    decrypted_data = DecodeAES(cipher, encrypted_data)

    meta = ast.literal_eval(decrypted_meta)

    img = np.frombuffer(decrypted_data, dtype=np.dtype(meta[0])).reshape(meta[1])

    cv2.imshow("Capturing", img)
    key = cv2.waitKey(1)

    if key == ord("q"):
        break

【讨论】:

  • 变量前为什么要加b?
  • 很抱歉没有告诉你,但我使用的是 python 2,所以 print("") 应该是 print "",除了 usr/bin 之外还有什么需要更改的吗?
  • 最后一件事。如果我使用您的代码,我会收到此错误:encrypt_cipher = AES.new(SECRET, CIPHER_MODE) File "D:\Python27\lib\site-packages\Crypto\Cipher\AES.py", line 95, in new return AESCipher(key, *args, **kwargs) File "D:\Python27\lib\site-packages\Crypto\Cipher\AES.py", line 59, in __init__ blockalgo.BlockAlgo.__init__(self, _AES, key, *args, **kwargs) File "D:\Python27\lib\site-packages\Crypto\Cipher\blockalgo.py", line 141, in __init__ self._cipher = factory.new(key, *args, **kwargs) ValueError: IV must be 16 bytes long
  • 正如我所解释的,许多更改都与 Python 3 相关(我意识到您使用的是 2,因此是注释的第一部分)。 b 用于字节print("") 也适用于 Python 2。对于 AES 您需要删除第二个参数(就像在您的原始代码中一样)。我将在代码中添加一些 cmets。
  • 所以作为结论,将第一行更改为#!/usr/bin/env python,然后是 2 个 AES 初始化(我放置 cmets 的位置),打印可以保持原样(或者您可以完全删除它们),并且在 Python2 中,字符串前面的 b 无效。
猜你喜欢
  • 2022-07-06
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-21
  • 2020-02-10
  • 2015-12-05
  • 1970-01-01
相关资源
最近更新 更多