首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >向NI IMAQ的imgBayerColorDecode传递哪种类型的ctype指针?

向NI IMAQ的imgBayerColorDecode传递哪种类型的ctype指针?
EN

Stack Overflow用户
提问于 2013-06-13 19:23:36
回答 1查看 883关注 0票数 4

我正在使用ctype来访问来自国家仪器(NI)的图像采集API。在它中,有一个名为imgBayerColorDecode()的函数,我在imgSnap()函数返回的拜耳编码图像上使用它。我想将解码后的输出(即RGB图像)与我将根据原始数据创建的一些numpy ndarray进行比较,这就是imgSnap返回的内容。

然而,有两个问题。

第一种方法很简单:将imgSnap返回的imgbuffer传递给numpy数组。现在首先有一个问题:如果您的机器是64位的,并且有超过3GB的RAM,您就不能创建带有numpy的数组并将其作为指向imgSnap的指针传递。这就是为什么您必须实现一个解决方案,这在NI的论坛(尼参-前2个员额)中得到了描述:禁用错误消息(附在下面的代码:imaq.niimaquDisable32bitPhysMemLimitEnforcement中的第125行),并确保是IMAQ库创建了图像(imaq.imgCreateBuffer)所需的内存。在此之后,这个菜谱是这样的应该能够再次将缓冲区转换为numpy数组。但我不确定我是否对数据类型做了正确的更改:相机有1020x1368像素,每个像素的强度以10位的精度记录下来。它通过一个CameraLink返回图像,我假设它以每像素2个字节的方式实现,以便于数据传输。这是否意味着我必须修改另一个中给出的菜谱,这样的问题:

代码语言:javascript
复制
buffer = numpy.core.multiarray.int_asbuffer(ctypes.addressof(y.contents), 8*array_length)
a = numpy.frombuffer(buffer, float)

对此:

代码语言:javascript
复制
bufsize = 1020*1368*2
buffer = numpy.core.multiarray.int_asbuffer(ctypes.addressof(y.contents), bufsize)
a = numpy.frombuffer(buffer, numpy.int16)

第二个问题是,imgBayerColorDecode()没有给出我期望的输出。下面是两个图像,第一个是imgSnap的输出,用imgSessionSaveBufferEx()保存。第二个是imgSnap在经历了imgBayerColorDecode()的去噪之后的输出。

  • 原始数据: i42.tinypic.com/znpr38.jpg
  • 拜耳解码: i39.tinypic.com/n12nmq.jpg

正如你所看到的,拜耳解码的图像仍然是灰度的,而且它不像原始的图像(这里的小注释,这些图像被缩放以便用imagemagick上传)。最初的图像是用红色滤色镜在一些面具前拍摄的。从它(和另外两个颜色过滤器)中,我知道拜耳颜色过滤器在左上角的样子如下:

代码语言:javascript
复制
BGBG
GRGR

我认为我在将正确类型的指针传递给imgBayerDecode时做错了什么,我的代码附在下面。

代码语言:javascript
复制
#!/usr/bin/env python
from __future__ import division

import ctypes as C
import ctypes.util as Cutil
import time


# useful references:
# location of the niimaq.h: C:\Program Files (x86)\National Instruments\NI-IMAQ\Include
# location of the camera files: C:\Users\Public\Documents\National Instruments\NI-IMAQ\Data
# check it C:\Users\Public\Documents\National Instruments\NI-IMAQ\Examples\MSVC\Color\BayerDecode

class IMAQError(Exception):
    """A class for errors produced during the calling of National Intrument's IMAQ functions.
    It will also produce the textual error message that corresponds to a specific code."""

    def __init__(self, code):
        self.code = code
        text = C.c_char_p('')
        imaq.imgShowError(code, text)
        self.message = "{}: {}".format(self.code, text.value)
        # Call the base class constructor with the parameters it needs
        Exception.__init__(self, self.message)


def imaq_error_handler(code):
    """Print the textual error message that is associated with the error code."""

    if code < 0:
        raise IMAQError(code)
        free_associated_resources = 1
        imaq.imgSessionStopAcquisition(sid)
        imaq.imgClose(sid, free_associated_resources)
        imaq.imgClose(iid, free_associated_resources)
    else:
        return code

