Skip to content

Commit c587474

Browse files
committed
changed 15-02, created 15-03
1 parent 68f6043 commit c587474

File tree

3 files changed

+235
-16
lines changed

3 files changed

+235
-16
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ add_executable( example_14-03 example_14-03.cpp )
4848
add_executable( example_14-04 example_14-04.cpp )
4949
add_executable( example_15-01 example_15-01.cpp )
5050
add_executable( example_15-02 example_15-02.cpp )
51+
add_executable( example_15-03 example_15-03.cpp )
5152
add_executable( example_15-04 example_15-04.cpp )
5253
#...
5354
add_executable( example_16-01 example_16-01.cpp )
@@ -94,6 +95,7 @@ target_link_libraries( example_14-03 ${OpenCV_LIBS} )
9495
target_link_libraries( example_14-04 ${OpenCV_LIBS} )
9596
target_link_libraries( example_15-01 ${OpenCV_LIBS} )
9697
target_link_libraries( example_15-02 ${OpenCV_LIBS} )
98+
target_link_libraries( example_15-03 ${OpenCV_LIBS} )
9799
target_link_libraries( example_15-04 ${OpenCV_LIBS} )
98100
#...
99101
target_link_libraries( example_16-01 ${OpenCV_LIBS} )

example_15-02.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ cv::Mat Imaskt;
2626

2727
// Thresholds
2828
//
29-
float high_thresh = 15.0; //scaling the thesholds in backgroundDiff()
30-
float low_thresh = 13.0;
29+
float high_thresh = 20.0; //scaling the thesholds in backgroundDiff()
30+
float low_thresh = 28.0;
3131

3232
// Counts number of images learned for averaging later
3333
//
@@ -134,6 +134,7 @@ void showForgroundInRed( char** argv, const cv::Mat &img) {
134134
Igray[2] = cv::max( mask, Igray[2] );
135135
cv::merge( Igray, rawImage );
136136
cv::imshow( argv[0], rawImage );
137+
cv::imshow("Segmentation", mask);
137138
}
138139

