Размер сообщений sensor_msgs.image/compressImage type изменится при публикации / подписке в ROS-Android?

Мне нужно получить данные предварительного просмотра изображения с камеры телефона Android и опубликовать их в ROS, а вот мой пример кода:

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    if(data != null){
        Camera.Size size = camera.getParameters().getPreviewSize();
        YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);

        if(yuvImage != null){
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ChannelBufferOutputStream stream = new ChannelBufferOutputStream(MessageBuffers.dynamicBuffer());

            yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 80, baos);
            yuvImage = null;

            stream.buffer().writeBytes(baos.toByteArray());
            try{
                baos.flush();
                baos.close();
                baos = null;
            }
            catch(IOException e){
                e.printStackTrace();
            }

            // compressedImage type
            sensor_msgs.CompressedImage compressedImage = compressedImagePublisher.newMessage();
            compressedImage.getHeader().setFrameId("xxx");    // frame id

            Time curTime = connectedNode.getCurrentTime();    
            compressedImage.getHeader().setStamp(curTime);    // time

            compressedImage.setFormat("jpeg");                // format
            compressedImage.setData(stream.buffer().copy());  // data

            stream.buffer().clear();
            try {
                stream.flush();
                stream.close();
                stream = null;
            }
            catch (IOException e) {
                e.printStackTrace();
            }

            // publish
            System.out.println("-----Publish: " + compressedImage.getData().array().length + "-----");
            compressedImagePublisher.publish(compressedImage);
            compressedImage = null;
            System.gc();
        }
        else{
            Log.v("Log_Tag", "-----Failed to get yuvImage!-----");
        }
    }
    else{
        Log.v("Log_Tag", "-----Failed to get the preview frame!-----");
    }
}

А потом я подписался на эту тему, просто чтобы проверить, были ли сообщения опубликованы полностью и правильно. Как и в следующем коде:

@Override
public void onStart(ConnectedNode node) {
    this.connectedNode = node;

    // publisher
    this.compressedImagePublisher = connectedNode.newPublisher(topic_name, sensor_msgs.CompressedImage._TYPE);
    // subscriber
    this.compressedImageSubscriber = connectedNode.newSubscriber(topic_name, sensor_msgs.CompressedImage._TYPE);
    compressedImageSubscriber.addMessageListener(new MessageListener<CompressedImage>() {
        @Override
        public void onNewMessage(final CompressedImage compressedImage) {
            byte[] receivedImageBytes = compressedImage.getData().array();
            if(receivedImageBytes != null && receivedImageBytes.length != 0) {
                System.out.println("-----Subscribe(+46?): " + receivedImageBytes.length + "-----");

                // decode bitmap from byte[] with a strange number of offset and necessary
                Bitmap bmp = BitmapFactory.decodeByteArray(receivedImageBytes, offset, receivedImageBytes.length - offset);
                ...    
            }
        }
    });
}

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

Я не знаю почему, и я прочитал несколько статей о структуре jpg, и подозреваю, что это может быть информация из заголовка байтовых сообщений jpg. Тем не менее, эта проблема как раз случается в ros-android сцене.

У кого-нибудь есть хорошая идея по этому поводу?


ХОРОШО! Я знаю, что вопрос, который я задал, и проблема, описанная ранее, ужасны, поэтому получили 2 отрицательных балла. Я очень сожалею об этом, и я должен восполнить свою вину, рассказав вам, ребята, больше информации и прояснив проблему сейчас.

Во-первых, забудьте обо всем коде, который я вставил раньше. Проблема произошла в моем проекте ros-android. В этом проекте мне нужно отправить сенсорные сообщения типа сжатого изображения на ros-сервер и получить обработанные байты изображения (формат jpg) способом публикации / подписки. И теоретически, размер байтов изображения должен быть одинаковым, и фактически это было доказано в моем проекте ros-C и ros-C# при тех же условиях.

Тем не менее, они разные в ros-android, они становятся больше! По этой причине я не могу просто декодировать растровое изображение из байтов изображения, на которые я подписан, и я должен пропустить нарастающие байты со смещением в массиве байтов изображения. Я не знаю, почему это произошло в ros-android или ros-java, и что это за добавляющая часть.

Я не могу найти причину в своем коде, поэтому я вставил свой код подробно для вас. Мне действительно нужна помощь! Заранее спасибо!

Logcat

1 ответ

Решение

Может быть, мне действительно нужно сначала проверить API, прежде чем задавать вопрос здесь. Это очень простой вопрос, если бы я проверял свойства ChannelBuffer в API, потому что свойство arrayOffset уже сообщило мне ответ на этот вопрос!


Что ж, ради большей осторожности, и кто-то из вас, ребята, нуждается в разъяснении моего ответа, поэтому я должен сделать объяснение в деталях!

Во-первых, я должен сказать, что я до сих пор не знаю, как ChannelBuffer упаковывает данные массива байтов изображения, это означает, что я до сих пор не знаю, почему должен быть arrayOffset перед данными массива. Почему мы не можем просто получить данные? Есть ли действительно важные причины существования arrayOffset? Ради безопасности или эффективности? Я не знаю, я не могу найти ответ от API. Так что я действительно устал от этого вопроса сейчас, и я устал от того, что вы, ребята, отрицательно относитесь к этому вопросу или нет, просто отпустите его!

Возвращаясь к теме, проблему можно решить следующим образом:

int offset = compressedImage.getData().arrayOffset();
Bitmap bmp = BitmapFactory.decodeByteArray(receivedImageBytes, offset, receivedImageBytes.length - offset);

ХОРОШО! Я все еще надеюсь, что кто-то, кто хорошо знает это, может сказать мне, почему, я буду так благодарен за это! Если вы, ребята, просто устали от такого вопроса, как я, просто давайте проголосуем, чтобы закрыть его, я тоже буду благодарен! Спасибо, в любом случае!

Другие вопросы по тегам