c++ - 两个独立的进程共享相同的 Camera feed OpenCv

标签 c++ python opencv

我有两个独立的进程,它们同时使用 VideoCapture 来获取网络摄像头图像流。有没有办法让多个进程使用同一个VideoCapture(为了有效节省资源)?

我正在考虑使用 mmap 将当前图像从一个进程传输到另一个进程,但我认为有更好的方法。有谁知道如何在 Opencv 中与两个进程共享相同的视频提要?

此外,共享相同的视频捕获在计算上是否值得?或者有两个不断获取网络摄像头图像的进程在资源方面是否更好?

感谢您的任何建议。

最佳答案

第一个也是最好的选择是让第二个进程 Hook 并拦截第一个进程的图像。这是两个进程几乎同时访问图像的最快方式。当然,一个人总是先于另一个人拥有它。

如果您选择共享内存方式,那么以下可能对您有用:

共享内存.hpp:

#ifndef SHAREDMEMORY_HPP_INCLUDED
#define SHAREDMEMORY_HPP_INCLUDED

#if defined _WIN32 || defined _WIN64
    #include <windows.h>
#else
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <dlfcn.h>
    #include <fcntl.h>
    #include <unistd.h>
#endif

#include <tchar.h>
#include <iostream>
#include <map>

class SharedMemory
{
    private:
        void* FromFile;
        void* hFileMap;
        void* pData;
        std::string MapName;
        std::size_t Size;
        bool Debug;
        std::map<std::string, void*> Events;

    public:
        SharedMemory(std::string MapName);
        SharedMemory(std::string MapName, std::size_t Size);
        ~SharedMemory();

        SharedMemory(const SharedMemory& Shm) = delete;
        SharedMemory(SharedMemory && Shm) = delete;
        SharedMemory& operator = (const SharedMemory& Shm) = delete;
        SharedMemory& operator = (SharedMemory && Shm) = delete;

        void* GetDataPointer();

        bool OpenMemoryMap(std::size_t Size);

        bool MapMemory(std::size_t Size);

        bool ReleaseMemory();

        bool CreateNewEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, bool bManualReset, bool bInitialState, std::string EventName);

        std::uint32_t OpenSingleEvent(std::string EventName, bool InheritHandle, bool SaveHandle = false, std::uint32_t dwDesiredAccess = EVENT_ALL_ACCESS, std::uint32_t dwMilliseconds = INFINITE);

        bool SetEventSignal(std::string EventName, bool Signaled);

        bool DeleteSingleEvent(std::string EventName);

        bool DeleteAllEvents();

        void SetDebug(bool On);
};

#endif // SHAREDMEMORY_HPP_INCLUDED

共享内存.cpp:

#include "SharedMemory.hpp"

SharedMemory::SharedMemory(std::string MapName) : hFileMap(nullptr), pData(nullptr), MapName(MapName), Size(0), Debug(false), Events() {}
SharedMemory::SharedMemory(std::string MapName, std::size_t Size) : hFileMap(nullptr), pData(nullptr), MapName(MapName), Size(Size), Debug(false), Events() {}
SharedMemory::~SharedMemory()
{
    ReleaseMemory();
    DeleteAllEvents();
}

void* SharedMemory::GetDataPointer()
{
    void* Ptr = pData;
    return Ptr;
}

bool SharedMemory::OpenMemoryMap(std::size_t Size)
{
    this->Size = Size;

    #if defined _WIN32 || defined _WIN64
    if ((hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, MapName.c_str())) == nullptr)
    {
        if (Debug) std::cout << _T("\nCould Not Open Shared Memory Map.\n");
        return false;
    }

    if ((pData = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, Size)) == nullptr)
    {
        if (Debug) std::cout << _T("\nCould Not Map View Of File.\n");
        CloseHandle(hFileMap);
        return false;
    }

    #else

    if ((hFileMap = open(MapName.c_str(), O_RDWR | O_CREAT, 438)) == -1)
    {
        if (Debug) std::cout << _T("\nCould Not Open Shared Memory Map.\n");
        return false;
    }

    if ((pData = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, hFileMap, 0)) == MAP_FAILED)
    {
        if (Debug) std::cout << _T("\nCould Not Map View Of File.\n");
        close(hFileMap);
        return false;
    }
    #endif

    if (Debug) std::cout << _T("\nInter-Process Communication Successful.\n");
    return true;
}

