【问题标题】:Get background model from BackgroundSubtractorMOG2 in python从 python 中的 BackgroundSubtractorMOG2 获取背景模型
【发布时间】:2013-10-02 15:12:51
【问题描述】:

我需要使用 opencv 获取高斯混合的背景模型。我知道在 C++ 中有一个名为 getBackgroundImage 的方法,我搜索了是否可以在 python 接口中获取它,但我没有得到好的结果。我尝试了 opencv 3.0.0-dev,因为它具有 BackgroundSubtractorMOG2 实现,但 help() 函数没有记录背景模型的方法实现。你知道是否有未记录的实现吗?我搜索了如何编辑 opencv 源代码以实现 python 实现,但我还没有找到关于它的文档。我更喜欢避免使用 scipy.weave 来编译 c++ 代码,而且我不知道 scipy.weave 在这种情况下是否有用

【问题讨论】:

  • 我正在使用 opencv 3.0.0-dev 因为我已经阅读了您建议的链接...现在我正在尝试了解 opencv python 解析器的工作原理...否则如果没有其他解决方案,我认为我应该用 Python C API 编写 MOG2 的包装器
  • 也许这样的事情就足够了? bg = 0.99*bg+0.01*(frame& ~cv2.cvtColor(fg,cv2.COLOR_GRAY2BGR)); cv2.imshow('bg',bg/255)
  • MOG2 绑定已经在 opencv 3-dev 中可用。那你为什么要自己写呢?
  • @AbidRahmanK MOG2 在 opencv 3-dev 中的绑定没有我需要工作的 getBackgroundImage。

标签: python opencv mog


【解决方案1】:

改编Zaw Lin的解决方案

  • Ubuntu 18.04
  • OpenCV 3.2 通过apt install libopencv-dev 安装

主要区别在于结果 (fg / bg) 图像在 python 中创建/分配,然后传递给 c++ 库。 Zaw Lin 的解决方案给了我错误(errno 139 - SIG_SEGV),因为应用程序正在访问无效的内存区域。希望它可以为某人节省几个小时:)

mog2.cpp:

#include <opencv2/opencv.hpp>

cv::BackgroundSubtractorMOG2 *mog = cv::createBackgroundSubtractorMOG2 (500, 16, false);

extern "C" void getfg(int rows, int cols, unsigned char* imgData,
        unsigned char *fgD) {
    cv::Mat img(rows, cols, CV_8UC3, (void *) imgData);
    cv::Mat fg(rows, cols, CV_8UC1, fgD);
    mog->apply(img, fg);
}

extern "C" void getbg(int rows, int cols, unsigned char *bgD) {
    cv::Mat bg = cv::Mat(rows, cols, CV_8UC3, bgD);
    mog->getBackgroundImage(bg);
}

编译如下:

gcc  \
    -shared \
    -o libmog2.so  \
    -fPIC ./mog2.cpp  \
    -lopencv_core -lopencv_highgui -lopencv_objdetect -lopencv_imgproc -lopencv_features2d -lopencv_ml -lopencv_calib3d -lopencv_video

然后是python:

mog2.py

import numpy as np
import ctypes as C
import cv2

libmog = C.cdll.LoadLibrary('path/to/libmog2.so')

def getfg(img):
    (rows, cols) = (img.shape[0], img.shape[1])
    res = np.zeros(dtype=np.uint8, shape=(rows, cols))
    libmog.getfg(img.shape[0], img.shape[1],
                       img.ctypes.data_as(C.POINTER(C.c_ubyte)),
                       res.ctypes.data_as(C.POINTER(C.c_ubyte)))
    return res


def getbg(img):
    (rows, cols) = (img.shape[0], img.shape[1])
    res = np.zeros(dtype=np.uint8, shape=(rows, cols, 3))

    libmog.getbg(rows, cols, res.ctypes.data_as(C.POINTER(C.c_ubyte)))
    return res


if __name__ == '__main__':
    c = cv2.VideoCapture(0)
    while 1:
        _, f = c.read()
        cv2.imshow('f', f)
        cv2.imshow('fg', getfg(f))
        cv2.imshow('bg', getbg(f))
        if cv2.waitKey(1) == 27:
            exit(0)

