C++ OpenCV/C++;:如何有效设置Raspberry Cam帧速率
我最近开始使用OpenCV。虽然一开始我取得了很大的进步,但现在我几乎忘记了一项看似简单的任务:用树莓皮摄像机录制一段简单的视频。问题是生成的视频似乎是快进的,原因似乎是在录制时实际写入的必要帧不到一半 经过一个多小时的编解码器实验和对代码进行时间测量以找出瓶颈后,我现在发现问题似乎与OpenCV VideoCapture类有关,在我的代码中,它的实例实际提供的帧远少于预期 所以我写了一篇简单的文章,计算视频捕获在五秒钟内传送的帧数。将捕获的属性设置为640x480x30fps效果良好,可提供大约150帧。但是,将其拨到1920x1080x30fps(根据规格,这是一种有效的相机模式,在其他应用中也可以正常工作)时,5秒钟内只能得到15帧左右的画面 可能有一个非常明显的解决方案,但我完全茫然了。有人能帮我吗?谢谢C++ OpenCV/C++;:如何有效设置Raspberry Cam帧速率,c++,opencv,raspberry-pi,C++,Opencv,Raspberry Pi,我最近开始使用OpenCV。虽然一开始我取得了很大的进步,但现在我几乎忘记了一项看似简单的任务:用树莓皮摄像机录制一段简单的视频。问题是生成的视频似乎是快进的,原因似乎是在录制时实际写入的必要帧不到一半 经过一个多小时的编解码器实验和对代码进行时间测量以找出瓶颈后,我现在发现问题似乎与OpenCV VideoCapture类有关,在我的代码中,它的实例实际提供的帧远少于预期 所以我写了一篇简单的文章,计算视频捕获在五秒钟内传送的帧数。将捕获的属性设置为640x480x30fps效果良好,可提供大
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <ctime>
float getElapsedCPUTime(std::clock_t begin){
return float(clock() - begin)/CLOCKS_PER_SEC;
}
std::time_t getCurrentWallTime(){
return std::time(nullptr);
}
int main (){
// int cols(640);
// int rows(480);
int cols(1920);
int rows(1080);
cv::Mat currentFrame;
// set capture properties
cv::VideoCapture cap(0);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, rows);
cap.set(CV_CAP_PROP_FRAME_WIDTH, cols);
cap.set(cv::CAP_PROP_FPS, 30);
cap.set(cv::CAP_PROP_FOURCC, 0x21);
// control capture properties
int rows_c(cap.get(CV_CAP_PROP_FRAME_HEIGHT));
int cols_c(cap.get(CV_CAP_PROP_FRAME_WIDTH));
int fps(cap.get(cv::CAP_PROP_FPS));
std::cout << "rows: " << rows_c << ", cols " << cols_c << ", fps " << fps << ", CPS: " << CLOCKS_PER_SEC << std::endl;
int cnt(0);
std::time_t loopExecution_begin(getCurrentWallTime());
while(1){
std::string msg("");
// capture frame
std::clock_t capture_begin(clock());
cap >> currentFrame;
float time_for_capture = getElapsedCPUTime(capture_begin);
++cnt;
// get elapsed wall time
std::time_t loopRunTime = getCurrentWallTime() - loopExecution_begin;
// output message
msg += "#: " + std::to_string(cnt);
msg += "\tTicks begin: " + std::to_string(capture_begin);
msg += "\tCapturetime: " + std::to_string(time_for_capture) + "s";
msg += "\tLoop Runtime: " + std::to_string(loopRunTime) + "s";
std::cout << msg << std::endl;
// break after 5s
if (loopRunTime > 5.0) break;
}
}
似乎您希望从相机中获得h.264流 当你想对相机帧进行一些处理时,OpenCV是无与伦比的,但我不一定要将它用于需要获得H.264的任务,因为Pi有一个硬件H.264编码器,我不确定在你的情况下是否会使用它 要将h.264输出到文件中,或者在某个地方对其进行流式处理,您可以使用标准的raspivid应用程序并将其输出传输到您想要的地方,或者如果您需要更多的控制,您可以获取它的源代码并对其进行修改 我变得懒惰,做了前者。下面的代码将H.264流传输到TCP套接字。 如果出现拥塞(即数据不能足够快地写入套接字,代码将关闭套接字,然后客户端重新连接)。这种方法可能不是非常优雅,但我已经使用了一段时间,它似乎工作正常
#include "CameraRelay.h"
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/select.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <thread>
#include <mutex>
#include <memory>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#define READ 0
#define WRITE 1
pid_t popen2(const char *command, char * const args[], int *infp, int *outfp) {
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execv(command, args);
perror("execl");
exit(1);
}
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
namespace CameraRelay {
static std::unique_ptr<std::thread> s_thread;
static std::mutex s_startStopMutex;
static bool s_bRun;
int s_listensock = -1;
void RelayThread() {
signal(SIGPIPE, SIG_IGN);
s_listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s_listensock < 0) {
perror("socket() for camera relay failed");
return;
}
int on = 1;
setsockopt(s_listensock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
ioctl(s_listensock, FIONBIO, (char *)&on);
unsigned int bufsz = 1024; // small buffer to control latency
setsockopt(s_listensock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsz, sizeof(bufsz));
struct sockaddr_in sa;
memset((char *)&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(7124);
if (bind(s_listensock, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0) {
perror("bind() for camera relay failed");
return;
}
bufsz = 1024; // small buffer to control latency
setsockopt(s_listensock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsz, sizeof(bufsz));
if (listen(s_listensock, 1)) {
perror("listen() for camera relay failed");
return;
}
while (s_bRun) {
sockaddr_in sa;
memset((char *)&sa, 0, sizeof(sa));
socklen_t len = sizeof(sa);
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = s_listensock;
pfd.events = POLLIN;
int ret = poll(&pfd, 1, 500);
if (ret > 0) {
int sock = accept(s_listensock, (struct sockaddr *)&sa, &len);
unsigned int bufsz = 16384; // small buffer to control latency
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsz, sizeof(bufsz));
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
printf("camera relay socket got new connection.\n");
char buffer[512];
std::string cmd = "/usr/bin/raspivid";
const char *args[] = { "/usr/bin/raspivid", "-o", "-", "-n" , "-s", "-t" ,"0", "-fl", "-hf", "-b", "5000000", "-w", "1280", "-h", "720", "-fps", "25", nullptr };
int pin = 0;
int pout = 0;
pid_t pid = popen2(cmd.c_str(), const_cast<char **>(args), &pin, &pout);
if (pid <= 0) {
perror("popen() failed!");
break;
}
fcntl(pout, F_SETPIPE_SZ, 1024); // small buffer to control latency
bool bFailed = false;
int nWait = 0;
while (s_bRun && !bFailed) {
struct pollfd pfd2[2];
memset(&pfd2, 0, sizeof(pfd2));
pfd2[0].fd = sock;
pfd2[0].events = POLLIN;
pfd2[1].fd = pout;
pfd2[1].events = POLLIN;
poll(pfd2, 2, 500);
if (pfd2[0].revents) {
char rcv;
if (recv(sock, &rcv, 1, 0)) {
}
}
if (pfd2[1].revents) {
int nRead = read(pout, buffer, sizeof(buffer));
if (nRead <= 0) {
break;
}
int nSent = 0;
while (nSent < nRead) {
int ret = send(sock, buffer + nSent, nRead - nSent, 0);
if ((ret < 0 && errno != EWOULDBLOCK) || !s_bRun) {
perror("camera relay send() failed");
bFailed = true;
break;
}
if (!nSent && ret == nRead) {
nWait = 0;
}
nSent += ret;
if (nSent < nRead) {
memset(&pfd, 0, sizeof(pfd));
pfd.fd = sock;
pfd.events = POLLOUT;
poll(&pfd, 1, 500);
nWait++;
if (nWait > 2) {
bFailed = true;
break;
}
}
}
}
}
if (pout > 0)
close(pout);
if (pin > 0)
close(pin);
if (pid > 0) {
printf("Killing raspivid child process %d with SIGKILL...\n", pid);
kill(pid, SIGINT);
sleep(1);
kill(pid, SIGKILL);
int status = 0;
printf("Waiting for process to end...\n");
waitpid(pid, &status, 0);
printf("Killed raspivid child process\n");
}
if (sock > 0)
close(sock);
}
}
}
bool Open() {
if (s_thread)
return false;
system("killall raspivid");
s_bRun = true;
s_thread = std::unique_ptr<std::thread>(new std::thread(RelayThread));
return true;
}
void Close() {
if (!s_thread)
return;
s_bRun = false;
s_thread->join();
}
};
#包括“CameraRelay.h”
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义读取0
#定义写入1
pid_t popen2(const char*命令,char*const args[],int*infp,int*outpp){
int p_stdin[2],p_stdout[2];
pid_t pid;
如果(管道(压力标准差)!=0 |管道(压力标准差)!=0)
返回-1;
pid=fork();
if(pid<0)
返回pid;
否则如果(pid==0)
{
关闭(p_stdin[WRITE]);
dup2(p_stdin[READ],READ);
关闭(p_stdout[READ]);
dup2(p_stdout[WRITE],WRITE);
execv(命令,args);
perror(“execl”);
出口(1);
}
if(infp==NULL)
关闭(p_stdin[WRITE]);
其他的
*infp=p_stdin[写入];
if(outpp==NULL)
关闭(p_stdout[READ]);
其他的
*outpp=p_stdout[READ];
返回pid;
}
名称空间摄影机{
静态std::唯一的_ptr s_线程;
静态std::mutex s_startStopMutex;
静态布尔斯布伦;
int s_listensock=-1;
void RelayThread(){
信号(信号管、信号灯);
s_listensock=套接字(自动网络、套接字流、IPPROTO\u TCP);
如果(s_listensock<0){
perror(“摄像头继电器插座()故障”);
返回;
}
int on=1;
setsockopt(s_listensock,SOL_SOCKET,SO_REUSEADDR,(char*)&on,sizeof(on));
ioctl(s_listensock,FIONBIO,(char*)和on);
unsigned int bufsz=1024;//用于控制延迟的小缓冲区
setsockopt(s_listensock,SOL_SOCKET,SO_SNDBUF,(void*)和bufsz,sizeof(bufsz));
sa中的结构sockaddr_;
memset((char*)&sa,0,sizeof(sa));
sa.sin_family=AF_INET;
sa.sin_addr.s_addr=htonl(INADDR_ANY);
sa.sin_港=htons(7124);
if(bind(s_listensock,(struct sockaddr*)和sa,sizeof(struct sockaddr))<0{
perror(“摄像机继电器的绑定()失败”);
返回;
}
bufsz=1024;//用于控制延迟的小缓冲区
setsockopt(s_listensock,SOL_SOCKET,SO_SNDBUF,(void*)和bufsz,sizeof(bufsz));
如果(听(s_listensock,1)){
perror(“摄像头继电器的侦听()失败”);
返回;
}
while(s_bRun){
萨卡德鲁;
memset((char*)&sa,0,sizeof(sa));
socklen_t len=sizeof(sa);
结构pollfd-pfd;
memset(&pfd,0,sizeof(pfd));
pfd.fd=s_列表锁;
pfd.events=POLLIN;
int ret=投票(和pfd,1500);
如果(ret>0){
int sock=accept(s_listensock,(struct sockaddr*)和sa,&len);
unsigned int bufsz=16384;//用于控制延迟的小缓冲区
setsockopt(sock,SOL_SOCKET,SO_SNDBUF,(void*)和bufsz,sizeof(bufsz));
fcntl(sock,F_SETFL,fcntl(sock,F_GETFL,0)| O_NONBLOCK);
printf(“摄像头继电器插座获得新连接。\n”);
字符缓冲区[512];
std::string cmd=“/usr/bin/raspivid”;
const char*args[]={/usr/bin/raspivid“,”o“,”n“,”s“,”t“,”0“,”fl“,”hf“,”b“,”5000000“,”w“,”1280“,”h“,”720“,”fps“,”25“,”nullptr};
int引脚=0;
int-pout=0;
pid_t pid=popen2(cmd.c_str(),const_cast(args),&pin,&pout);
如果(pid 0)
闭嘴;
如果(引脚>0)
关闭(pin);
如果(pid>0){
printf(“使用SIGKILL…\n”终止raspivid子进程%d),pid);
kill(pid,SIGINT);
睡眠(1);
kill(pid,SIGKILL);
int status=0;
printf(“等待进程结束…\n”);
waitpid(pid和status,0);
printf(“已终止的raspivid子进程\n”);
}
如果(sock>0)
关闭(袜子);
}
}
}
布尔公开赛{
if(s_螺纹)
返回false;
系统(“killall raspivid”);
s_bRun=正确;
s_thread=std::unique_ptr(新std::thread(RelayThread));
返回true;
}
无效关闭(){
如果(!s_螺纹)
返回;
s_bRun=fal
#include "CameraRelay.h"
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/select.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <thread>
#include <mutex>
#include <memory>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#define READ 0
#define WRITE 1
pid_t popen2(const char *command, char * const args[], int *infp, int *outfp) {
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execv(command, args);
perror("execl");
exit(1);
}
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
namespace CameraRelay {
static std::unique_ptr<std::thread> s_thread;
static std::mutex s_startStopMutex;
static bool s_bRun;
int s_listensock = -1;
void RelayThread() {
signal(SIGPIPE, SIG_IGN);
s_listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s_listensock < 0) {
perror("socket() for camera relay failed");
return;
}
int on = 1;
setsockopt(s_listensock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
ioctl(s_listensock, FIONBIO, (char *)&on);
unsigned int bufsz = 1024; // small buffer to control latency
setsockopt(s_listensock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsz, sizeof(bufsz));
struct sockaddr_in sa;
memset((char *)&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(7124);
if (bind(s_listensock, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0) {
perror("bind() for camera relay failed");
return;
}
bufsz = 1024; // small buffer to control latency
setsockopt(s_listensock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsz, sizeof(bufsz));
if (listen(s_listensock, 1)) {
perror("listen() for camera relay failed");
return;
}
while (s_bRun) {
sockaddr_in sa;
memset((char *)&sa, 0, sizeof(sa));
socklen_t len = sizeof(sa);
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = s_listensock;
pfd.events = POLLIN;
int ret = poll(&pfd, 1, 500);
if (ret > 0) {
int sock = accept(s_listensock, (struct sockaddr *)&sa, &len);
unsigned int bufsz = 16384; // small buffer to control latency
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsz, sizeof(bufsz));
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
printf("camera relay socket got new connection.\n");
char buffer[512];
std::string cmd = "/usr/bin/raspivid";
const char *args[] = { "/usr/bin/raspivid", "-o", "-", "-n" , "-s", "-t" ,"0", "-fl", "-hf", "-b", "5000000", "-w", "1280", "-h", "720", "-fps", "25", nullptr };
int pin = 0;
int pout = 0;
pid_t pid = popen2(cmd.c_str(), const_cast<char **>(args), &pin, &pout);
if (pid <= 0) {
perror("popen() failed!");
break;
}
fcntl(pout, F_SETPIPE_SZ, 1024); // small buffer to control latency
bool bFailed = false;
int nWait = 0;
while (s_bRun && !bFailed) {
struct pollfd pfd2[2];
memset(&pfd2, 0, sizeof(pfd2));
pfd2[0].fd = sock;
pfd2[0].events = POLLIN;
pfd2[1].fd = pout;
pfd2[1].events = POLLIN;
poll(pfd2, 2, 500);
if (pfd2[0].revents) {
char rcv;
if (recv(sock, &rcv, 1, 0)) {
}
}
if (pfd2[1].revents) {
int nRead = read(pout, buffer, sizeof(buffer));
if (nRead <= 0) {
break;
}
int nSent = 0;
while (nSent < nRead) {
int ret = send(sock, buffer + nSent, nRead - nSent, 0);
if ((ret < 0 && errno != EWOULDBLOCK) || !s_bRun) {
perror("camera relay send() failed");
bFailed = true;
break;
}
if (!nSent && ret == nRead) {
nWait = 0;
}
nSent += ret;
if (nSent < nRead) {
memset(&pfd, 0, sizeof(pfd));
pfd.fd = sock;
pfd.events = POLLOUT;
poll(&pfd, 1, 500);
nWait++;
if (nWait > 2) {
bFailed = true;
break;
}
}
}
}
}
if (pout > 0)
close(pout);
if (pin > 0)
close(pin);
if (pid > 0) {
printf("Killing raspivid child process %d with SIGKILL...\n", pid);
kill(pid, SIGINT);
sleep(1);
kill(pid, SIGKILL);
int status = 0;
printf("Waiting for process to end...\n");
waitpid(pid, &status, 0);
printf("Killed raspivid child process\n");
}
if (sock > 0)
close(sock);
}
}
}
bool Open() {
if (s_thread)
return false;
system("killall raspivid");
s_bRun = true;
s_thread = std::unique_ptr<std::thread>(new std::thread(RelayThread));
return true;
}
void Close() {
if (!s_thread)
return;
s_bRun = false;
s_thread->join();
}
};