代码之家  ›  专栏  ›  技术社区  ›  Hossein

为什么只有在python模块使用cv.imshow()时才执行C回调?

  •  1
  • Hossein  · 技术社区  · 6 年前

    我想不出一个更好的更描述性的标题,因为它涉及3种语言,我现在解释。
    我写了一封信 C++ 围绕Python模块的包装器,它在C++中的工作方式很好。我用这个包装器制作了一个动态链接库,将一些功能公开为C,并在C应用程序中使用它们。

    C# 如果我不显示网络摄像头,应用程序就会挂起。
    Python

    if self.debug_show_feed:
        cv2.imshow('service core face Capture', frame)
    

    当设置时 True ,将显示网络摄像头源。
    这主要是一个调试的东西,我把它和实际生产需要被禁用。在C++上很好 我可以把这个设定为 false (通过建造商)一切正常。
    然而,在 ,如果我尝试使用模块而不将网络摄像头提要设置为 true ,的 C级# Start() 主操作将成为阻塞调用,并且不返回任何回调。
    我的 DllImport 顺便说一下如下:

    [DllImport(@"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int Initialize(bool showFeed);
    
    [DllImport(@"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void Start(bool async);
    
    [DllImport(@"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void Stop();
    
    [DllImport(@"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void SetCpuAffinity(int mask);
    
    
    
    public delegate void CallbackDelegate(bool status, string message);
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    
    [DllImport(@"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void AddCallback(IntPtr fn);
    
    [DllImport(@"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void RemoveCallback(IntPtr fn);
    
    

    这是我的回电:

    private CallbackDelegate del;
    public void SetUpCallback()
    {
        txtLog.Text += "Registering C# callback...\r\n";
        del = new CallbackDelegate(callback01);
        AddCallback(Marshal.GetFunctionPointerForDelegate(del));
        txtLog.Text += "Calling passed C++ callback...\r\n";
    }
    
    bool status;
    string id;
    public void callback01(bool status, string id)
    {
         this.status = status;
         this.id = id;
    }
    

    这是执行的主要python模块:

    def start(self):
        try:
            self.is_running = True
            self._main_loop()
    
        except Exception as ex:
            path='exceptions-servicecore.log'
            track = traceback.format_exc()
            exception_time = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
            with open(path, 'a') as f:
                f.writelines(f'\n{exception_time} : exception occured {ex.args} \n{track}')
    
    def start_async(self):
        st = threading.Thread(target=self.start) 
        st.start()
    
    def _main_loop(self):
    
        name = None
        is_valid = False
        while self.is_running and self.cap.isOpened():
            is_success, frame = self.cap.read()
            if is_success:
                name="sth"
                is_valid=True
    
                self._execute_callbacks(is_valid, name, frame)
                self._execute_c_callbacks(is_valid, name)
    
                if self.debug_show_feed:
                    cv2.imshow('service core face Capture', frame)
    
            if self.save:
                self.video_writer.write(frame)
    
            if (cv2.waitKey(1)&0xFF == ord('q')) or (not self.is_running):
                break
    
        self.cap.release()
        if self.save:
            self.video_writer.release()
        cv2.destroyAllWindows()    
    
    

    C级# 而不是 C++ ,我可能在封送或使用 C级# 此场景中的回调。

    下面是一个Visual Studio,其中有一个简单的示例来演示这一点: https://workupload.com/file/epsgzmMMVMY

    这里有什么问题?为什么是 cv.imshow()

    0 回复  |  直到 6 年前
        1
  •  0
  •   halfer Jatin Pandey    6 年前

    我找到了C端回调没有输出任何内容的原因。回调都按其应该的方式执行,但是由于Python端的主循环是一个阻塞方法,因此它们只在阻塞方法结束时才开始执行(就像递归函数一样,直到最后才返回输出)。

    然后我注意到 cv2.imshow() 创造一个短暂的停顿,在这段时间里 C# 客户机有机会更新输出及其发送到的对象。我第一次尝试在Python中暂停当前正在运行的线程,它实际上起到了某种作用,输出开始在C端弹出,但应用程序仍然没有响应。

    我注意到我实际上可以通过使用 cv2.waitkey(1) 或 cv2.imread('') 在else子句中 showFeed 为假:

    while (self.is_running):
    ...
        if self.showFeed:
            cv2.imshow("image", frame)
        else:
            #cv2.imread('')
            # or 
            cv2.waitkey(1)
        ...
    

    然后写下:

    while (self.is_running):
    ...
        if self.showFeed:
            cv2.imshow("image", frame)
        else:
            cv2.namedWindow('image', cv2.WINDOW_OPENGL)
            cv2.waitKey(1)
            cv2.destroyAllWindows()
        ...
    

    我需要补充一点,在c上使用timer()控件事件来打印输出并保持应用程序的响应性是行不通的,创建一个新线程似乎也行不通。似乎这种封送回调不能这样使用(我很高兴听到我错了)。

    当我找到比这两个更好的解决方案时,我会更新这个答案:C(在线程上运行回调)或Python端,创建一个可见窗口或完全解决这个问题。

    更新

    我删除了Python端的更改,并在C部分实现了线程。初始线程不起作用的原因是,所有互操作都必须在同一个线程中调用,这意味着所有导入的方法,例如 Initialize Start 和 AddCallback 必须在同一线程中设置和运行。

    推荐文章