3

I am trying to use Leptonica (C library) from within python. The library has a pixRead method that takes absolute path to an image file as a parameter. Currently I'm successfully calling this from python like this:

leptonica = ctypes.cdll.LoadLibrary("/path/to/lept.so")
pix_image = leptonica.pixRead("/path/to/image.jgp")

However, I would like to call the method pixReadStream that takes in file stream as an input parameter. In my python program, I have access to the image as a numpy array using OpenCV.

Question

Is there any way to pass an image I have as a numpy array in my Python program to the pixReadStream method in leptopnica C library that takes file stream as an input parameter?

roi #OpenCV image numpy array
leptonica = ctypes.cdll.LoadLibrary("/path/to/lept.so")
pix_image = leptonica.pixReadStream(##any way to pass roi here?##)
2
  • pix_image will be of type int and not of type PIX*, so you cannot really do anything with it unless you tell python how to handle the struct PIX. Anyway, to answer your initial question, you could try to create a file-like object by using numpy.ndarray.tostring and StringIO Commented Apr 19, 2016 at 6:16
  • Modelling the PIX struct is not really necessary as Leptonica has accessor functions for all fields considered public. So you can get away with that number and using it as address for a void pointer. StringIO won't work as that isn't a real operating system level file but just a Python object with methods expected from a file from Python's point of view. Commented May 18, 2016 at 22:32

3 Answers 3

0

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()
Sign up to request clarification or add additional context in comments.

Comments

-1

Does this help you maybe?

There is an answer given which says that "You can use PyFile_AsFile from it."

1 Comment

That doesn't help as we don't have a file open for reading here.
-1
  1. For the conversion you can have numpy.load function...http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.load.html

https://github.com/numpy/numpy/blob/v1.10.1/numpy/lib/npyio.py#L257-L419

  1. For communicating with c...you can have ctypes or cffi

https://kogs-www.informatik.uni-hamburg.de/~seppke/content/teaching/wise1314/20131107_pridoehl-cffi.pdf

1 Comment

Ad 1: Adam already has a numpy array, so numpy.load() makes no sense. Ad 2: Adam already knows about ctypes and with cffi there's still the same problem/question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.