Creating a Leptonica PIX
structure from a Numpy array can be done without encoding the data as a image format meant for storage and channeling that somehow via the kernel as file within the same process. Convert the array data from OpenCV to RGBA data and wrap enough from Leptonica to create an empty PIX
structure of the appropriate size and then copy the data from the array into the PIX
.
Here is a small example how to load an image with OpenCV, convert it into a Python object wrapping a PIX
structure, and save the image data with Leptonica into a file again:
#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
from ctypes import c_char_p, c_uint32, c_void_p, CDLL, memmove, pointer, POINTER
from ctypes.util import find_library
import cv2
LEPTONICA = CDLL(find_library('lept'))
_pix_create = LEPTONICA.pixCreate
_pix_create.argtypes = [c_uint32, c_uint32, c_uint32]
_pix_create.restype = c_void_p
_pix_destroy = LEPTONICA.pixDestroy
_pix_destroy.argtypes = [POINTER(c_void_p)]
_pix_destroy.restype = None
_pix_get_data = LEPTONICA.pixGetData
_pix_get_data.argtypes = [c_void_p]
_pix_get_data.restype = POINTER(c_uint32)
_pix_endian_byte_swap = LEPTONICA.pixEndianByteSwap
_pix_endian_byte_swap.argtypes = [c_void_p]
_pix_endian_byte_swap.restype = c_uint32
_pix_write_implied_format = LEPTONICA.pixWriteImpliedFormat
_pix_write_implied_format.argtypes = [c_char_p, c_void_p, c_uint32, c_uint32]
_pix_write_implied_format.restype = c_uint32
class Pix(object):
def __init__(self, width, height, depth):
self._as_parameter_ = _pix_create(width, height, depth)
self._pointer = pointer
self._pix_destroy = _pix_destroy
def __del__(self):
pix_pointer = self._pointer(c_void_p(self._as_parameter_))
self._pix_destroy(pix_pointer)
assert pix_pointer[0] is None
@property
def data(self):
return _pix_get_data(self)
def endian_byte_swap(self):
_pix_endian_byte_swap(self)
def save(self, filename, quality=0, progessive=False):
_pix_write_implied_format(filename, self, quality, progessive)
@classmethod
def from_rgba(cls, array):
width, height, depth = array.shape
if depth != 4 and array.itemsize != 1:
raise ValueError('array has wrong format')
result = cls(width, height, 32)
memmove(result.data, array.ctypes.data, array.size * array.itemsize)
result.endian_byte_swap()
return result
def main():
image = cv2.imread('test.jpg')
image = cv2.cvtColor(image, cv2.cv.CV_BGR2RGBA)
pix = Pix.from_rgba(image)
pix.save('test.png')
if __name__ == '__main__':
main()