【讨论】:

  • 谢谢,我用静态编译的 opencv 版本对其进行了测试。所以花了一些时间用共享库来测试它。
  • re Emanuel:更正了错误:getfg 中的 shape=(rows, cols, 1) 应该只有 shape=(rows,cols)。如果我将 res 包装(转换)为 SimpleCV Image(使用 Image(res)),则会导致错误。更新答案
  • @Matyas,我无法将 c++ 代码编译为 libmog2.so 文件。我不断收到错误“opencv2/opencv.hpp:没有这样的文件或目录”。我正在使用 Windows 10。我尝试添加 #include "C:/opencv2/opencv.hpp" 但没有运气。您能分享一下您是如何解决这个问题的吗?
  • 嘿@Vendetta,我已经重新检查了 Ubuntu18.04 上的编译;OpenCV3.2 更新了帖子,因此 C++ 编译工作。你有一个更普遍的问题,你安装的头文件没有找到/检测到,所以你应该研究如何在 Windows 中配置它。自从在 linux/ubuntu 上开箱即用以来,我还没有完成这些步骤。
【解决方案2】:

opencv 3.0

bgd=dict(history=20,nmixtures=20,backgroundRatio=0.5,noiseSigma=0)
fgbg=cv2.bgsegm.createBackgroundSubtractorMOG(**bgd)

【讨论】:

    【解决方案3】:

    这是一个使用 ctypes 的简单包装器,我只在 windows 上测试过

    cpp,构建为 dll

    #include "opencv2/opencv.hpp"
    cv::BackgroundSubtractorMOG2 mog(100, 16, false);
    
    cv::Mat bg;
    cv::Mat fg;
    extern "C" __declspec(dllexport)  unsigned char*  getfg(int rows,int cols, unsigned char* fdata)
    {
        cv::Mat frame= cv::Mat(rows, cols, CV_8UC3,fdata);
        mog(frame,fg);
        //check fg.iscont(), copy as needed
        return fg.data;
    }
    
    
    extern "C" __declspec(dllexport)   unsigned char*  getbg()
    {
        mog.getBackgroundImage(bg);
        return bg.data;
    }
    

    蟒蛇

    import cv2
    import numpy as np
    import ctypes as C
    lib = C.cdll.LoadLibrary('wrapper.dll')
    
    def getfg(img):
        ptr = lib.getfg(img.shape[0],img.shape[1],img.ctypes.data_as(C.POINTER(C.c_ubyte)))
    
        buf = (C.c_ubyte * img.shape[0] * img.shape[1]  * 1).from_address(ptr)
        res = np.ndarray(buffer=buf, dtype=np.uint8,
                           shape=(img.shape[0], img.shape[1], 1))
        return res
    
    def getbg(img):
        ptr = lib.getbg()
        buf = (C.c_ubyte * img.shape[0] * img.shape[1]  * 3).from_address(ptr)
        res = np.ndarray(buffer=buf, dtype=np.uint8,
                           shape=(img.shape[0], img.shape[1], 3))
        return res
    
    c = cv2.VideoCapture(0)
    while(1):
        _,f = c.read()
        cv2.imshow('f',f)
        cv2.imshow('fg',getfg(f))
        cv2.imshow('bg',getbg(f))
        if cv2.waitKey(1)==27:
            exit(0)    
    

    【讨论】:

    • 我在 Mac OS X 上,我删除了 __declspec(ddlexport) 并创建了一个 dylib。 ctypes 有效,但我在 getfg(f) 的 imshow 上遇到分段错误
    • 我要花点时间才能接触到 mac,而且我不熟悉 mac 编程,但我在 ubuntu 上尝试过,它工作正常。你能在 ubuntu 上试试吗,如果你还有问题,我可以更新更多细节
    • 我用 Python C API 编写了一个包装器,但你是最好的解决方案。我会尝试强制它在我的系统上工作:)
    • 删除 __declspec(dllexport) 使其可在 Ubuntu 上编译(与所有添加了 -l 的 opencv 库共享库)。虽然我的问题是我无法从返回的地址加载图像。 np.ndarray(buffer=buf[...] 行因 SIG_SEGV(分段错误)而失败。有什么想法吗?
    • @ZawLin,我现在确实在 Windows 上尝试了很长时间来构建 wrapper.dll 文件。它只是不工作。我安装了 opencv 并尝试使用此命令进行编译 gcc -o fgbg.dll mog2.cpp -I C:/opencv3.4.10/opencv/build/include -I C:/opencv3.4.10/opencv/build/include/opencv2 -L C:/opencv3.4.10/opencv/build/x64/vc14/lib 它给了我这样的错误 ` undefined reference to cv::String::allocate(unsigned int)' c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: 你能解释一下如何构建 wrapper.dll 吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    • 1970-01-01
    • 2015-06-11
    相关资源
    最近更新 更多