【问题标题】:camera image incorrectly formatted in ctypes pointer (python)相机图像在 ctypes 指针(python)中格式不正确
【发布时间】:2018-02-06 19:08:46
【问题描述】:

我正在使用 DLL 库来调用函数以在 python 中操作相机,并且我能够使用 ctypes 检索图像,但它的格式不正确。返回的图像是重复的,其中一半是空白的。我需要做什么来解决这个问题?

我有一个 labview 程序,可以正确地从相机中获取图像,所以它们应该是这样的。

使用 Labview 检索到的正确图像

使用 Python 检索的图像:

图像在 python 中是重复的,也是横向的。

python 代码:

from ctypes import *
import numpy as np
import matplotlib.pyplot as plt
mydll = windll.LoadLibrary('StTrgApi.dll')
hCamera = mydll.StTrg_Open()
print(hCamera)

im_height = 1200
im_width = 1600

dwBufferSize = im_height * im_width

pbyteraw = np.zeros((im_height, im_width), dtype=np.uint16)

dwNumberOfByteTrans = 0
dwNumberOfByteTrans = (c_ubyte * dwNumberOfByteTrans)()

dwFrameNo = 0
dwFrameNo = (c_ubyte * dwFrameNo)()

dwMilliseconds = 3000
mydll.StTrg_TakeRawSnapShot(hCamera, 
pbyteraw.ctypes.data_as(POINTER(c_int16)), dwBufferSize*2, 
dwNumberOfByteTrans, dwFrameNo, dwMilliseconds)

print(pbyteraw)
plt.matshow(pbyteraw)
plt.show()

用于获取图像的 C++ 代码:

DWORD dwBufferSize = 0;
    if(!StTrg_GetRawDataSize(hCamera, &dwBufferSize))
    {
        _tprintf(TEXT("Get Raw Data Size Failed.\n"));
        return(-1);
    }

    PBYTE pbyteRaw = new BYTE[dwBufferSize];
    if(NULL != pbyteRaw)
    {
        DWORD dwNumberOfByteTrans = 0;
        DWORD dwFrameNo = 0;
        DWORD dwMilliseconds = 3000;
        for(DWORD dwPos = 0; dwPos < 10; dwPos++)
        {

            if(StTrg_TakeRawSnapShot(hCamera, pbyteRaw, dwBufferSize, 
&dwNumberOfByteTrans, &dwFrameNo, dwMilliseconds))
        {
            TCHAR szFileName[MAX_PATH];
            if(is2BytesMode)
            {
                _stprintf_s(szFileName, _countof(szFileName), TEXT("%s\\%u.tif"), szBitmapFilePath, dwFrameNo);
                StTrg_SaveImage(dwWidth, dwHeight, STCAM_PIXEL_FORMAT_16_MONO_OR_RAW, pbyteRaw, szFileName, 0);
            }
            else
            {
                _stprintf_s(szFileName, _countof(szFileName), TEXT("%s\\%u.bmp"), szBitmapFilePath, dwFrameNo);
                StTrg_SaveImage(dwWidth, dwHeight, STCAM_PIXEL_FORMAT_08_MONO_OR_RAW, pbyteRaw, szFileName, 0);
            }
            _tprintf(TEXT("Save Image:%s\n"), szFileName);
        }
        else
        {
            _tprintf(TEXT("Fail:StTrg_TakeRawSnapShot\n"));
            break;
        }
    }
    delete[] pbyteRaw;
}

【问题讨论】:

  • 根据你的other question 表明原始缓冲区是一个字节指针,你为什么使用 uint16 作为数据类型?另请参阅我在您关于正确传递输出参数的其他问题中的回答。您可以检查dwNumberOfByteTrans 的输出以查看您发送的缓冲区大小和接收的数量是否有意义。这将有助于在 DLL 中显示 C 函数的确切原型,甚至显示正确调用该函数的工作 C 代码。
  • 我不知道为什么,我不确定要使用什么。当我使用 uint8 时,python 在调用拍摄快照功能时崩溃。当我使用 uint32 时,它会起作用,但显示的图像更小(分辨率更低,空白空间更多)。我也尝试过 ubyte 作为数据类型,但出现内存错误:OSError: exception: access violation reading 0x074B5000
  • 我不知道为什么,我不确定要使用什么。当我使用 uint8 时,python 在调用拍摄快照功能时崩溃。当我使用 uint32 时,它会起作用,但显示的图像更小(分辨率更低,空白空间更多)。我也尝试将 ubyte 作为数据类型,但出现内存错误: OSError: exception: access violation reading 0x074B5000 我添加了 cpp 代码,添加 .argtypes 似乎没有什么不同。谢谢你的帮助

标签: python pointers dll camera ctypes


【解决方案1】:

根据你的 C 代码,这样的东西应该可以工作,但它未经测试,因为我没有你的相机库。如果您使用的是 32 位 Python,请确保库调用为 __stdcall 以使用 WinDLL,否则使用 CDLL。 64位Python没关系。定义参数类型和返回类型有助于捕获错误。对于输出参数,创建正确 ctype 的实例,然后传递 byref()。您当前执行输出参数的方式可能是导致崩溃的原因。设置 argtypes 会检测到这些值不是指向 DWORD 的指针。

from ctypes import *
from ctypes import wintypes as w

mydll = WinDLL('StTrgApi')

mydll.StTrg_Open.argtypes = None
mydll.StTrg_Open.restype = w.HANDLE

mydll.StTrg_GetRawDataSize.argtypes = w.HANDLE,w.PDWORD
mydll.StTrg_GetRawDataSize.restype = None

mydll.StTrg_TakeRawSnapShot.argtypes = w.HANDLE,w.PBYTE,w.DWORD,w.PDWORD,w.PDWORD,w.DWORD
mydll.StTrg_TakeRawSnapShot.restype = None

hCamera = mydll.StTrg_Open()
print(hCamera)

dwBufferSize = w.DWORD()
mydll.StTrg_GetRawDataSize(hCamera,byref(dwBufferSize))

pbyteraw = (w.BYTE * dwbufferSize)()
dwNumberOfByteTrans = w.DWORD() # output parameters.  Pass byref()
dwFrameNo = w.DWORD()           # output parameters.  Pass byref()
dwMilliseconds = 3000

mydll.StTrg_TakeRawSnapShot(hCamera,
                            pbyteraw,
                            dwbufferSize,
                            byref(dwNumberOfByteTrans),
                            byref(dwFrameNo),
                            dwMilliseconds)

【讨论】:

  • 我解决了这个问题,我必须使用 uint8 数据类型的 numpy 数组,并将其作为 pbyteraw 参数作为指针传递,它可以工作。使用 uint16 将显示两个图像(就像我发布的原始图像一样),而 uint32 将显示四个重复的图像,而图像的其余部分为空白。我真的不明白如何更改数据类型会导致重复的图像。谢谢你的帮助
  • @zonzon510 它没有复制图像。对于 16 位数据,您分配的缓冲区是原来的两倍,而一行的字节数是原来的两倍,因此一个“行”包含两行实际数据。这也是为什么您的图像的后半部分是空白的......只有前半部分填充了字节数据。
猜你喜欢
  • 2019-04-19
  • 2018-12-31
  • 2011-05-11
  • 1970-01-01
  • 2014-01-23
  • 2017-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多