139140
void adjustThresholds(char** argv, cv::Mat &img) {
@@ -189,11 +190,13 @@ int main( int argc, char** argv) {
189190

190191
// SECOND PROCESSING LOOP (TESTING):
191192
//
193+
cv::namedWindow("Segmentation", cv::WINDOW_AUTOSIZE ); //For the mask image
192194
while((key = cv::waitKey()) != 27 || key == 'q' || key == 'Q' ) { // esc, 'q' or 'Q' to exit
193195
cap >> image;
194196
if( !image.data ) exit(0);
195197
cout << frame_count++ << endl;
196198
backgroundDiff( image, mask );
199+
cv::imshow("Segmentation", mask);
197200

198201
// A simple visualization is to write to the red channel
199202
//

example_15-03.cpp

Lines changed: 228 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
//Example 15-3. Computing the on and off-diagonal elements of a variance/covariance model
2+
#include <opencv2/opencv.hpp>
3+
#include <vector>
4+
#include <iostream>
5+
#include <cstdlib>
6+
#include <fstream>
7+
8+
using namespace std;
29

310
vector<cv::Mat> planes(3);
411
vector<cv::Mat> sums(3);
512
vector<cv::Mat> xysums(6);
13+
cv::Mat sum, sqsum;
614
int image_count = 0;
715

816
//A function to accumulate
917
// the information we need for our variance computation:
18+
//
1019
void accumulateVariance(
11-
cv::Mat& I
12-
) {
13-
if( sum.empty ) {
20+
cv::Mat& I) {
21+
if( sum.empty() ) {
1422
sum = cv::Mat::zeros( I.size(), CV_32FC(I.channels()) );
1523
sqsum = cv::Mat::zeros( I.size(), CV_32FC(I.channels()) );
24+
image_count = 0;
1625
}
1726
cv::accumulate( I, sum );
1827
cv::accumulateSquare( I, sqsum );
@@ -23,29 +32,43 @@ void accumulateVariance(
2332
// (note that 'variance' is sigma^2)
2433
//
2534
void computeVariance(
26-
cv::Mat& variance
27-
) {
35+
cv::Mat& variance) {
2836
double one_by_N = 1.0 / image_count;
29-
variance = one_by_N * sqsum – (one_by_N * one_by_N) * sum.mul(sum);
37+
variance = (one_by_N * sqsum) - ((one_by_N * one_by_N) * sum.mul(sum));
3038
}
3139

40+
//Same as above function, but compute standard deviation
41+
void computeStdev(
42+
cv::Mat& std__) {
43+
double one_by_N = 1.0 / image_count;
44+
cv::sqrt(((one_by_N * sqsum) -((one_by_N * one_by_N) * sum.mul(sum))), std__);
45+
}
3246

47+
//And avg images
48+
void computeAvg(
49+
cv::Mat& av) {
50+
double one_by_N = 1.0 / image_count;
51+
av = one_by_N * sum;
52+
}
53+
54+
// ===================================================================//
3355

3456

3557
void accumulateCovariance(
3658
cv::Mat& I
3759
) {
3860
int i, j, n;
3961

40-
if( sum.empty ) {
62+
if( sum.empty() ) {
63+
image_count = 0;
4164
for( i=0; i<3; i++ ) {
4265
// the r, g, and b sums
4366
sums[i]
44-
= cv::Mat::zeros( I.size(), CV::F32C1 );
67+
= cv::Mat::zeros( I.size(), CV_32FC1 );
4568
}
4669
for( n=0; n<6; n++ ) {
4770
// the rr, rg, rb, gg, gb, and bb elements
48-
xysums[n] = cv::Mat::zeros( I.size(), CV::F32C1 ) );
71+
xysums[n] = cv::Mat::zeros( I.size(), CV_32FC1 );
4972
}
5073
}
5174
cv::split( I, planes );
@@ -64,11 +87,11 @@ cv::Mat& I
6487
image_count++;
6588
}
6689

67-
//The corresponding compute function is also just a slight extension of the compute
68-
//function for the variances we saw earlier.
90+
//The corresponding compute function is also just a slight extension of
91+
//the compute function for the variances we saw earlier.
6992
// note that 'variance' is sigma^2
7093
//
71-
void computeVariance(
94+
void computeCoariance(
7295
cv::Mat& covariance
7396
// a six-channel array, channels are the
7497
// rr, rg, rb, gg, gb, and bb elements of Sigma_xy
@@ -83,12 +106,203 @@ void computeVariance(
83106
for( int j=i; j<3; j++ ) {
84107
// "column" of Sigma
85108
n++;
86-
xysums[n] = one_by_N * xysums[n]
87-
– (one_by_N * one_by_N) * sums[i].mul(sums[j]);
109+
xysums[n] = (one_by_N * xysums[n])
110+
- ((one_by_N * one_by_N) * sums[i].mul(sums[j]));
88111
}
89112
}
90113

91114
// reassemble the six individual elements into a six-channel array
92115
//
93116
cv::merge( xysums, covariance );
94117
}
118+
119+
////////////////////////////////////////////////////////////////////////
120+
/////////////Utilities to run///////////////////////////////////////////
121+
122+
void help(char** argv ) {
123+
cout << "\n"
124+
<< "Compute mean and std on <#frames to train on> frames of an incoming video, then run the model\n"
125+
<< argv[0] <<" <#frames to train on> <avi_path/filename>\n"
126+
<< "For example:\n"
127+
<< argv[0] << " 50 ../tree.avi\n"
128+
<< "'a' to adjust thresholds, esc, 'q' or 'Q' to quit"
129+
<< endl;
130+
}
131+
132+
////////////// Borrowed code from example_15-02 //////////////////////
133+
134+
// Global storage
135+
//
136+
// Float, 3-channel images
137+
//
138+
cv::Mat image; // movie frame
139+
cv::Mat IavgF, IdiffF, IhiF, IlowF; //threshold
140+
cv::Mat tmp, mask; //scratch and our mask
141+
142+
// Float, 1-channel images
143+
//
144+
vector<cv::Mat> Igray(3); //scratch to split image
145+
vector<cv::Mat> Ilow(3);//low per pixel thresh
146+
vector<cv::Mat> Ihi(3); //high per pixel thresh
147+
148+
// Byte, 1-channel image
149+
//
150+
cv::Mat Imaskt; //Temp mask
151+
152+
// Thresholds
153+
//
154+
float high_thresh = 21.0; //scaling the thesholds in backgroundDiff()
155+
float low_thresh = 2.0; //
156+
157+
// I is just a sample image for allocation purposes
158+
// (passed in for sizing)
159+
//
160+
void AllocateImages( const cv::Mat& I ) {
161+
cv::Size sz = I.size();
162+
IavgF = cv::Mat::zeros(sz, CV_32FC3 );
163+
IdiffF = cv::Mat::zeros(sz, CV_32FC3 );
164+
IhiF = cv::Mat::zeros(sz, CV_32FC3 );
165+
IlowF = cv::Mat::zeros(sz, CV_32FC3 );
166+
tmp = cv::Mat::zeros( sz, CV_32FC3 );
167+
Imaskt = cv::Mat( sz, CV_32FC1 );
168+
}
169+
170+
171+
void setHighThreshold( float scale ) {
172+
IhiF = IavgF + (IdiffF * scale);
173+
cv::split( IhiF, Ihi );
174+
}
175+
176+
void setLowThreshold( float scale ) {
177+
IlowF = IavgF - (IdiffF * scale);
178+
cv::split( IlowF, Ilow );
179+
}
180+
181+
void createModelsfromStats() {
182+
//IavgF is already set;
183+
//IdiffF is the standard deviation image...
184+
185+
// Make sure diff is always something
186+
//
187+
IdiffF += cv::Scalar( 0.1, 0.1, 0.1 );
188+
setHighThreshold( high_thresh);
189+
setLowThreshold( low_thresh);
190+
}
191+
192+
193+
// Create a binary: 0,255 mask where 255 (red) means foreground pixel
194+
// I Input image, 3-channel, 8u
195+
// Imask Mask image to be created, 1-channel 8u
196+
//
197+
void backgroundDiff(
198+
cv::Mat& I,
199+
cv::Mat& Imask) {
200+
201+
I.convertTo( tmp, CV_32F ); // To float
202+
cv::split( tmp, Igray );
203+
204+
// Channel 1
205+
//
206+
cv::inRange( Igray[0], Ilow[0], Ihi[0], Imask );
207+
208+
// Channel 2
209+
//
210+
cv::inRange( Igray[1], Ilow[1], Ihi[1], Imaskt );
211+
Imask = cv::min( Imask, Imaskt );
212+
213+
// Channel 3
214+
//
215+
cv::inRange( Igray[2], Ilow[2], Ihi[2], Imaskt );
216+
Imask = cv::min( Imask, Imaskt );
217+
218+
// Finally, invert the results
219+
//
220+
Imask = 255 - Imask;
221+
}
222+
223+
224+
void showForgroundInRed( char** argv, const cv::Mat &img) {
225+
cv::Mat rawImage;
226+
cv::split( img, Igray );
227+
Igray[2] = cv::max( mask, Igray[2] );
228+
cv::merge( Igray, rawImage );
229+
cv::imshow( argv[0], rawImage );
230+
cv::imshow("Segmentation", mask);
231+
}
232+
233+
void adjustThresholds(char** argv, cv::Mat &img) {
234+
int key = 1;
235+
while((key = cv::waitKey()) != 27 && key != 'Q' && key != 'q') // Esc or Q or q to exit
236+
{
237+
if(key == 'L') { low_thresh += 0.2;}
238+
if(key == 'l') { low_thresh -= 0.2;}
239+
if(key == 'H') { high_thresh += 0.2;}
240+
if(key == 'h') { high_thresh -= 0.2;}
241+
cout << "H or h, L or l, esq or q to quit; high_thresh = " << high_thresh << ", " << "low_thresh = " << low_thresh << endl;
242+
setHighThreshold(high_thresh);
243+
setLowThreshold(low_thresh);
244+
backgroundDiff(img, mask);
245+
showForgroundInRed(argv, img);
246+
}
247+
}
248+
249+
int main( int argc, char** argv) {
250+
cv::namedWindow( argv[0], cv::WINDOW_AUTOSIZE );
251+
cv::VideoCapture cap;
252+
if((argc < 3)|| !cap.open(argv[2])) {
253+
cerr << "Couldn't run the program" << endl;
254+
help(argv);
255+
cap.open(0);
256+
return -1;
257+
}
258+
int number_to_train_on = atoi( argv[1] );
259+
260+
// FIRST PROCESSING LOOP (TRAINING):
261+
//
262+
int image_count = 0;
263+
int key;
264+
bool first_frame = true;
265+
cout << "Total frames to train on = " << number_to_train_on << endl; //db
266+
while(1) {
267+
cout << "frame#: " << image_count << endl;
268+
cap >> image;
269+
if( !image.data ) exit(1); // Something went wrong, abort
270+
if(image_count == 0) AllocateImages( image );
271+
accumulateVariance(image);
272+
cv::imshow( argv[0], image );
273+
image_count++;
274+
if( (key = cv::waitKey(7)) == 27 || key == 'q' || key == 'Q' || image_count >= number_to_train_on) break; //Allow early exit on space, esc, q
275+
}
276+
277+
// We have accumulated our training, now create the models
278+
//
279+
cout << "Creating the background model" << endl;
280+
computeAvg(IavgF);
281+
computeStdev(IdiffF);
282+
createModelsfromStats();
283+
cout << "Done! Hit any key to continue into single step. Hit 'a' or 'A' to adjust thresholds, esq, 'q' or 'Q' to quit\n" << endl;
284+
285+
// SECOND PROCESSING LOOP (TESTING):
286+
//
287+
cv::namedWindow("Segmentation", cv::WINDOW_AUTOSIZE ); //For the mask image
288+
while((key = cv::waitKey()) != 27 || key == 'q' || key == 'Q' ) { // esc, 'q' or 'Q' to exit
289+
cap >> image;
290+
if( !image.data ) exit(0);
291+
cout << image_count++ << endl;
292+
backgroundDiff( image, mask );
293+
cv::imshow("Segmentation", mask);
294+
295+
// A simple visualization is to write to the red channel
296+
//
297+
showForgroundInRed( argv, image);
298+
if(key == 'a') {
299+
cout << "In adjust thresholds, 'H' or 'h' == high thresh up or down; 'L' or 'l' for low thresh up or down." << endl;
300+
cout << " esq, 'q' or 'Q' to quit " << endl;
301+
adjustThresholds(argv, image);
302+
cout << "Done with adjustThreshold, back to frame stepping, esq, q or Q to quit." << endl;
303+
}
304+
}
305+
exit(0);
306+
}
307+
308+

0 commit comments

Comments
 (0)