motioncells: make framedrop work at 30 fps too
[platform/upstream/gstreamer.git] / ext / opencv / MotionCells.cpp
1 /*
2  * GStreamer
3  * Copyright (C) 2011 Robert Jobbagy <jobbagy.robert@gmail.com>
4  * Copyright (C) 2011 Nicola Murino <nicola.murino@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Alternatively, the contents of this file may be used under the
25  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
26  * which case the following provisions apply instead of the ones
27  * mentioned above:
28  *
29  * This library is free software; you can redistribute it and/or
30  * modify it under the terms of the GNU Library General Public
31  * License as published by the Free Software Foundation; either
32  * version 2 of the License, or (at your option) any later version.
33  *
34  * This library is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
37  * Library General Public License for more details.
38  *
39  * You should have received a copy of the GNU Library General Public
40  * License along with this library; if not, write to the
41  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
42  * Boston, MA 02110-1301, USA.
43  */
44
45 /* This breaks the build for reasons that aren't entirely clear to me yet */
46 #if 0
47 //#ifdef HAVE_CONFIG_H
48 //#include "config.h"
49 //#endif
50 #endif
51
52 #include <cstdlib>
53 #include <errno.h>
54 #include <math.h>
55 #include <gst/gst.h>
56 #include <arpa/inet.h>
57 #include "MotionCells.h"
58
59 uint64_t ntohl64 (uint64_t val);
60 uint64_t htonl64 (uint64_t val);
61
62 uint64_t
63 ntohl64 (uint64_t val)
64 {
65   uint64_t res64;
66   uint32_t low = (uint32_t) (val & 0x00000000FFFFFFFFLL);
67   uint32_t high = (uint32_t) ((val & 0xFFFFFFFF00000000LL) >> 32);
68   low = ntohl (low);
69   high = ntohl (high);
70   res64 = (uint64_t) high + (((uint64_t) low) << 32);
71   return res64;
72 }
73
74
75 uint64_t
76 htonl64 (uint64_t val)
77 {
78   uint64_t res64;
79   uint32_t low = (uint32_t) (val & 0x00000000FFFFFFFFLL);
80   uint32_t high = (uint32_t) ((val & 0xFFFFFFFF00000000LL) >> 32);
81   low = htonl (low);
82   high = htonl (high);
83   res64 = (uint64_t) high + (((uint64_t) low) << 32);
84   return res64;
85 }
86
87 MotionCells::MotionCells ()
88 {
89   m_framecnt = 0;
90   m_motioncells_idx_count = 0;
91   m_motioncellsidxcstr = NULL;
92   m_saveInDatafile = false;
93   mc_savefile = NULL;
94   m_pcurFrame = NULL;
95   m_pprevFrame = NULL;
96   transparencyimg = NULL;
97   m_pdifferenceImage = NULL;
98   m_pbwImage = NULL;
99   m_initdatafilefailed = new char[BUSMSGLEN];
100   m_savedatafilefailed = new char[BUSMSGLEN];
101   m_initerrorcode = 0;
102   m_saveerrorcode = 0;
103   m_alpha = 0.5;
104   m_beta = 0.5;
105   m_useAlpha = false;
106   m_isVisible = false;
107
108 }
109
110 MotionCells::~MotionCells ()
111 {
112   if (mc_savefile) {
113     fclose (mc_savefile);
114     mc_savefile = NULL;
115   }
116   delete[]m_initdatafilefailed;
117   delete[]m_savedatafilefailed;
118   if (m_motioncellsidxcstr)
119     delete[]m_motioncellsidxcstr;
120   if (m_pcurFrame)
121     cvReleaseImage (&m_pcurFrame);
122   if (m_pprevFrame)
123     cvReleaseImage (&m_pprevFrame);
124   if (transparencyimg)
125     cvReleaseImage (&transparencyimg);
126   if (m_pdifferenceImage)
127     cvReleaseImage (&m_pdifferenceImage);
128   if (m_pbwImage)
129     cvReleaseImage (&m_pbwImage);
130 }
131
132 int
133 MotionCells::performDetectionMotionCells (IplImage * p_frame,
134     double p_sensitivity, double p_framerate, int p_gridx, int p_gridy,
135     gint64 timestamp_millisec, bool p_isVisible, bool p_useAlpha,
136     int motionmaskcoord_count, motionmaskcoordrect * motionmaskcoords,
137     int motionmaskcells_count, motioncellidx * motionmaskcellsidx,
138     cellscolor motioncellscolor, int motioncells_count,
139     motioncellidx * motioncellsidx, gint64 starttime, char *p_datafile,
140     bool p_changed_datafile, int p_thickness)
141 {
142
143   int sumframecnt = 0;
144   int ret = 0;
145   p_framerate >= 1 ? p_framerate <= 5 ? sumframecnt = 1
146       : p_framerate <= 10 ? sumframecnt = 2
147       : p_framerate <= 15 ? sumframecnt = 3
148       : p_framerate <= 20 ? sumframecnt = 4
149       : p_framerate <= 25 ? sumframecnt = 5
150       : p_framerate <= 30 ? sumframecnt = 6 : sumframecnt = 0 : sumframecnt = 0;
151
152   m_framecnt++;
153   m_changed_datafile = p_changed_datafile;
154   if (m_framecnt >= sumframecnt) {
155     m_useAlpha = p_useAlpha;
156     m_gridx = p_gridx;
157     m_gridy = p_gridy;
158     if (m_changed_datafile) {
159       ret = initDataFile (p_datafile, starttime);
160       if (ret != 0)
161         return ret;
162     }
163
164     m_frameSize = cvGetSize (p_frame);
165     m_frameSize.width /= 2;
166     m_frameSize.height /= 2;
167     setMotionCells (m_frameSize.width, m_frameSize.height);
168     m_sensitivity = 1 - p_sensitivity;
169     m_isVisible = p_isVisible;
170     m_pcurFrame = cvCloneImage (p_frame);
171     IplImage *m_pcurgreyImage = cvCreateImage (m_frameSize, IPL_DEPTH_8U, 1);
172     IplImage *m_pprevgreyImage = cvCreateImage (m_frameSize, IPL_DEPTH_8U, 1);
173     IplImage *m_pgreyImage = cvCreateImage (m_frameSize, IPL_DEPTH_8U, 1);
174     IplImage *m_pcurDown =
175         cvCreateImage (m_frameSize, m_pcurFrame->depth, m_pcurFrame->nChannels);
176     IplImage *m_pprevDown = cvCreateImage (m_frameSize, m_pprevFrame->depth,
177         m_pprevFrame->nChannels);
178     m_pbwImage = cvCreateImage (m_frameSize, IPL_DEPTH_8U, 1);
179     cvPyrDown (m_pprevFrame, m_pprevDown);
180     cvCvtColor (m_pprevDown, m_pprevgreyImage, CV_RGB2GRAY);
181     cvPyrDown (m_pcurFrame, m_pcurDown);
182     cvCvtColor (m_pcurDown, m_pcurgreyImage, CV_RGB2GRAY);
183     m_pdifferenceImage = cvCloneImage (m_pcurgreyImage);
184     //cvSmooth(m_pcurgreyImage, m_pcurgreyImage, CV_GAUSSIAN, 3, 0);//TODO camera noise reduce,something smoothing, and rethink runningavg weights
185
186     //Minus the current gray frame from the 8U moving average.
187     cvAbsDiff (m_pprevgreyImage, m_pcurgreyImage, m_pdifferenceImage);
188
189     //Convert the image to black and white.
190     cvAdaptiveThreshold (m_pdifferenceImage, m_pbwImage, 255,
191         CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 7);
192
193     // Dilate and erode to get object blobs
194     cvDilate (m_pbwImage, m_pbwImage, NULL, 2);
195     cvErode (m_pbwImage, m_pbwImage, NULL, 2);
196
197     //mask-out the overlay on difference image
198     if (motionmaskcoord_count > 0)
199       performMotionMaskCoords (motionmaskcoords, motionmaskcoord_count);
200     if (motionmaskcells_count > 0)
201       performMotionMask (motionmaskcellsidx, motionmaskcells_count);
202     if (getIsNonZero (m_pbwImage)) {    //detect Motion
203       GST_DEBUG ("DETECT MOTION \n");
204       if (m_MotionCells.size () > 0)    //it contains previous motioncells what we used when frames dropped
205         m_MotionCells.clear ();
206       if (transparencyimg)
207         cvReleaseImage (&transparencyimg);
208       (motioncells_count > 0) ?
209           calculateMotionPercentInMotionCells (motioncellsidx,
210           motioncells_count)
211           : calculateMotionPercentInMotionCells (motionmaskcellsidx, 0);
212
213       transparencyimg = cvCreateImage (cvGetSize (p_frame), p_frame->depth, 3);
214       cvSetZero (transparencyimg);
215       if (m_motioncellsidxcstr)
216         delete[]m_motioncellsidxcstr;
217       m_motioncells_idx_count = m_MotionCells.size () * MSGLEN; //one motion cell idx: (lin idx : col idx,) it's 4 character except last motion cell idx
218       m_motioncellsidxcstr = new char[m_motioncells_idx_count];
219       char *tmpstr = new char[MSGLEN];
220       for (int i = 0; i < MSGLEN; i++)
221         tmpstr[i] = ' ';
222       for (unsigned int i = 0; i < m_MotionCells.size (); i++) {
223         CvPoint pt1, pt2;
224         pt1.x = m_MotionCells.at (i).cell_pt1.x * 2;
225         pt1.y = m_MotionCells.at (i).cell_pt1.y * 2;
226         pt2.x = m_MotionCells.at (i).cell_pt2.x * 2;
227         pt2.y = m_MotionCells.at (i).cell_pt2.y * 2;
228         if (m_useAlpha && m_isVisible) {
229           cvRectangle (transparencyimg,
230               pt1,
231               pt2,
232               CV_RGB (motioncellscolor.B_channel_value,
233                   motioncellscolor.G_channel_value,
234                   motioncellscolor.R_channel_value), CV_FILLED);
235         } else if (m_isVisible) {
236           cvRectangle (p_frame,
237               pt1,
238               pt2,
239               CV_RGB (motioncellscolor.B_channel_value,
240                   motioncellscolor.G_channel_value,
241                   motioncellscolor.R_channel_value), p_thickness);
242         }
243
244         if (i < m_MotionCells.size () - 1) {
245           snprintf (tmpstr, MSGLEN, "%d:%d,", m_MotionCells.at (i).lineidx,
246               m_MotionCells.at (i).colidx);
247         } else {
248           snprintf (tmpstr, MSGLEN, "%d:%d", m_MotionCells.at (i).lineidx,
249               m_MotionCells.at (i).colidx);
250         }
251         if (i == 0)
252           strncpy (m_motioncellsidxcstr, tmpstr, m_motioncells_idx_count);
253         else
254           strcat (m_motioncellsidxcstr, tmpstr);
255       }
256       if (m_MotionCells.size () == 0)
257         strncpy (m_motioncellsidxcstr, " ", m_motioncells_idx_count);
258
259       if (m_useAlpha && m_isVisible) {
260         if (m_MotionCells.size () > 0)
261           blendImages (p_frame, transparencyimg, m_alpha, m_beta);
262       }
263
264       delete[]tmpstr;
265
266       if (mc_savefile && m_saveInDatafile) {
267         ret = saveMotionCells (timestamp_millisec);
268         if (ret != 0)
269           return ret;
270       }
271     } else {
272       m_motioncells_idx_count = 0;
273       if (m_MotionCells.size () > 0)
274         m_MotionCells.clear ();
275       if (transparencyimg)
276         cvReleaseImage (&transparencyimg);
277     }
278
279     if (m_pprevFrame)
280       cvReleaseImage (&m_pprevFrame);
281     m_pprevFrame = cvCloneImage (m_pcurFrame);
282     m_framecnt = 0;
283     if (m_pcurFrame)
284       cvReleaseImage (&m_pcurFrame);
285     if (m_pdifferenceImage)
286       cvReleaseImage (&m_pdifferenceImage);
287     if (m_pcurgreyImage)
288       cvReleaseImage (&m_pcurgreyImage);
289     if (m_pprevgreyImage)
290       cvReleaseImage (&m_pprevgreyImage);
291     if (m_pgreyImage)
292       cvReleaseImage (&m_pgreyImage);
293     if (m_pbwImage)
294       cvReleaseImage (&m_pbwImage);
295     if (m_pprevDown)
296       cvReleaseImage (&m_pprevDown);
297     if (m_pcurDown)
298       cvReleaseImage (&m_pcurDown);
299     if (m_pCells) {
300       for (int i = 0; i < m_gridy; ++i) {
301         delete[]m_pCells[i];
302       }
303       delete[]m_pCells;
304     }
305
306     if (p_framerate <= 5) {
307       if (m_MotionCells.size () > 0)
308         m_MotionCells.clear ();
309       if (transparencyimg)
310         cvReleaseImage (&transparencyimg);
311     }
312   } else {                      //we do frame drop
313     m_motioncells_idx_count = 0;
314     ret = -2;
315     for (unsigned int i = 0; i < m_MotionCells.size (); i++) {
316       CvPoint pt1, pt2;
317       pt1.x = m_MotionCells.at (i).cell_pt1.x * 2;
318       pt1.y = m_MotionCells.at (i).cell_pt1.y * 2;
319       pt2.x = m_MotionCells.at (i).cell_pt2.x * 2;
320       pt2.y = m_MotionCells.at (i).cell_pt2.y * 2;
321       if (m_useAlpha && m_isVisible) {
322         cvRectangle (transparencyimg,
323             pt1,
324             pt2,
325             CV_RGB (motioncellscolor.B_channel_value,
326                 motioncellscolor.G_channel_value,
327                 motioncellscolor.R_channel_value), CV_FILLED);
328       } else if (m_isVisible) {
329         cvRectangle (p_frame,
330             pt1,
331             pt2,
332             CV_RGB (motioncellscolor.B_channel_value,
333                 motioncellscolor.G_channel_value,
334                 motioncellscolor.R_channel_value), p_thickness);
335       }
336
337     }
338     if (m_useAlpha && m_isVisible) {
339       if (m_MotionCells.size () > 0)
340         blendImages (p_frame, transparencyimg, m_alpha, m_beta);
341     }
342   }
343   return ret;
344 }
345
346 int
347 MotionCells::initDataFile (char *p_datafile, gint64 starttime)  //p_date is increased with difference between current and previous buffer ts
348 {
349   MotionCellData mcd;
350   if (strncmp (p_datafile, " ", 1)) {
351     mc_savefile = fopen (p_datafile, "w");
352     if (mc_savefile == NULL) {
353       //fprintf(stderr, "%s %d:initDataFile:fopen:%d (%s)\n", __FILE__, __LINE__, errno,
354       //strerror(errno));
355       strncpy (m_initdatafilefailed, strerror (errno), BUSMSGLEN - 1);
356       m_initerrorcode = errno;
357       return 1;
358     } else {
359       m_saveInDatafile = true;
360     }
361   } else
362     mc_savefile = NULL;
363   bzero (&m_header, sizeof (MotionCellHeader));
364   m_header.headersize = htonl (MC_HEADER);
365   m_header.type = htonl (MC_TYPE);
366   m_header.version = htonl (MC_VERSION);
367   //it needs these bytes
368   m_header.itemsize =
369       htonl ((int) ceil (ceil (m_gridx * m_gridy / 8.0) / 4.0) * 4 +
370       sizeof (mcd.timestamp));
371   m_header.gridx = htonl (m_gridx);
372   m_header.gridy = htonl (m_gridy);
373   m_header.starttime = htonl64 (starttime);
374
375   snprintf (m_header.name, sizeof (m_header.name), "%s %dx%d", MC_VERSIONTEXT,
376       ntohl (m_header.gridx), ntohl (m_header.gridy));
377   m_changed_datafile = false;
378   return 0;
379 }
380
381 int
382 MotionCells::saveMotionCells (gint64 timestamp_millisec)
383 {
384
385   MotionCellData mc_data;
386   mc_data.timestamp = htonl (timestamp_millisec);
387   mc_data.data = NULL;
388   //There is no datafile
389   if (mc_savefile == NULL)
390     return 0;
391
392   if (ftello (mc_savefile) == 0) {
393     //cerr << "Writing out file header"<< m_header.headersize <<":" << sizeof(MotionCellHeader) << " itemsize:"
394     //<< m_header.itemsize << endl;
395     if (fwrite (&m_header, sizeof (MotionCellHeader), 1, mc_savefile) != 1) {
396       //fprintf(stderr, "%s %d:saveMotionCells:fwrite:%d (%s)\n", __FILE__, __LINE__, errno,
397       //strerror(errno));
398       strncpy (m_savedatafilefailed, strerror (errno), BUSMSGLEN - 1);
399       m_saveerrorcode = errno;
400       return -1;
401     }
402   }
403
404   mc_data.data =
405       (char *) calloc (1,
406       ntohl (m_header.itemsize) - sizeof (mc_data.timestamp));
407   if (mc_data.data == NULL) {
408     //fprintf(stderr, "%s %d:saveMotionCells:calloc:%d (%s)\n", __FILE__, __LINE__, errno,
409     //strerror(errno));
410     strncpy (m_savedatafilefailed, strerror (errno), BUSMSGLEN - 1);
411     m_saveerrorcode = errno;
412     return -1;
413   }
414
415   for (unsigned int i = 0; i < m_MotionCells.size (); i++) {
416     int bitnum =
417         m_MotionCells.at (i).lineidx * ntohl (m_header.gridx) +
418         m_MotionCells.at (i).colidx;
419     int bytenum = (int) floor (bitnum / 8.0);
420     int shift = bitnum - bytenum * 8;
421     mc_data.data[bytenum] = mc_data.data[bytenum] | (1 << shift);
422     //cerr << "Motion Detected " <<  "line:" << m_MotionCells.at(i).lineidx << " col:" << m_MotionCells.at(i).colidx;
423     //cerr << "    bitnum " << bitnum << " bytenum " << bytenum << " shift " << shift << " value " << (int)mc_data.data[bytenum] << endl;
424   }
425
426   if (fwrite (&mc_data.timestamp, sizeof (mc_data.timestamp), 1,
427           mc_savefile) != 1) {
428     //fprintf(stderr, "%s %d:saveMotionCells:fwrite:%d (%s)\n", __FILE__, __LINE__, errno,
429     //strerror(errno));
430     strncpy (m_savedatafilefailed, strerror (errno), BUSMSGLEN - 1);
431     m_saveerrorcode = errno;
432     return -1;
433   }
434
435   if (fwrite (mc_data.data,
436           ntohl (m_header.itemsize) - sizeof (mc_data.timestamp), 1,
437           mc_savefile) != 1) {
438     //fprintf(stderr, "%s %d:saveMotionCells:fwrite:%d (%s)\n", __FILE__, __LINE__, errno,
439     //strerror(errno));
440     strncpy (m_savedatafilefailed, strerror (errno), BUSMSGLEN - 1);
441     m_saveerrorcode = errno;
442     return -1;
443   }
444
445   free (mc_data.data);
446   return 0;
447 }
448
449 double
450 MotionCells::calculateMotionPercentInCell (int p_row, int p_col,
451     double *p_cellarea, double *p_motionarea)
452 {
453   double cntpixelsnum = 0;
454   double cntmotionpixelnum = 0;
455
456   int ybegin = floor ((double) p_row * m_cellheight);
457   int yend = floor ((double) (p_row + 1) * m_cellheight);
458   int xbegin = floor ((double) (p_col) * m_cellwidth);
459   int xend = floor ((double) (p_col + 1) * m_cellwidth);
460   int cellw = xend - xbegin;
461   int cellh = yend - ybegin;
462   int cellarea = cellw * cellh;
463   *p_cellarea = cellarea;
464   int thresholdmotionpixelnum = floor ((double) cellarea * m_sensitivity);
465
466   for (int i = ybegin; i < yend; i++) {
467     for (int j = xbegin; j < xend; j++) {
468       cntpixelsnum++;
469       if ((((uchar *) (m_pbwImage->imageData + m_pbwImage->widthStep * i))[j]) >
470           0) {
471         cntmotionpixelnum++;
472         if (cntmotionpixelnum >= thresholdmotionpixelnum) {     //we dont needs calculate anymore
473           *p_motionarea = cntmotionpixelnum;
474           return (cntmotionpixelnum / cntpixelsnum);
475         }
476       }
477       int remainingpixelsnum = cellarea - cntpixelsnum;
478       if ((cntmotionpixelnum + remainingpixelsnum) < thresholdmotionpixelnum) { //moving pixels number will be less than threshold
479         *p_motionarea = 0;
480         return 0;
481       }
482     }
483   }
484
485   return (cntmotionpixelnum / cntpixelsnum);
486 }
487
488 void
489 MotionCells::calculateMotionPercentInMotionCells (motioncellidx *
490     p_motioncellsidx, int p_motioncells_count)
491 {
492   if (p_motioncells_count == 0) {
493     for (int i = 0; i < m_gridy; i++) {
494       for (int j = 0; j < m_gridx; j++) {
495         m_pCells[i][j].MotionPercent = calculateMotionPercentInCell (i, j,
496             &m_pCells[i][j].CellArea, &m_pCells[i][j].MotionArea);
497         m_pCells[i][j].hasMotion =
498             m_sensitivity < m_pCells[i][j].MotionPercent ? true : false;
499         if (m_pCells[i][j].hasMotion) {
500           MotionCellsIdx mci;
501           mci.lineidx = i;
502           mci.colidx = j;
503           mci.cell_pt1.x = floor ((double) j * m_cellwidth);
504           mci.cell_pt1.y = floor ((double) i * m_cellheight);
505           mci.cell_pt2.x = floor ((double) (j + 1) * m_cellwidth);
506           mci.cell_pt2.y = floor ((double) (i + 1) * m_cellheight);
507           int w = mci.cell_pt2.x - mci.cell_pt1.x;
508           int h = mci.cell_pt2.y - mci.cell_pt1.y;
509           mci.motioncell = cvRect (mci.cell_pt1.x, mci.cell_pt1.y, w, h);
510           m_MotionCells.push_back (mci);
511         }
512       }
513     }
514   } else {
515     for (int k = 0; k < p_motioncells_count; ++k) {
516
517       int i = p_motioncellsidx[k].lineidx;
518       int j = p_motioncellsidx[k].columnidx;
519       m_pCells[i][j].MotionPercent =
520           calculateMotionPercentInCell (i, j,
521           &m_pCells[i][j].CellArea, &m_pCells[i][j].MotionArea);
522       m_pCells[i][j].hasMotion =
523           m_pCells[i][j].MotionPercent > m_sensitivity ? true : false;
524       if (m_pCells[i][j].hasMotion) {
525         MotionCellsIdx mci;
526         mci.lineidx = p_motioncellsidx[k].lineidx;
527         mci.colidx = p_motioncellsidx[k].columnidx;
528         mci.cell_pt1.x = floor ((double) j * m_cellwidth);
529         mci.cell_pt1.y = floor ((double) i * m_cellheight);
530         mci.cell_pt2.x = floor ((double) (j + 1) * m_cellwidth);
531         mci.cell_pt2.y = floor ((double) (i + 1) * m_cellheight);
532         int w = mci.cell_pt2.x - mci.cell_pt1.x;
533         int h = mci.cell_pt2.y - mci.cell_pt1.y;
534         mci.motioncell = cvRect (mci.cell_pt1.x, mci.cell_pt1.y, w, h);
535         m_MotionCells.push_back (mci);
536       }
537     }
538   }
539 }
540
541 void
542 MotionCells::performMotionMaskCoords (motionmaskcoordrect * p_motionmaskcoords,
543     int p_motionmaskcoords_count)
544 {
545   CvPoint upperleft;
546   upperleft.x = 0;
547   upperleft.y = 0;
548   CvPoint lowerright;
549   lowerright.x = 0;
550   lowerright.y = 0;
551   for (int i = 0; i < p_motionmaskcoords_count; i++) {
552     upperleft.x = p_motionmaskcoords[i].upper_left_x;
553     upperleft.y = p_motionmaskcoords[i].upper_left_y;
554     lowerright.x = p_motionmaskcoords[i].lower_right_x;
555     lowerright.y = p_motionmaskcoords[i].lower_right_y;
556     cvRectangle (m_pbwImage, upperleft, lowerright, CV_RGB (0, 0, 0),
557         CV_FILLED);
558   }
559 }
560
561 void
562 MotionCells::performMotionMask (motioncellidx * p_motionmaskcellsidx,
563     int p_motionmaskcells_count)
564 {
565   for (int k = 0; k < p_motionmaskcells_count; k++) {
566     int beginy = p_motionmaskcellsidx[k].lineidx * m_cellheight;
567     int beginx = p_motionmaskcellsidx[k].columnidx * m_cellwidth;
568     int endx =
569         (double) p_motionmaskcellsidx[k].columnidx * m_cellwidth + m_cellwidth;
570     int endy =
571         (double) p_motionmaskcellsidx[k].lineidx * m_cellheight + m_cellheight;
572     for (int i = beginy; i < endy; i++)
573       for (int j = beginx; j < endx; j++) {
574         ((uchar *) (m_pbwImage->imageData + m_pbwImage->widthStep * i))[j] = 0;
575       }
576   }
577 }
578
579 ///BGR if we use only OpenCV
580 //RGB if we use gst+OpenCV
581 void
582 MotionCells::blendImages (IplImage * p_actFrame, IplImage * p_cellsFrame,
583     float p_alpha, float p_beta)
584 {
585
586   int height = p_actFrame->height;
587   int width = p_actFrame->width;
588   int step = p_actFrame->widthStep / sizeof (uchar);
589   int channels = p_actFrame->nChannels;
590   int cellstep = p_cellsFrame->widthStep / sizeof (uchar);
591   uchar *curImageData = (uchar *) p_actFrame->imageData;
592   uchar *cellImageData = (uchar *) p_cellsFrame->imageData;
593
594   for (int i = 0; i < height; i++)
595     for (int j = 0; j < width; j++)
596       for (int k = 0; k < channels; k++)
597         if (cellImageData[i * cellstep + j * channels + k] > 0) {
598           curImageData[i * step + j * channels + k] =
599               round ((double) curImageData[i * step + j * channels +
600                   k] * p_alpha + ((double) cellImageData[i * cellstep +
601                       j * channels + k] * p_beta));
602         }
603 }