我有两个独立的进程,它们同时使用 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/
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我有一个在Linux服务器上运行的ruby脚本。它不使用rails或任何东西。它基本上是一个命令行ruby脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
让多条路线去同一条路的最优雅的方式是什么ControllerAction?我有:get'dashboard',to:'dashboard#index'get'dashboard/pending',to:'dashboard#index'get'dashboard/live',to:'dashboard#index'get'dashboard/sold',to:'dashboard#index'这很丑陋。有什么“更优雅”的建议吗?一个类轮的奖励积分。 最佳答案 为什么不只有一个路由和一个Controller操作,并根据传递给它的参数来