gpt4 book ai didi

c++ - 如何跨平台在 C++ 的单独 posix 线程中运行 OpenCV Videocapture?

转载 作者:太空狗 更新时间:2023-10-29 12:13:11 26 4
gpt4 key购买 nike

在我的代码中,我想在一个单独的pthread 中连续运行一个Videocapture,而主线程将作为一个socket server与任何客户沟通(反之亦然)。

client连接到server时,server会立即发送最新的Videocapture帧给客户端并关闭连接并再次等待另一个连接。

我目前在 mingw32 环境中使用 OpenCV 2.3.0

StackOverflow 上查看了一些可能的解决方案后,我尝试按照它们进行操作,但是,我可以将 OpenCV 变量 放置在本地全局交换线程,即将Videocapture线程保持在主线程第二线程中>,当客户端连接时,程序只是静静地卡在 VideoCapture 线程的 mutex locked area 处。

我想当 server 线程在连接到客户端后开始锁定 mutex 时会发生这种情况。

任何推理可能的解决方案将不胜感激。另外,我使用的是 prebuilt OpenCV 2.3.0 版,我需要代码是跨平台的。无论如何,如果它指向一个错误,我显然可以切换到其他版本。


服务器代码

mynet.h

#ifndef __MYNET__
#define __MYNET__
#ifdef _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501 /* Windows XP. */
#endif
#include <winsock2.h>
#include <Ws2tcpip.h>
#else
/* Assume that any non-Windows platform uses POSIX-style sockets instead. */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */
#include <unistd.h> /* Needed for close() */
#endif

int sockInit(void)
{
#ifdef _WIN32
WSADATA wsa_data;
return WSAStartup(MAKEWORD(1,1), &wsa_data);
#else
return 0;
#endif
}

int sockQuit(void)
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}

/* Note: For POSIX, typedef SOCKET as an int. */
#ifndef _WIN32
typedef int SOCKET;
#else
typedef unsigned int SOCKET;
#endif

int sockClose(SOCKET sock)
{
int status = 0;
#ifdef _WIN32
status = shutdown(sock, SD_BOTH);
if (status == 0) { status = closesocket(sock); }
#else
status = shutdown(sock, SHUT_RDWR);
if (status == 0) { status = close(sock); }
#endif
return status;
}


#if(defined(_WIN32) || defined(WIN32))
#include <windows.h>
#define mysleep(x) Sleep((x))
#else
#include <unistd.h>
#define mysleep(x) usleep((x)*1000)
#endif

#endif

netserver.cpp

#define _GLIBCXX_USE_CXX11_ABI 0
#undef _GLIBCXX_DEBUG
#include "../mynet.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <pthread.h>

using namespace cv;
Mat frame(120, 160, CV_8UC3);;
pthread_mutex_t mutex;
pthread_t thread;

void *myfunc(void *threadid)
{
int n;
int listenfd = 0,connfd = 0;
struct sockaddr_in serv_addr;
unsigned char sendBuff[160*120*3];
Mat hereframe;

listenfd = socket(AF_INET, SOCK_STREAM, 0);
printf("socket retrieve success\n");

memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(listen(listenfd, 10) == -1)
{
printf("Failed to listen\n");
}
else
{
connfd = accept(listenfd, (struct sockaddr*)NULL,NULL); // accept awaiting request
if(connfd<=0) printf("Something went wrong with write()! %s\n", strerror(errno));
else
{
while(1)
{
printf("Got client...\n");
pthread_mutex_lock (&mutex);
printf("Copying data...\n");
frame.copyTo(hereframe);
pthread_mutex_unlock (&mutex);
printf("Hereframe size: %dX%d\n", hereframe.rows, hereframe.cols);
memcpy(sendBuff, hereframe.data, 120*160*3);
printf("Sending data...\n");
n = send(connfd, (char*)sendBuff, 120*160*3,0);
if(n<0) printf("Something went wrong with write()! %s\n", strerror(errno));
printf("Closing client after writing %d bytes...\n", n);
printf("Closed...\n");
mysleep(40);
printf("Restartng data...\n");
}
sockClose(connfd);
}
}
sockQuit();

pthread_exit(NULL);
}

int main(void)
{
//cvNamedWindow("Sisplay", CV_WINDOW_AUTOSIZE);
sockInit();
pthread_mutex_init(&mutex,NULL);
VideoCapture cap;
Mat hereframe1;
cap.open(0);
cap.set( CV_CAP_PROP_FRAME_WIDTH, 160 );
cap.set( CV_CAP_PROP_FRAME_HEIGHT, 120 );

if( !cap.isOpened()) printf("Fukced up\n");
int rc;
long t;
rc = pthread_create(&thread, NULL, myfunc, (void *)t);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}

for(;;)
{
cap >> hereframe1;
// printf("Video size: %dX%d\n", hereframe1.rows, hereframe1.cols);

pthread_mutex_lock(&mutex);
hereframe1.copyTo(frame); /* hangs here*/
pthread_mutex_unlock(&mutex);
// cvtColor(frame, gray, CV_BGR2GRAY);

Scalar tempVal = mean(hereframe1);
// printf("Mean = %f\n", tempVal.val[0]);
mysleep(30);
//if(waitKey(30)=='q') break;
// std::swap(prevgray, gray);
}
char *b;
pthread_join(thread,(void**)&b);
return 0;
}

客户端代码

receiver.cpp

#define _GLIBCXX_USE_CXX11_ABI 0
#include "../mynet.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>

using namespace cv;

int main(int argc, char *argv[])
{
int sockfd = 0,n = 0;
unsigned char recvBuff[120*160*3];
struct sockaddr_in serv_addr;
sockInit();
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);

if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
printf("Connected to server...\n");
Mat frame(120, 160, CV_8UC3);
int csz = 0;
cvNamedWindow("Display", CV_WINDOW_AUTOSIZE);
printf("OK here 0\n");
for(;;)
{
csz = 0;
while((n = recv(sockfd, (char*)recvBuff, sizeof(recvBuff), 0)) > 0)
{
printf("OK here 2\n");

printf("Read %d bytes...\n", n);
csz += n;
if(csz<=120*160*3)
{
memcpy(frame.data+(csz-n), recvBuff, n);
}
if(csz>= 120*160*3) break;
}
printf("OK here 3\n");

printf("Got data of size %d bytes...\n", csz);
imshow("Display", frame);
if(csz < 120*160*3)
{
printf("\n Read Error \n");
}
if(waitKey(30)=='q') break;
// std::swap(prevgray, gray);
}
sockClose(sockfd);

sockQuit();
return 0;
}

最佳答案

我认为 OpenCV 2.3.0 函数不是线程安全的。例如Mat::clone()、Mat::copyTo 等函数(需要说明)。

所以,不是在互斥锁定区域OpenCV变量中使用那些OpenCV函数作为一个整体在多个线程中共享,我只是使用基本的 C++ 函数和原始缓冲区。

互斥锁定区域中使用OpenCV函数,将OpenCV变量作为一个整体在多个线程中共享,看起来一点都不友好。

所以,我在服务器线程中做了一个更改

pthread_mutex_lock (&mutex);
//printf("Copying data...\n");
memcpy(sendBuff, frame.data, 120*160*3);
//frame.copyTo(hereframe); buggy here removed
pthread_mutex_unlock (&mutex);

现在它按预期工作。呃!现在,我需要清理代码中的所有困惑。

其实我也会把OpenCV的frame变量替换成一个简单的unsigned char缓冲区来分享。

关于c++ - 如何跨平台在 C++ 的单独 posix 线程中运行 OpenCV Videocapture?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34469844/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com