我有一个配备了摄像头的树莓派4,一个过程是使用OpenCV库捕捉图像。这个图像然后被转发到两个目的地。
这是Raspberry PI上的图像服务器(C++)。
#define MAX_IMAGESIZE 40090
typedef struct __attribute__((packed))
uint16_t len;
uint8_t data[MAX_IMAGESIZE];
} image_msg;
void __attribute__((noreturn)) camera_task()
cv::VideoCapture capture(0);
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in pcaddr, phaddr;
memset(&pcaddr, 0x00, sizeof(struct sockaddr_in));
memset(&phaddr, 0x00, sizeof(struct sockaddr_in));
pcaddr.sin_family = AF_INET;
pcaddr.sin_addr.s_addr = inet_addr(PC_ADDRESS);
pcaddr.sin_port = htons(4321);
phaddr.sin_family = AF_INET;
phaddr.sin_addr.s_addr = inet_addr(PH_ADDRESS);
phaddr.sin_port = htons(4321);
if (!capture.isOpened())
exit(EXIT_FAILURE);
cv::Mat frame;
while (1)
if (!capture.read(frame))
exit(EXIT_FAILURE);
cv::flip(frame, frame, -1);
std::vector<int> params;
std::vector<uint8_t> buffer;
params.push_back(cv::IMWRITE_JPEG_QUALITY);
params.push_back(60);
cv::imencode(".jpg", frame, buffer, params);
image_msg outmsg;
outmsg.len = static_cast<uint16_t>(buffer.size());
for(uint16_t i = 0; i < outmsg.len; i++)
outmsg.data[i] = buffer[i];
if(sendto(sock, reinterpret_cast<char*>(&outmsg), sizeof(outmsg), 0, reinterpret_cast<struct sockaddr*>(&pcaddr), sizeof(pcaddr)) > 0)
//printf("OK sendto PC\n");
perror("Camera task to PC");
if(sendto(sock, reinterpret_cast<char*>(&outmsg), sizeof(outmsg), 0, reinterpret_cast<struct sockaddr*>(&phaddr), sizeof(phaddr)) > 0)
//printf("OK sendto PHONE\n");
perror("Camera task to PHONE");
这是笔记本电脑上的图像客户端(C++)。
cv::Mat *imagewindow;
void init_window()
init_localsock(&imu_socket, &imu_saddr, IMUPORT); //not related with camera
init_localsock(&speed_socket, &speed_saddr, VELPORT); //not related with camera
init_localsock(&attitude_socket, &attitude_saddr, ATTPORT); //not related with camera
init_localsock(&radiation_socket, &radiation_saddr, RADPORT); //not related with camera
init_localsock(&throttle_socket, &throttle_saddr, THRPORT); //not related with camera
init_localsock(&image_socket, &image_saddr, RENPORT); //initialize socket on port 4321
imagewindow = new cv::Mat(600, 600, CV_8UC3, cv::Scalar(0, 0, 0));
cv::imshow(PROJNAME, *imagewindow);
void main_loop(const char* board_address)
while(true)
imu_task();
speed_task();
attitude_task();
radiation_task();
throttle_task();
image_task(); //this is the image receiver task
render_window();
cmd_out_task(board_address);
void image_task()
image_msg recv; //the same struct defined on the raspberry
socklen_t len;
ssize_t bytes_recv = recvfrom(image_socket, &recv, sizeof(image_msg), 0, (struct sockaddr*)&image_saddr, &len);
if(bytes_recv > 0)
memset(imagewindow->data, 0x00, imagewindow->dataend - imagewindow->data);
update_image(recv);
void update_image(image_msg image)
std::vector<char> data(image.data, image.data + image.len);
*imagewindow = cv::imdecode(cv::Mat(data), 1);
而且工作正常。这里是正在发生的情况的截图。
下面我们来看看问题所在。安卓系统上的接收器是这样的。
private byte[] recv_image(DatagramSocket sock) throws Exception
byte[] b = new byte[40090];
DatagramPacket p = new DatagramPacket(b, b.length);
byte[] recv_length = new byte[4];
length[3] = b[0];
length[2] = b[1];
int recv_len = ByteBuffer.wrap(length).getInt();
byte[] image_bytes = new byte[recv_len];
for(int i = 0; i < recv_len; i++)
image_bytes[i] = b[4 + i];
return image_bytes;
接收线程正在做。
initialize_videosocket(); //init a local UDP socket on port 4321
while(true)
final byte[] imagebytes = recv_image(video_sock);
Bitmap bmp = BitmapFactory.decodeByteArray(imagebytes, 0, imagebytes.length);
catch(Exception e)
Log.d("Exception in image thread: " + e.toString();
问题是,Bitmap bmp总是为空。从文档中可以看出,如果JPG是无效的,decodeByteArray返回null。这些是我做的尝试。
试着在我的安卓应用中使用opencv。
Mat mat = Imgcodecs.imdecode(new MatOfByte(imagebytes), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
Bitmap bmp = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rgb, bmp);
但mat.cols()
和mat.rows()
都返回-1。 我强制参数为480,640(因为它应该是),我在执行Utils.matToBitmap
时得到一个断言失败。
试着比较笔记本和手机上收到的jpg缓冲区。它们是相等的。
试着在一个.jpg文件上写jpg缓冲区,然后用Gimp把它作为标准的.jpg文件打开。它起作用了,所以缓冲区包含一个正确的.jpg文件,但如果缓冲区不是一个有效的.jpg文件,decodeByteArray应该返回null。
我真的被困于此,希望得到任何帮助。谢谢