if __name__ == '__main__':
    imaqlib_path = Cutil.find_library('imaq')
    imaq = C.windll.LoadLibrary(imaqlib_path)


    imaq_function_list = [  # this is not an exhaustive list, merely the ones used in this program
        imaq.imgGetAttribute,
        imaq.imgInterfaceOpen,
    imaq.imgSessionOpen,
        imaq.niimaquDisable32bitPhysMemLimitEnforcement,  # because we're running on a 64-bit machine with over 3GB of RAM
        imaq.imgCreateBufList,
        imaq.imgCreateBuffer,
        imaq.imgSetBufferElement,
        imaq.imgSnap,
        imaq.imgSessionSaveBufferEx,
        imaq.imgSessionStopAcquisition,
        imaq.imgClose,
        imaq.imgCalculateBayerColorLUT,
        imaq.imgBayerColorDecode ]

    # for all imaq functions we're going to call, we should specify that if they
    # produce an error (a number), we want to see the error message (textually)
    for func in imaq_function_list:
        func.restype = imaq_error_handler




    INTERFACE_ID = C.c_uint32
    SESSION_ID = C.c_uint32
    BUFLIST_ID = C.c_uint32
    iid = INTERFACE_ID(0)
    sid = SESSION_ID(0)
    bid = BUFLIST_ID(0)
    array_16bit = 2**16 * C.c_uint32
    redLUT, greenLUT, blueLUT  = [ array_16bit() for _ in range(3) ]
    red_gain, blue_gain, green_gain = [ C.c_double(val) for val in (1., 1., 1.) ]

    # OPEN A COMMUNICATION CHANNEL WITH THE CAMERA
    # our camera has been given its proper name in Measurement & Automation Explorer (MAX)
    lcp_cam = 'JAI CV-M7+CL'
    imaq.imgInterfaceOpen(lcp_cam, C.byref(iid))
    imaq.imgSessionOpen(iid, C.byref(sid)); 

    # START C MACROS DEFINITIONS
    # define some C preprocessor macros (these are all defined in the niimaq.h file)
    _IMG_BASE = 0x3FF60000

    IMG_BUFF_ADDRESS = _IMG_BASE + 0x007E  # void *
    IMG_BUFF_COMMAND = _IMG_BASE + 0x007F  # uInt32
    IMG_BUFF_SIZE = _IMG_BASE + 0x0082  #uInt32
    IMG_CMD_STOP = 0x08  # single shot acquisition

    IMG_ATTR_ROI_WIDTH = _IMG_BASE + 0x01A6
    IMG_ATTR_ROI_HEIGHT = _IMG_BASE + 0x01A7
    IMG_ATTR_BYTESPERPIXEL = _IMG_BASE + 0x0067  
    IMG_ATTR_COLOR = _IMG_BASE + 0x0003  # true = supports color
    IMG_ATTR_PIXDEPTH = _IMG_BASE + 0x0002  # pix depth in bits
    IMG_ATTR_BITSPERPIXEL = _IMG_BASE + 0x0066 # aka the bit depth

    IMG_BAYER_PATTERN_GBGB_RGRG = 0
    IMG_BAYER_PATTERN_GRGR_BGBG = 1
    IMG_BAYER_PATTERN_BGBG_GRGR = 2
    IMG_BAYER_PATTERN_RGRG_GBGB = 3
    # END C MACROS DEFINITIONS

    width, height = C.c_uint32(), C.c_uint32()
    has_color, pixdepth, bitsperpixel, bytes_per_pixel = [ C.c_uint8() for _ in range(4) ]

    # poll the camera (or is it the camera file (icd)?) for these attributes and store them in the variables
    for var, macro in [ (width, IMG_ATTR_ROI_WIDTH), 
                        (height, IMG_ATTR_ROI_HEIGHT),
                        (bytes_per_pixel, IMG_ATTR_BYTESPERPIXEL),
                        (pixdepth, IMG_ATTR_PIXDEPTH),
                        (has_color, IMG_ATTR_COLOR),
                        (bitsperpixel, IMG_ATTR_BITSPERPIXEL) ]:
        imaq.imgGetAttribute(sid, macro, C.byref(var))  


    print("Image ROI size: {} x {}".format(width.value, height.value))
    print("Pixel depth: {}\nBits per pixel: {} -> {} bytes per pixel".format(
        pixdepth.value, 
        bitsperpixel.value, 
        bytes_per_pixel.value))

    bufsize = width.value*height.value*bytes_per_pixel.value
    imaq.niimaquDisable32bitPhysMemLimitEnforcement(sid)

    # create the buffer (in a list)
    imaq.imgCreateBufList(1, C.byref(bid))  # Creates a buffer list with one buffer

    # CONFIGURE THE PROPERTIES OF THE BUFFER
    imgbuffer = C.POINTER(C.c_uint16)()  # create a null pointer
    RGBbuffer = C.POINTER(C.c_uint32)()  # placeholder for the Bayer decoded imgbuffer (i.e. demosaiced imgbuffer)
    imaq.imgCreateBuffer(sid, 0, bufsize, C.byref(imgbuffer))  # allocate memory (the buffer) on the host machine (param2==0)
    imaq.imgCreateBuffer(sid, 0, width.value*height.value * 4, C.byref(RGBbuffer))

    imaq.imgSetBufferElement(bid, 0, IMG_BUFF_ADDRESS, C.cast(imgbuffer, C.POINTER(C.c_uint32)))  # my guess is that the cast to an uint32 is necessary to prevent 64-bit callable memory addresses
    imaq.imgSetBufferElement(bid, 0, IMG_BUFF_SIZE, bufsize)
    imaq.imgSetBufferElement(bid, 0, IMG_BUFF_COMMAND, IMG_CMD_STOP)

    # CALCULATE THE LOOKUP TABLES TO CONVERT THE BAYER ENCODED IMAGE TO RGB (=DEMOSAICING)
    imaq.imgCalculateBayerColorLUT(red_gain, green_gain, blue_gain, redLUT, greenLUT, blueLUT, bitsperpixel)


    # CAPTURE THE RAW DATA 

    imgbuffer_vpp = C.cast(C.byref(imgbuffer), C.POINTER(C.c_void_p))
    imaq.imgSnap(sid, imgbuffer_vpp)
    #imaq.imgSnap(sid, imgbuffer)  # <- doesn't work (img produced is entirely black). The above 2 lines are required
    imaq.imgSessionSaveBufferEx(sid, imgbuffer,"bayer_mosaic.png")
    print('1 taken')


    imaq.imgBayerColorDecode(RGBbuffer, imgbuffer, height, width, width, width, redLUT, greenLUT, blueLUT, IMG_BAYER_PATTERN_BGBG_GRGR, bitsperpixel, 0) 
    imaq.imgSessionSaveBufferEx(sid,RGBbuffer,"snapshot_decoded.png");

    free_associated_resources = 1
    imaq.imgSessionStopAcquisition(sid)
    imaq.imgClose(sid, free_associated_resources )
    imaq.imgClose(iid, free_associated_resources )
    print "Finished"

