Размер сообщений 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, и что это за добавляющая часть.
Я не могу найти причину в своем коде, поэтому я вставил свой код подробно для вас. Мне действительно нужна помощь! Заранее спасибо!
1 ответ
Может быть, мне действительно нужно сначала проверить API, прежде чем задавать вопрос здесь. Это очень простой вопрос, если бы я проверял свойства ChannelBuffer в API, потому что свойство arrayOffset уже сообщило мне ответ на этот вопрос!
Что ж, ради большей осторожности, и кто-то из вас, ребята, нуждается в разъяснении моего ответа, поэтому я должен сделать объяснение в деталях!
Во-первых, я должен сказать, что я до сих пор не знаю, как ChannelBuffer упаковывает данные массива байтов изображения, это означает, что я до сих пор не знаю, почему должен быть arrayOffset перед данными массива. Почему мы не можем просто получить данные? Есть ли действительно важные причины существования arrayOffset? Ради безопасности или эффективности? Я не знаю, я не могу найти ответ от API. Так что я действительно устал от этого вопроса сейчас, и я устал от того, что вы, ребята, отрицательно относитесь к этому вопросу или нет, просто отпустите его!
Возвращаясь к теме, проблему можно решить следующим образом:
int offset = compressedImage.getData().arrayOffset();
Bitmap bmp = BitmapFactory.decodeByteArray(receivedImageBytes, offset, receivedImageBytes.length - offset);
ХОРОШО! Я все еще надеюсь, что кто-то, кто хорошо знает это, может сказать мне, почему, я буду так благодарен за это! Если вы, ребята, просто устали от такого вопроса, как я, просто давайте проголосуем, чтобы закрыть его, я тоже буду благодарен! Спасибо, в любом случае!