Передача байтового массива от java до python на Android с использованием Chaquopy - PullRequest
1 голос
/ 22 марта 2020

Я запускаю приложение камеры android и хочу выполнить обработку изображений в Python. Чтобы проверить это, я хочу передать один кадр изображения в функцию python, разделить все значения на 2, используя целочисленное деление, и вернуть результат.

Для этого у меня есть следующий код:

в Java:

public void onCapturedImage(Image image)
    {

        Image.Plane[] tmp = image.getPlanes();
        byte[] bytes = null;
        ByteBuffer buffer = tmp[0].getBuffer();
        buffer.rewind();
        bytes = new byte[buffer.remaining()];
        buffer.get(bytes, 0, buffer.remaining());
        buffer.rewind();

        Log.d(TAG, "start python section");

        // assume python.start() is elsewhere

        Python py = Python.getInstance();
        PyObject array1 = PyObject.fromJava(bytes);
        Log.d(TAG, "get python module");
        PyObject py_module = py.getModule("mymod");
        Log.d(TAG, "call pic func");

        byte [] result  = py_module.callAttr("pic_func", array1).toJava(byte[].class);
        // compare the values at some random location to see make sure result is as expected
        Log.d(TAG, "Compare: "+Byte.toString(bytes[33]) + " and " + Byte.toString(result[33]));
        Log.d(TAG,"DONE");

    }

В python, у меня есть следующее:

import numpy as np

def pic_func(o):
    a = np.array(o)
    b = a//2
    return b.tobytes()

У меня есть несколько проблем с этим кодом.

  1. Не работает должным образом - значение в местоположении 33 не равно половине. Возможно, я перепутал значения байтов, но я не уверен, что именно происходит. Тот же код без «тобайт» и с использованием списка python вместо массива numpy работает как положено.

  2. Передача параметров - не уверен, что происходит под капотом. Это передать по значению или по ссылке? Копируется ли массив, или просто передается указатель?

  3. Это МЕДЛЕННО. на вычисление этой операции уходит более 12 миллионов значений. Есть какие-нибудь указания по ускорению этого процесса?

Спасибо!

1 Ответ

1 голос
/ 23 марта 2020

Ваши последние два вопроса связаны, поэтому я отвечу на них вместе.

PyObject array1 = PyObject.fromJava(bytes)
py_module.callAttr("pic_func", array1)

Передается по ссылке: код Python получает объект jarray, который обращается к исходному массиву.

np.array(o)

np.array всегда делает копию, и в этом случае это будет медленная копия, потому что к массиву нужно обращаться по одному элементу за раз через JNI. Вы можете избежать этого, сначала преобразовав объект Python bytes, что можно сделать на любом языке:

  • В Java: PyObject array1 = py.getBuiltins().callAttr("bytes", bytes)
  • Или в Python: np.array(bytes(o))

Это фактически приведет к созданию дополнительной копии, но поскольку все копии теперь можно выполнять с помощью прямой копии в памяти, это будет намного быстрее.

b.tobytes()
toJava(byte[].class)

Оба эти выражения также сделают копию, но они также будут прямыми копиями памяти, поэтому производительность не должна быть проблемой.

Что касается возврата неправильного ответа, я думаю, это возможно потому, что NumPy использует тип данных по умолчанию float64. При вызове np.array вы должны явно указать тип данных, передав dtype=np.int8 или dtype=np.uint8. (Если вы ищете byte[] в документации Chaquopy , вы найдете точную информацию о том, как работает преобразование со знаком / без знака, но, вероятно, проще просто попробовать оба варианта и посмотреть, какой из них дает ожидаемый ответ .)

...