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

标签 c++ linux opencv pthreads mingw32

在我的代码中,我想在单独的pthread中连续运行Videocapture,而主线程将充当套接字服务器与任何客户沟通(反之亦然)。

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

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

在 StackOverflow 上查看了一些可能的解决方案后,我尝试遵循它们,但是,我可以将 OpenCV 变量 放置在 本地全局交换线程,即将Videocapture线程保留在主线程中或第二个线程中>,当客户端连接时,程序只是静静地卡在 VideoCapture 线程的互斥锁定区域

我认为当服务器线程在连接到客户端后开始锁定互斥体时就会发生这种情况。

任何推理可能的解决方案都将受到高度赞赏。另外,我正在使用预构建 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;
}

客户端代码

接收器.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 functionsmutex locked regionsOpenCV variables作为一个在多个线程中共享的整体,我只使用基本的 C++ 函数和原始缓冲区。

使用OpenCV functionsmutex locked regionsOpenCV variables作为一个整体在多个线程中共享似乎一点也不友好。

所以,我对服务器线程进行了更改

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/

相关文章:

c++ - 是否有更有效的方法来检查元素是否在给定区间内?

python - 来自opencv矩形的奇怪错误

c++ - 带有用 C 编写的库的智能指针

c++ - 使此 C++ 代码通用

c++ - 构建项目的 Eclipse CDT 问题

linux - 在 Linux i686 上使用 sqlite-3.7.6.3 出现编译错误

java - 无法使用 Java 运行 linux 命令

python - 如何改善圆检测

c++ - vector.back() 的意外值

mysql - 比较同一组字符的加密值