我需要帮助从我的树莓PI(Python)通过TCP传输PNG图像到我的Android应用程序(Java)。我花了近两个星期的时间来理解和解决这个问题,所以任何帮助都会非常感谢。
我已经建立了一个客户机-服务器架构,这样我的Raspberry Pi3记录音频,对其进行一些分析,然后(通过TCP)将数据发送到Android应用程序,显示在应用程序屏幕上。记录和分析完成后,我就可以连接并传输显示在应用程序上的字符串数据,没有问题。然而,我一直没有成功地将一个图像从rpi传输到android应用程序。所以基本上,图像存储在rpi上,我试图将图像传输到应用程序以显示它。
当前实施:
关于rpi(python):正如我所说,发送字符串并在android应用程序上显示它们是没有任何问题的。当我发送音频分析的图像部分时,我首先发送一个字符串,上面写着“?启动“以便Android端知道将要发送图像而不是字符串(并等待更新GUI,直到它接收到整个图像)。然后,我打开存储在rpi上的图像,将整个图像作为字节数组读取(通常大约40-50k字节)。我得到字节数组的长度并将其作为字符串发送到android应用程序。最后,我将字节数组发送给android,它等待来自应用程序的ok消息。所有这些都能正常工作,不会报告任何错误。
在Android应用程序(Java)上:当应用程序接收到“?启动“string”,然后它使用一个缓冲读卡器(这是我用来读取之前成功传输到应用程序的字符串数据)来读取图像字节数组的大小。然后,我创建一个缓冲区,一次最多读取1024个字节,msg_buff将保存图像的整个字节数组。在无限while循环中,我有一个名为baos的datainputstream,将字节读取到in并返回读取的字节数。然后,我将msg_buff的内容添加到msg_buff中。一旦从baos读取的字节数为-1或in(仅为读取的字节总数)大于或等于图像字节数组的大小,while循环将断开。然后,我将尝试将图像保存到android内部存储,然后稍后将其加载到img_offset中显示。这段代码成功地读取字节,直到有大约2000-3000个字节需要读取,然后它似乎冻结在ImageView行。我还没能通过这一点,所以我不知道是否将图像保存到内部存储器中,然后以这种方式将其加载到int bytes_read = in.read(msg_buff, 0, byte_size)也可以。我相信这是冻结的,因为一些字节丢失或不从Python发送到Java。有人知道我怎么解决这个问题吗?
从python服务器读取图像数据的代码位于ImageView方法中。
tcpclient.java
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClient {
public static final String SERVER_IP = myIPAddress; //your computer IP address
public static final int SERVER_PORT = myPortNumber;
// message to send to the server
private String mServerMessage;
// sends message received notifications
private OnMessageReceived mMessageListener = null;
// while this is true, the server will continue running
private boolean mRun = false;
// used to send messages
private PrintWriter mBufferOut;
// used to read messages from the server
private BufferedReader mBufferIn;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TcpClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends the message entered by client to the server
*
* @param message text entered by client
*/
public void sendMessage(String message) {
if (mBufferOut != null && !mBufferOut.checkError()) {
mBufferOut.println(message);
mBufferOut.flush();
}
}
/**
* Close the connection and release the members
*/
public void stopClient() {
Log.i("Debug", "stopClient");
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.e("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
InputStream sin = socket.getInputStream();
OutputStream sout = socket.getOutputStream();
DataInputStream in = new DataInputStream(sin);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//in this while the client listens for the messages sent by the server
while (mRun) {
mServerMessage = mBufferIn.readLine();
if (mServerMessage != null && mMessageListener != null) {
//Check if data is image
if(mServerMessage.equals("?start"))
{
mServerMessage = mBufferIn.readLine();
String fileName = "";
if(mServerMessage.equals("signal"))
{
fileName = "signal.jpeg";
}
else if(mServerMessage.equals("spec"))
{
fileName = "spec.jpeg";
}
// Get length of image byte array
int size = Integer.parseInt(mBufferIn.readLine());
Log.i("Debug:", "image message size: "+size);
// Create buffers
byte[] msg_buff = new byte[1024];
//byte[] img_buff = new byte[size];
int img_offset = 0;
while(true){
int byte_size = msg_buff.length;
int bytes_read = in.read(msg_buff, 0, byte_size);
Log.i("Debug:", "image message bytes:" + bytes_read);
if(bytes_read == -1){
break;
}
//copy bytes into img_buff
//System.arraycopy(msg_buff, 0, img_buff, img_offset, bytes_read);
baos.write(msg_buff, 0, bytes_read);
img_offset += bytes_read;
Log.i("Debug:", "image message bytes read:"+img_offset);
if( img_offset >= size)
{
break;
}
}
try{
byte[] data = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ContextWrapper cw = new ContextWrapper(ApplicationContextProvider.getContext());
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
File mypath = new File(directory, fileName);
//Bitmap bitmap = BitmapFactory.decodeByteArray(img_buff, 0, img_buff.length);
Bitmap bitmap = BitmapFactory.decodeStream(bais);
FileOutputStream fos = new FileOutputStream(mypath);
//Use compress method on Bitmap object to write image to OutputStream
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
//Send OK
byte[] OK = new byte[] {0x4F, 0x4B};
sout.write(OK);
} catch (Exception e) {
Log.i("Debug:", "image message" +e);
e.printStackTrace();
}
}
//call the method messageReceived from MyActivity class
mMessageListener.messageReceived(mServerMessage);
}
}
Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
//Declare the interface. The method messageReceived(String message) must be implemented in the MainActivity
//class in asynckTask doInBackground
public interface OnMessageReceived {
void messageReceived(String message);
}
}
import android.app.Application;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.*;
import org.apache.commons.codec.binary.Base64;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class MainActivity extends AppCompatActivity {
private TcpClient mTcpClient;
private TextView dbView;
private TextView roomView;
private TextView classView;
private TextView statusView;
private TextView timeView;
private ImageView signalView;
private ImageView specView;
private Button getAnalysis;
private Button disconnect;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getAnalysis = findViewById(R.id.get_analysis);
dbView = findViewById(R.id.db_level);
roomView = findViewById(R.id.RoomsValues);
classView = findViewById(R.id.ClassValues);
timeView = findViewById(R.id.timeStamp);
signalView = findViewById(R.id.audioPic);
specView = findViewById(R.id.specPic);
statusView = findViewById(R.id.status);
disconnect = findViewById(R.id.disconnect);
getAnalysis.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
statusView.setText("Connecting to Auris...\nRoom analytics will arrive shortly.");
new ConnectTask().execute("");
}
});
disconnect.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v)
{
mTcpClient.stopClient();
statusView.setText("Disconnected from Auris.\nReconnect to receive room analysis updates.");
}
});
}
public class ConnectTask extends AsyncTask<String, String, TcpClient> {
@Override
protected TcpClient doInBackground(String... message) {
//we create a TCPClient object and
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
@Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
publishProgress(message);
Log.i("Debug","Input message: " + message);
}
});
//statusView.setText("Get analysis from Auris as it is collected.");
mTcpClient.run();
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//Store string of values sent from Auris device
String str = values[0];
//if data starts with +, then it is the string data
if(str.startsWith("+"))
{
//Split values around spaces
/*
Values in data indices
0-8 are room log likelihoods
9-12 are class log likelihoods
13 is dbA level
14 is room model best matched
15 is class model best matched
*/
// Remove +
str = str.substring(1);
String data[]= str.split(" ");
String roomData = "";
String classData = "";
String status;
for(int i = 0; i < 9; i++)
{
roomData = roomData.concat(data[i]);
roomData = roomData.concat("\n");
}
roomView.setText(roomData);
for(int i = 9; i < 13; i++)
{
classData = classData.concat(data[i]);
classData = classData.concat("\n");
}
classView.setText(classData);
dbView.setText(data[13]);
status = "The room most closely matches " + data[14] + " room model & " + data[15] + " class model.";
statusView.setText(status);
}
else if (str.startsWith("TIME"))
{
// Remove "TIME"
str.substring(4);
String message = "This room profile represents the room at " + str + ".";
timeView.setText(message);
}
else
{
try {
String fileName = "";
if(str.equals("signal"))
{
fileName = "signal.jpeg";
}
else if(str.equals("spec"))
{
fileName = "spec.jpeg";
}
ContextWrapper cw = new ContextWrapper(ApplicationContextProvider.getContext());
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
File file = new File(directory, fileName);
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
signalView.setImageBitmap(bitmap);
} catch (FileNotFoundException e){
e.printStackTrace();
}
}
Log.i("onProgressUpdate",values[0]);
}
}
}
def send_image_to_byte_array(image_file, conn, label):
with open(image_file, "rb") as imageFile:
content = imageFile.read()
conn.sendall("?start\n".encode('utf-8'))
conn.sendall(label.encode('utf-8'))
size = len(content)
strSize = str(size) + "\n"
conn.sendall(strSize.encode('utf-8'))
conn.sendall(content)
run()方法中的int bytes_read = in.read(msg_buff, 0, byte_size);行上。从读取不同的帖子来看,使用Stutt.UnPcCy/Pope似乎是在将图像从Python传输到Python时修复了这个问题,但是我不知道如何在Java中实现Struts。我也不确定在Python中使用struct.pack的最佳方法是什么。非常感谢您的帮助!最佳答案
此问题是由离线读取额外数据引起的(为了填充其内部缓冲区),这使得该数据无法从BufferedReader获得。
从sample Android BufferedReader implementation中可以看到,调用in.read()会导致readLine()尝试填充其内部缓冲区。它将使用其源代码上的任何可用字节来执行此操作。最多8192个字符。而且,如果BufferedReader已经读取了这些字节,那么当您试图从InputStream获取这些字节时,它们不会在那里。这会打乱整个尺寸计算系统,意味着您最终会在BufferedReader中阻塞,因为您没有读取预期的所有数据。
最方便的解决方案可能是实现您自己的in.read()版本,该版本一次组装一个字节的字符串,直到它到达'\n'。毕竟,您需要in.read()的唯一原因是readLine()函数。
关于java - 从Python服务器到Android客户端的图像数据丢失(Endian问题??),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57184485/
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht