如何通过HTTP服务器在Android端显示Raspberry Pi摄像头图像流
Hey there! I’ve built a few Raspberry Pi robot projects with Android control, so I can walk you through exactly how to get that camera stream up and running over HTTP. Let’s break this down into manageable steps for your setup.
Since you’re already using OpenCV for image processing, we can embed a lightweight HTTP server directly into your Python code to stream the processed frames. This way, you don’t need extra tools like mjpg-streamer—you’ll have full control over the frames before they’re sent to Android.
Here’s a working code snippet you can adapt:
import cv2 from http.server import BaseHTTPRequestHandler, HTTPServer # Initialize camera (adjust resolution based on your needs/performance) cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) class StreamHandler(BaseHTTPRequestHandler): def do_GET(self): # Handle only the /stream endpoint if self.path == '/stream': self.send_response(200) # Use multipart mixed replace to send continuous frames self.send_header('Content-type', 'multipart/x-mixed-replace; boundary=frame') self.end_headers() while True: ret, frame = cap.read() if not ret: break # Exit loop if camera disconnects # --- Add your OpenCV processing here --- # Example: frame = cv2.Canny(frame, 100, 200) # Replace with your actual image processing logic # Encode frame to JPEG (adjust quality for speed/size tradeoff) ret, jpeg = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 70]) frame_bytes = jpeg.tobytes() # Send the frame over HTTP self.wfile.write(b'--frame\r\n') self.send_header('Content-Type', 'image/jpeg') self.send_header('Content-Length', len(frame_bytes)) self.end_headers() self.wfile.write(frame_bytes) self.wfile.write(b'\r\n') else: self.send_response(404) self.end_headers() def run_server(port=8000): server_address = ('', port) # Listen on all available interfaces httpd = HTTPServer(server_address, StreamHandler) try: print(f"Stream running at http://<your-pi-ip>:{port}/stream") httpd.serve_forever() except KeyboardInterrupt: pass # Cleanup httpd.server_close() cap.release() if __name__ == '__main__': run_server()
- How it works: The server listens for requests to
/stream, then sends a continuous stream of JPEG frames using themultipart/x-mixed-replacecontent type—this tells Android to keep updating the image as new frames arrive. - Important: Replace
<your-pi-ip>with your Raspberry Pi’s local IP address (find it withhostname -Iin the Pi terminal).
On the Android side, you’ll need to fetch the stream from the Pi’s HTTP server and render it in your app. You can use OkHttp for reliable network requests, and update an ImageView with each new frame.
First, add dependencies
In your app-level build.gradle file, add OkHttp:
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
Then, create a stream loader class
This class handles fetching the stream, parsing the multipart frames, and updating the UI:
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Looper; import android.widget.ImageView; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; import java.io.IOException; import java.io.InputStream; public class CameraStreamLoader { private final OkHttpClient client = new OkHttpClient(); private final ImageView streamView; private final String streamUrl; private boolean isStreaming = true; private final Handler mainHandler = new Handler(Looper.getMainLooper()); public CameraStreamLoader(ImageView streamView, String streamUrl) { this.streamView = streamView; this.streamUrl = streamUrl; } public void startStreaming() { new Thread(() -> { Request request = new Request.Builder().url(streamUrl).build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Failed to connect: " + response.code()); ResponseBody body = response.body(); if (body == null) return; InputStream inputStream = body.byteStream(); byte[] buffer = new byte[4096]; int bytesRead; boolean isNewFrame = false; while (isStreaming && (bytesRead = inputStream.read(buffer)) != -1) { String chunk = new String(buffer, 0, bytesRead); // Detect the start of a new frame (boundary from our Pi server) if (chunk.contains("--frame")) { isNewFrame = true; // Skip headers to get to the JPEG data int jpegStart = chunk.indexOf("\r\n\r\n") + 4; if (jpegStart != -1) { byte[] jpegData = chunk.substring(jpegStart).getBytes(); updateImage(jpegData); } } else if (isNewFrame) { // Process the remaining JPEG data for the current frame updateImage(buffer, bytesRead); isNewFrame = false; } } } catch (IOException e) { e.printStackTrace(); } }).start(); } private void updateImage(byte[] data, int length) { Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, length); if (bitmap != null) { mainHandler.post(() -> streamView.setImageBitmap(bitmap)); } } private void updateImage(byte[] data) { updateImage(data, data.length); } public void stopStreaming() { isStreaming = false; } }
Use the loader in your Activity/Fragment
Add an ImageView to your layout (e.g., activity_main.xml):
<ImageView android:id="@+id/camera_stream" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitCenter"/>
Then in your Activity:
import android.os.Bundle; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private CameraStreamLoader streamLoader; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView streamView = findViewById(R.id.camera_stream); // Replace <pi-ip> with your Raspberry Pi's local IP String streamUrl = "http://<pi-ip>:8000/stream"; streamLoader = new CameraStreamLoader(streamView, streamUrl); streamLoader.startStreaming(); } @Override protected void onDestroy() { super.onDestroy(); // Stop streaming when the activity is destroyed if (streamLoader != null) { streamLoader.stopStreaming(); } } }
Don’t forget permissions!
Add internet permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
- Network Setup: Make sure your Raspberry Pi and Android device are on the same local network (either connected to the same WiFi router, or the Pi can host a WiFi hotspot for your phone to connect to).
- Performance Optimization: If you notice lag, try reducing the camera resolution (e.g., 320x240) or lowering JPEG quality in the Pi code. You can also run OpenCV processing and HTTP streaming on separate threads to avoid blocking.
- Arduino Communication: The HTTP server runs independently of your Pi-Arduino serial communication, so you shouldn’t have conflicts—just make sure your serial code runs in a separate thread to avoid blocking the stream.
- Error Handling: Add retry logic in the Android code if the stream drops, and handle camera disconnects on the Pi side gracefully.
内容的提问来源于stack exchange,提问作者Anirudh Gangwal