bool SharedMemory::MapMemory(std::size_t Size)
{
    this->Size = Size;

    #if defined _WIN32 || defined _WIN64
    if ((hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, Size, MapName.c_str())) == nullptr)
    {
        if (Debug) std::cout << _T("\nCould Not Create Shared Memory Map.\n");
        return false;
    }

    if ((pData = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, Size)) == nullptr)
    {
        if (Debug) std::cout << _T("\nCould Not Map View Of File.\n");
        CloseHandle(hFileMap);
        return false;
    }

    #else

    if ((hFileMap = open(MapName.c_str(), O_RDWR | O_CREAT, 438)) == -1)
    {
        if (Debug) std::cout << _T("\nCould Not Create Shared Memory Map.\n");
        return false;
    }

    if ((pData = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, hFileMap, 0)) == MAP_FAILED)
    {
        if (Debug) std::cout << _T("\nCould Not Map View Of File.\n");
        close(hFileMap);
        return false;
    }
    #endif

    if (Debug) std::cout << _T("\nMapped Shared Memory Successfully.\n");
    return true;
}

bool SharedMemory::ReleaseMemory()
{
    bool Result = false;
    #if defined _WIN32 || defined _WIN64
    if (pData)
    {
        Result = UnmapViewOfFile(pData);
        pData = nullptr;
        if (Result && Debug)
        {
            std::cout << _T("\nMemory Un-Mapped Successfully.\n");
        }
    }

    if (hFileMap)
    {
        if (CloseHandle(hFileMap))
        {
            hFileMap = nullptr;
            Result = Result && true;
            if (Debug) std::cout << _T("\nMemory Map Closed Successfully.\n");
        }
    }

    #else

    if (pData)
    {
        Result = munmap(pData, Size);
        if (!Result && Debug)
        {
            std::cout << _T("\nMemory Un-Mapped Successfully.\n");
        }
        pData = nullptr;
        return true;
    }

    if (hFileMap)
    {
        if (!close(hFileMap))
        {
            hFileMap = nullptr;
            if (Debug) std::cout << _T("\nMemory Map Closed Successfully.\n");
        }
    }
    #endif
    return Result;
}

bool SharedMemory::CreateNewEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, bool bManualReset, bool bInitialState, std::string EventName)
{
    std::map<std::string, void*>::iterator it = Events.find(EventName);
    if (it != Events.end())
    {
        if (Debug)
        {
            std::cout << _T("\nCreateNewEvent Error: An Event With That Key Already Exists!\n");
        }
        return false;
    }

    Events.insert(std::pair<std::string, void*>(EventName, CreateEvent(lpEventAttributes, bManualReset, bInitialState, EventName.c_str())));
    it = Events.end();
    return ((--it)->second != nullptr);
}

std::uint32_t SharedMemory::OpenSingleEvent(std::string EventName, bool InheritHandle, bool SaveHandle, std::uint32_t dwDesiredAccess, std::uint32_t dwMilliseconds)
{
    void* hEvent = OpenEvent(dwDesiredAccess, InheritHandle, EventName.c_str());
    if (hEvent)
    {
        if (SaveHandle)
        {
            std::map<std::string, void*>::iterator it = Events.find(EventName);
            if (it != Events.end())
            {
                CloseHandle(it->second);
                it->second = hEvent;
            }
            else
                Events.insert(std::pair<std::string, void*>(EventName, hEvent));
        }
        std::uint32_t Result = WaitForSingleObject(hEvent, dwMilliseconds);
        if (!SaveHandle) CloseHandle(hEvent);
        return Result;
    }
    CloseHandle(hEvent);
    return WAIT_FAILED;
}

