共享同一个Camera feed OpenCv的两个独立进程 [英] Two separate processes sharing the same Camera feed OpenCv

查看:123
本文介绍了共享同一个Camera feed OpenCv的两个独立进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个单独的过程,它们同时使用VideoCapture获取网络摄像头图像流.有没有一种方法可以将同一VideoCapture用于多个进程(以便有效地节省资源)?

I have two separate processes that use a VideoCapture at the same time to get a webcam stream of images. Is there a way to use the same VideoCapture for multiple processes (in order to effectively save resources)?

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

I was considering using a mmap to transfer the current image from one process to another but I figure that there is a better way. Does anyone know how to share the same video feed with two processes in Opencv?

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

Also, would sharing the same video capture be computationally worth it? Or is having two processes that constantly get the webcam image be better in terms of resources?

谢谢您的任何建议.

推荐答案

第一个也是最好的选择是让第二个进程挂接并拦截第一个进程的映像.这是两个进程几乎同时访问映像的最快方法.当然,一个总是比另一个更先拥有它.

The first and best option is to have the second process hook and intercept the image of the first process. This is the fastest way for both processes to have access to the image at nearly the same time. Of course one will always have it before the other.

如果您选择执行共享内存方式,则可能对您有用:

If you choose to do the sharememory way, then the following MIGHT be of use to you:

SharedMemory.hpp:

SharedMemory.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

SharedMemory.cpp:

SharedMemory.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"的事件,以便第二个进程知道何时读取.

First Process: First process maps a shared memory segment using "OpenCVMap" as an identifier. It also creates an event with the identifier "ImageReplySignal" so that the second process can know when to read.

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

Upon receiving an image, it writes the image size to the shared memory region as an integer. Then it proceeds to write the contents of the image to the memory region.

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

When it is finished writing, it sets the event to signaled. This way, the second process receives a signal telling it that it is ok to read.

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

Second Process: Second process opens the shared memory region using "OpenCVMap" as the identifier. In a loop, it constant checks if the signal is set using the identifier "ImageReplySignal". If the event is set, it reads the size from the memory region. It then proceeds to copy the data from the memory region.

Voila现在两个进程都共享此图像.在第二过程中,不必复制存储区域的图像.它可以简单地在那之后进行操作.

Voila both processes now share this image. It is NOT necessary to copy the image OUT of the memory region in the second process. It can simply just manipulate it then and there.

不使用第一个进程,这可能是使两个进程共享完全"相同的图像/文件/视频/其他东西的最佳解决方案.

Without hooking the first process, this is probably the best solution to get BOTH processes to share the "EXACT" same image/file/video/whatever else..

无论如何,最好在我真正提出更好的解决方案之前,先提出一个想要的想法.

Anyway, it'd be best to give an idea of what you want before I can truly suggest a better solution..

这篇关于共享同一个Camera feed OpenCv的两个独立进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