我使用UDP套接字将图像从客户端传输到服务器。对于编码和解码,我使用OpenCV。有时我会得到错误的解码图像,因为丢失了一个或一些数据包(只发送了头文件,请查看我的终端屏幕了解一些信息)。我必须将jpeg的质量降低到30,以减少错误的解码图像比例。如何使用条件代码忽略丢失某些数据包的帧(不进行解码工作),或者在imshow函数中不显示错误的解码图像。如何修复或忽略通过套接字流式传输的错误解码图像
这里的错误解码图像:
终端跟踪屏幕:
我的客户代码:
#include "PracticalSocket.h"
#include <iostream>
#include <cstdlib>
#include "cv.hpp"
#include "config.h"
#include "logger.h" // For trace
using namespace ModernCppCI;
using namespace cv;
using namespace std;
int main(int argc, char * argv[]) {
Logger log{__func__};
if ((argc < 4) || (argc > 4)) { // Test for correct number of arguments
log.error("Usage: {} <Server> <Server Port>\n <RTSP link>", argv[0]);
exit(1);
}
string servAddress = argv[1]; // First arg: server address
unsigned short servPort = Socket::resolveService(argv[2], "udp");
try {
UDPSocket sock;
int jpegqual = ENCODE_QUALITY; // It's 30
Mat frame, send;
vector <uchar> encoded;
//VideoCapture cap("rtsp://admin:[email protected].234/Streaming/Channels/1?tcp"); // Grab the camera
VideoCapture cap(argv[3]);
if (!cap.isOpened()) {
log.error("OpenCV failed to open camera");
exit(1);
}
clock_t last_cycle = clock();
unsigned char pressed_key;
while (1) {
vector <int> compression_params;
cap >> send;
if(send.empty())continue;
// JPEG encoding
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(jpegqual);
imencode(".jpg", send, encoded, compression_params);
imshow("send", send);
int total_pack = 1 + (encoded.size() - 1)/PACK_SIZE; // PACK_SIZE is 4096
int ibuf[1];
ibuf[0] = total_pack;
sock.sendTo(ibuf, sizeof(int), servAddress, servPort);
for (int i = 0; i < total_pack; i++)
sock.sendTo(& encoded[i * PACK_SIZE], PACK_SIZE, servAddress, servPort);
pressed_key = waitKey(1);
if(pressed_key == ' ')
pressed_key = waitKey(0);
if(pressed_key == 'q')
break;
clock_t next_cycle = clock();
double duration = (next_cycle - last_cycle)/(double) CLOCKS_PER_SEC;
log.info(" FPS: {}, kbps: {}, Processing time: {}ms" , (1/duration), (PACK_SIZE * total_pack/duration/1024 * 8), 1000*duration);
last_cycle = next_cycle;
}
// Destructor closes the socket
} catch (SocketException & e) {
log.error(e.what());
exit(1);
}
return 0;
}
Server代码
#include "PracticalSocket.h"
#include <iostream>
#include <cstdlib>
#include "cv.hpp"
#include "config.h"
#include "logger.h" // For trace
using namespace ModernCppCI;
using namespace cv;
int main(int argc, char * argv[]) {
Logger log{__func__};
if (argc != 2) { // Test for correct number of parameters
log.error("Usage: {} <Server Port>", argv[0]);
exit(1);
}
unsigned short servPort = atoi(argv[1]); // First arg: Server port
try {
UDPSocket sock(servPort);
char buffer[BUF_LEN]; // Buffer for echo string
int recvMsgSize; // Size of received message
string sourceAddress; // Address of datagram source
unsigned short sourcePort; // Port of datagram source
clock_t last_cycle = clock();
unsigned char pressed_key;
while (1) {
// Block until receive message from a client
do {
recvMsgSize = sock.recvFrom(buffer, BUF_LEN, sourceAddress, sourcePort); // BUF_LEN is 65540
} while (recvMsgSize > sizeof(int));
int total_pack = ((int *) buffer)[0];
log.info("expecting length of packs: {}", total_pack);
char * longbuf = new char[PACK_SIZE * total_pack];
for (int i = 0; i < total_pack; i++) {
recvMsgSize = sock.recvFrom(buffer, BUF_LEN, sourceAddress, sourcePort);
if (recvMsgSize != PACK_SIZE) {
log.error("Received unexpected size pack: {}", recvMsgSize);
continue;
}
memcpy(& longbuf[i * PACK_SIZE], buffer, PACK_SIZE); // Copy PACK_SIZE bytes from buffer to longbuf
}
log.info("Received packet from {}:{}", sourceAddress, sourcePort);
Logger::level(LogLevel::trace);
log.trace("longbuf size: {}", ((int *) &longbuf)[0]);
Mat rawData = Mat(1, PACK_SIZE * total_pack, CV_8UC1, longbuf);
Mat frame = imdecode(rawData, CV_LOAD_IMAGE_COLOR);
if (frame.empty()) {
log.error("Decode failure!");
continue;
}
imshow("recv", frame);
pressed_key = waitKey(1);
if(pressed_key == ' ')
pressed_key = waitKey(0);
if(pressed_key == 'q')
break;
free(longbuf);
clock_t next_cycle = clock();
double duration = (next_cycle - last_cycle)/(double) CLOCKS_PER_SEC;
log.info(" FPS: {} , kbps: {} , Processing time: {}", (1/duration), (PACK_SIZE * total_pack/duration/1024 * 8), (next_cycle - last_cycle));
last_cycle = next_cycle;
}
} catch (SocketException & e) {
log.error(e.what());
exit(1);
}
return 0;
}
我想了解你的问题。当你检测到一个意想不到的大小数据包时,你想跳过整个帧;基本上,当你检查解码失败并继续时,你会想检查帧是否有意想不到的大小数据包并继续? – Basya