bool SharedMemory::SetEventSignal(std::string EventName, bool Signaled)
{
    std::map<std::string, void*>::iterator it = Events.find(EventName);
    if (it == Events.end())
    {
        if (Debug)
        {
            std::cout << _T("\nSetEventSignal Error: No Event With That Key Exists!\n");
        }
        return false;
    }
    if (Signaled) return SetEvent(it->second);
    return ResetEvent(it->second);
}

bool SharedMemory::DeleteSingleEvent(std::string EventName)
{
    std::map<std::string, void*>::iterator it = Events.find(EventName);
    if (it == Events.end()) return true;
    bool Result = CloseHandle(it->second);
    Events.erase(it);
    return Result;
}

bool SharedMemory::DeleteAllEvents()
{
    bool Result = false;
    for (std::map<std::string, void*>::iterator it = Events.begin(); it != Events.end(); ++it)
    {
        Result = Result && CloseHandle(it->second);
    }
    Events.clear();
    return Result;
}

void SharedMemory::SetDebug(bool On)
{
    Debug = On;
}

你可以像这样使用它:

第一道工序:

SharedMemory mem("OpenCVMap", 1980 * 1024 * 4); //Assuming max image size is 1980*1024*RGBA.
mem->CreateNewEvent(nullptr, true, false, "ImageReplySignal");

unsigned char* PtrToImagePixel = GetOpenCVCameraFeed();
unsigned char* MemPtr = static_cast<unsigned char*>(mem->GetDataPointer());
*reinterpret_cast<int*>(MemPtr) = GetOpenCVCameraFeedSize();
MemPtr += sizeof(int);

for (int i = 0; i < GetOpenCVCameraFeedSize(); ++i)
{
    *MemPtr += *PtrToImagePixels++;
} 
mem->SetEventSignal("ImageReplySignal", true);

第二过程:

SharedMemory mem("OpenCVMap");
mem->OpenMemoryMap(1980 * 1024 * 4);
std::vector<unsigned char> Image;

while(true)
{
    if (mem->OpenSingleEvent("ImageReplySignal", true, true) == WAIT_OBJECT_0)
    {
        unsigned char* MemPtr = static_cast<unsigned char*>(mem->GetDataPointer());
        int size = *(reinterpret_cast<int*>(MemPtr));
        MemPtr += sizeof(int);
        Image.resize(size);

        for (int i = 0; i < size; ++i)
        {
            Image[i] = *MemPtr++;
        }

        mem->SetEventSignal("ImageReplySignal", false);
    }
}

解释:

第一个过程: 第一个进程使用“OpenCVMap”作为标识符映射一个共享内存段。它还会创建一个带有标识符“ImageReplySignal”的事件,以便第二个进程可以知道何时读取。

收到图像后,它将图像大小作为整数写入共享内存区域。然后它继续将图像的内容写入内存区域。

完成写入后,它将事件设置为已发出信号。这样,第二个进程就会收到一个信号,告诉它可以读取了。

第二个过程: 第二个进程使用“OpenCVMap”作为标识符打开共享内存区域。在一个循环中,它不断检查是否使用标识符“ImageReplySignal”设置了信号。如果设置了事件,它会从内存区域读取大小。然后它继续从内存区域复制数据。

瞧,这两个进程现在共享这个图像。没有必要在第二个过程中将内存区域的图像复制出来。它可以简单地当场操纵它。

在不 Hook 第一个进程的情况下,这可能是让两个进程共享“完全”相同的图像/文件/视频/其他任何内容的最佳解决方案..

无论如何,在我真正提出更好的解决方案之前,最好先了解您的需求。

关于c++ - 两个独立的进程共享相同的 Camera feed OpenCv,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19614549/

相关文章:

c++ - 删除复制构造函数导致删除默认构造函数

c++ - WICConvertBitmapSource BGR 到 Gray 意外像素格式转换

python - 在for循环中从多个视频中提取帧

c++ - 在类中初始化 const 数组

c++ - 为什么不能 map::find 指向 const 的指针?

python - PyCharm,什么是 python_stubs?

python - next() 在 python 中的任何/全部都不能很好地发挥作用

python - 重新排序图像骨架坐标以使 interp1d 更好地工作

c++ - OpenCV 质量中心点

Python:检测黑色方 block