鱼C论坛

 找回密码
 立即注册

基于OpenCV的ViBe算法,下午写的,但愿不太糟糕

热度 1已有 1230 次阅读2014-7-15 21:12 |个人分类:鱼C日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <opencv2/opencv.hpp>
using namespace cv;
 
const int sam_frames = 20;
const int min_match = 2;
const int radius = 20;
const int sub_sam = 16;
 
class ViBe
{
    Mat _samples[sam_frames];
    Mat _fg_match;
    Mat m_mask;
    RNG rand_gen;
public:
    ViBe(const Mat& img)
    {
        for (int i = 0; i < sam_frames; ++i)
            _samples[i] = Mat::zeros(img.size(), CV_8UC1);
        m_mask    = Mat::zeros(img.size(), CV_8UC1);
        _fg_match = Mat::zeros(img.size(), CV_8UC1);
        _proc_first(img);
    }
 
    void update(const Mat& img)
    {
        for (int i = 0; i < img.rows; ++i)
        {
            for (int j = 0; j < img.cols; ++j)
            {
                int matches(0), count(0);
                int dist;
 
                while (matches < min_match && count < sam_frames)
                {
                    dist = abs(_samples[count].at<uchar>(i, j) - img.at<uchar>(i, j));
                    if (dist < radius) ++matches;
                    ++count;
                }
 
                if (matches >= min_match)
                {
                    _samples[sam_frames].at<uchar>(i, j) = 0;
                    m_mask.at<uchar>(i, j) = 0;
 
                    int random = rand_gen.uniform(0, sub_sam);
                    if (!random)
                    {
                        random = rand_gen.uniform(0, sam_frames);
                        _samples[random].at<uchar>(i, j) = img.at<uchar>(i, j);
                    }
                    if (!random)
                    {
                        int row, col;
                        row = i + rand_gen.uniform(-1, 1);
                        col = j + rand_gen.uniform(-1, 1);
                        if (row < 0) row = 0;
                        if (row >= img.rows) --row;
                        if (col < 0) col = 0;
                        if (col >= img.cols) --col;
 
                        random = rand_gen.uniform(0, sam_frames);
                        _samples[random].at<uchar>(i, j) = img.at<uchar>(i, j);
                    }
                }
                else
                {
                    _fg_match.at<uchar>(i, j)++;
                    m_mask.at<uchar>(i, j) = 255;
 
                    if (_fg_match.at<uchar>(i, j) > 50)
                    {
                        int random = rand_gen.uniform(0, sam_frames);
                        if (random == 0)
                        {
                            random = rand_gen.uniform(0, sam_frames);
                            _samples[random].at<uchar>(i, j) = img.at<uchar>(i, j);
                        }
                    }
                }
            }
        }
    }
 
    void process(const Mat & img_input, Mat & img_output)
    {
        if (img_input.empty())
            return;
 
        if (img_input.channels() == 3)
        {
            Mat gray, filtered_input_image;
            cvtColor(img_input, gray, CV_BGR2GRAY);
            GaussianBlur(gray, filtered_input_image, Size(5,5), 1.5);
            update(filtered_input_image);
            Mat mask = getMask();
            // median filtering
            medianBlur(mask, mask, 5);
 
            // find blobs
            std::vector<std::vector<Point> > v;
            std::vector<Vec4i> hierarchy;
            findContours(mask, v, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
            mask = Scalar(0, 0, 0);
            for (size_t i=0; i < v.size(); ++i)
            {
                // drop smaller blobs
                if (contourArea(v[i]) < 20)
                    continue;
                // draw filled blob
                drawContours(mask, v, i, Scalar(255,0,0), CV_FILLED, 8, hierarchy, 0, Point()); 
            }
 
            // morphological closure
            Mat element = getStructuringElement(MORPH_RECT, Size(7, 7));
            morphologyEx(mask, mask, MORPH_CLOSE, element);
 
            mask.copyTo(img_output);
        }
    }
 
    Mat & getMask()
    {
        return m_mask;
    }
private:
    void _proc_first(const Mat& img)
    {
        int row, col;
 
        for (int i = 0; i < img.rows; ++i)
        {
            for (int j = 0; j < img.cols; ++j)
            {
                for (int k = 0; k < sam_frames; ++k)
                {
                    row = i + rand_gen.uniform(-1, 1);
                    col = j + rand_gen.uniform(-1, 1);
                    if (row < 0) row = 0;
                    if (row >= img.rows) --row;
                    if (col < 0) col = 0;
                    if (col >= img.cols) --col;
 
                    _samples[k].at<uchar>(i, j) = img.at<uchar>(row, col);
                }
            }
        }
    }
};
 
int main()
{
    Mat frame, mask;
    VideoCapture capture(0);
    if (!capture.isOpened())
    {
        std::cout << "No camera!" << std::endl;
        return -1;
    }
 
    capture >> frame;
    ViBe bgs(frame);
    std::cout << "ViBe instantiated." << std::endl;
    while (capture.isOpened())
    {
        capture >> frame;
        if (frame.empty())
            break;
        bgs.process(frame, mask);
        imshow("mask", mask);
        imshow("input", frame); 
        if (waitKey(10) == 27)
            break;
    }
}

路过

雷人
1

握手

鲜花

鸡蛋

刚表态过的朋友 (1 人)

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-13 05:57

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部