跟进:经过与镍代表的讨论后,我确信第二个问题是因为imgBayerColorDecode在2012年发布之前被限制在8位输入图像(我们正在为2010年工作)。但是,我想确认这一点:如果我将10位映像转换为8位映像,只保留最重要的字节,并将此转换版本传递给imgBayerColorDecode,我希望看到一个RGB图像。

为此,我将imgbuffer转换为numpy数组,并将10位数据转换为2位:

代码语言:javascript
复制
np_buffer = np.core.multiarray.int_asbuffer(
    ctypes.addressof(imgbuffer.contents), bufsize)
flat_data = np.frombuffer(np_buffer, np.uint16)

# from 10 bit to 8 bit, keeping only the non-empty bytes
Z = (flat_data>>2).view(dtype='uint8')[::2] 
Z2 = Z.copy()  # just in case

现在,我将ndarray Z2传递给imgBayerColorDecode:

代码语言:javascript
复制
bitsperpixel = 8
imaq.imgBayerColorDecode(RGBbuffer, Z2.ctypes.data_as(
    ctypes.POINTER(ctypes.c_uint8)), height, width, 
    width, width, redLUT, greenLUT, blueLUT, 
    IMG_BAYER_PATTERN_BGBG_GRGR, bitsperpixel, 0)

请注意,原来的代码(如上所示)已被稍加修改,因此redLUt、greenLUT和blueLUT现在仅为256个元素数组。最后,我给imaq.imgSessionSaveBufferEx(sid,RGBbuffer, save_path)打电话。但它仍然是一个灰度和img形状没有保存,所以我仍然做了一些可怕的错误。有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-25 07:50:07

经过一段时间的反复试验,原来提到的RGBbuffer必须保存正确的数据,但是imgSessionSaveBufferEx在这一点上做了一些奇怪的事情。

当我将数据从RGBbuffer传递回numpy时,将这个一维数组重新定位到图像的维数中,然后通过掩蔽和使用位移操作(例如red_channel = (np_RGB & 0XFF000000)>>16)将其分割成颜色通道,然后我可以使用PIL或pypng将其保存为png格式的漂亮彩色图像。

我还没有找到为什么imgSessionSaveBufferEx的行为奇怪,但上面的解决方案是有效的(尽管就速度而言,它确实是低效的)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17095359

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档