~ubuntu-branches/ubuntu/quantal/gst-plugins-bad0.10/quantal-proposed

« back to all changes in this revision

Viewing changes to gst/patchdetect/gstpatchdetect.c

  • Committer: Bazaar Package Importer
  • Author(s): Ken VanDine
  • Date: 2011-07-19 14:32:43 UTC
  • mfrom: (18.4.21 sid)
  • Revision ID: james.westby@ubuntu.com-20110719143243-p7pnkh45akfp0ihk
Tags: 0.10.22-2ubuntu1
* Rebased on debian unstable, remaining changes:
  - debian/gstreamer-plugins-bad.install
    * don't include dtmf, liveadder, rtpmux, autoconvert and shm, we include 
      them in -good

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GStreamer
 
2
 * Copyright (C) 2011 David Schleef <ds@entropywave.com>
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Library General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Library General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Library General Public
 
15
 * License along with this library; if not, write to the
 
16
 * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
 
17
 * Boston, MA 02110-1335, USA.
 
18
 */
 
19
/**
 
20
 * SECTION:element-gstpatchdetect
 
21
 *
 
22
 * The patchdetect element detects color patches from a color
 
23
 * calibration chart.  Currently, the patches for the 24-square
 
24
 * Munsell ColorChecker are hard-coded into the element.  When
 
25
 * a color chart is detected in the video stream, a message is
 
26
 * sent to the bus containing the detected color values of each
 
27
 * of the patches.
 
28
 *
 
29
 * <refsect2>
 
30
 * <title>Example launch line</title>
 
31
 * |[
 
32
 * gst-launch -v dv1394src ! dvdemux ! dvdec ! patchdetect ! xvimagesink
 
33
 * ]|
 
34
 * </refsect2>
 
35
 */
 
36
 
 
37
#ifdef HAVE_CONFIG_H
 
38
#include "config.h"
 
39
#endif
 
40
 
 
41
#include <gst/gst.h>
 
42
#include <gst/base/gstbasetransform.h>
 
43
#include <gst/video/video.h>
 
44
#include <math.h>
 
45
#include <string.h>
 
46
#include "gstpatchdetect.h"
 
47
 
 
48
GST_DEBUG_CATEGORY_STATIC (gst_patchdetect_debug_category);
 
49
#define GST_CAT_DEFAULT gst_patchdetect_debug_category
 
50
 
 
51
/* prototypes */
 
52
 
 
53
 
 
54
static void gst_patchdetect_set_property (GObject * object,
 
55
    guint property_id, const GValue * value, GParamSpec * pspec);
 
56
static void gst_patchdetect_get_property (GObject * object,
 
57
    guint property_id, GValue * value, GParamSpec * pspec);
 
58
static void gst_patchdetect_dispose (GObject * object);
 
59
static void gst_patchdetect_finalize (GObject * object);
 
60
 
 
61
static gboolean
 
62
gst_patchdetect_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
 
63
    guint * size);
 
64
static gboolean
 
65
gst_patchdetect_set_caps (GstBaseTransform * trans, GstCaps * incaps,
 
66
    GstCaps * outcaps);
 
67
static gboolean gst_patchdetect_start (GstBaseTransform * trans);
 
68
static gboolean gst_patchdetect_stop (GstBaseTransform * trans);
 
69
static gboolean gst_patchdetect_event (GstBaseTransform * trans,
 
70
    GstEvent * event);
 
71
static GstFlowReturn gst_patchdetect_transform_ip (GstBaseTransform * trans,
 
72
    GstBuffer * buf);
 
73
static gboolean gst_patchdetect_src_event (GstBaseTransform * trans,
 
74
    GstEvent * event);
 
75
 
 
76
enum
 
77
{
 
78
  PROP_0
 
79
};
 
80
 
 
81
/* pad templates */
 
82
 
 
83
static GstStaticPadTemplate gst_patchdetect_sink_template =
 
84
GST_STATIC_PAD_TEMPLATE ("sink",
 
85
    GST_PAD_SINK,
 
86
    GST_PAD_ALWAYS,
 
87
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
 
88
    );
 
89
 
 
90
static GstStaticPadTemplate gst_patchdetect_src_template =
 
91
GST_STATIC_PAD_TEMPLATE ("src",
 
92
    GST_PAD_SRC,
 
93
    GST_PAD_ALWAYS,
 
94
    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
 
95
    );
 
96
 
 
97
 
 
98
/* class initialization */
 
99
 
 
100
#define DEBUG_INIT(bla) \
 
101
  GST_DEBUG_CATEGORY_INIT (gst_patchdetect_debug_category, "patchdetect", 0, \
 
102
      "debug category for patchdetect element");
 
103
 
 
104
GST_BOILERPLATE_FULL (GstPatchdetect, gst_patchdetect, GstBaseTransform,
 
105
    GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
 
106
 
 
107
static void
 
108
gst_patchdetect_base_init (gpointer g_class)
 
109
{
 
110
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
111
 
 
112
  gst_element_class_add_pad_template (element_class,
 
113
      gst_static_pad_template_get (&gst_patchdetect_sink_template));
 
114
  gst_element_class_add_pad_template (element_class,
 
115
      gst_static_pad_template_get (&gst_patchdetect_src_template));
 
116
 
 
117
  gst_element_class_set_details_simple (element_class, "Color Patch Detector",
 
118
      "Video/Analysis", "Detects color patches from a color calibration chart",
 
119
      "David Schleef <ds@entropywave.com>");
 
120
}
 
121
 
 
122
static void
 
123
gst_patchdetect_class_init (GstPatchdetectClass * klass)
 
124
{
 
125
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
126
  GstBaseTransformClass *base_transform_class =
 
127
      GST_BASE_TRANSFORM_CLASS (klass);
 
128
 
 
129
  gobject_class->set_property = gst_patchdetect_set_property;
 
130
  gobject_class->get_property = gst_patchdetect_get_property;
 
131
  gobject_class->dispose = gst_patchdetect_dispose;
 
132
  gobject_class->finalize = gst_patchdetect_finalize;
 
133
  base_transform_class->get_unit_size =
 
134
      GST_DEBUG_FUNCPTR (gst_patchdetect_get_unit_size);
 
135
  base_transform_class->set_caps = GST_DEBUG_FUNCPTR (gst_patchdetect_set_caps);
 
136
  base_transform_class->start = GST_DEBUG_FUNCPTR (gst_patchdetect_start);
 
137
  base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_patchdetect_stop);
 
138
  base_transform_class->event = GST_DEBUG_FUNCPTR (gst_patchdetect_event);
 
139
  base_transform_class->transform_ip =
 
140
      GST_DEBUG_FUNCPTR (gst_patchdetect_transform_ip);
 
141
  base_transform_class->src_event =
 
142
      GST_DEBUG_FUNCPTR (gst_patchdetect_src_event);
 
143
 
 
144
}
 
145
 
 
146
static void
 
147
gst_patchdetect_init (GstPatchdetect * patchdetect,
 
148
    GstPatchdetectClass * patchdetect_class)
 
149
{
 
150
 
 
151
  patchdetect->sinkpad =
 
152
      gst_pad_new_from_static_template (&gst_patchdetect_sink_template, "sink");
 
153
 
 
154
  patchdetect->srcpad =
 
155
      gst_pad_new_from_static_template (&gst_patchdetect_src_template, "src");
 
156
}
 
157
 
 
158
void
 
159
gst_patchdetect_set_property (GObject * object, guint property_id,
 
160
    const GValue * value, GParamSpec * pspec)
 
161
{
 
162
  GstPatchdetect *patchdetect;
 
163
 
 
164
  g_return_if_fail (GST_IS_PATCHDETECT (object));
 
165
  patchdetect = GST_PATCHDETECT (object);
 
166
 
 
167
  switch (property_id) {
 
168
    default:
 
169
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
170
      break;
 
171
  }
 
172
}
 
173
 
 
174
void
 
175
gst_patchdetect_get_property (GObject * object, guint property_id,
 
176
    GValue * value, GParamSpec * pspec)
 
177
{
 
178
  GstPatchdetect *patchdetect;
 
179
 
 
180
  g_return_if_fail (GST_IS_PATCHDETECT (object));
 
181
  patchdetect = GST_PATCHDETECT (object);
 
182
 
 
183
  switch (property_id) {
 
184
    default:
 
185
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
186
      break;
 
187
  }
 
188
}
 
189
 
 
190
void
 
191
gst_patchdetect_dispose (GObject * object)
 
192
{
 
193
  GstPatchdetect *patchdetect;
 
194
 
 
195
  g_return_if_fail (GST_IS_PATCHDETECT (object));
 
196
  patchdetect = GST_PATCHDETECT (object);
 
197
 
 
198
  /* clean up as possible.  may be called multiple times */
 
199
 
 
200
  G_OBJECT_CLASS (parent_class)->dispose (object);
 
201
}
 
202
 
 
203
void
 
204
gst_patchdetect_finalize (GObject * object)
 
205
{
 
206
  GstPatchdetect *patchdetect;
 
207
 
 
208
  g_return_if_fail (GST_IS_PATCHDETECT (object));
 
209
  patchdetect = GST_PATCHDETECT (object);
 
210
 
 
211
  /* clean up object here */
 
212
 
 
213
  G_OBJECT_CLASS (parent_class)->finalize (object);
 
214
}
 
215
 
 
216
 
 
217
static gboolean
 
218
gst_patchdetect_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
 
219
    guint * size)
 
220
{
 
221
  int width, height;
 
222
  GstVideoFormat format;
 
223
  gboolean ret;
 
224
 
 
225
  ret = gst_video_format_parse_caps (caps, &format, &width, &height);
 
226
  *size = gst_video_format_get_size (format, width, height);
 
227
 
 
228
  return ret;
 
229
}
 
230
 
 
231
static gboolean
 
232
gst_patchdetect_set_caps (GstBaseTransform * trans, GstCaps * incaps,
 
233
    GstCaps * outcaps)
 
234
{
 
235
  GstPatchdetect *patchdetect = GST_PATCHDETECT (trans);
 
236
  int width, height;
 
237
  GstVideoFormat format;
 
238
  gboolean ret;
 
239
 
 
240
  ret = gst_video_format_parse_caps (incaps, &format, &width, &height);
 
241
  if (ret) {
 
242
    patchdetect->format = format;
 
243
    patchdetect->width = width;
 
244
    patchdetect->height = height;
 
245
  }
 
246
 
 
247
  return ret;
 
248
}
 
249
 
 
250
static gboolean
 
251
gst_patchdetect_start (GstBaseTransform * trans)
 
252
{
 
253
 
 
254
  return TRUE;
 
255
}
 
256
 
 
257
static gboolean
 
258
gst_patchdetect_stop (GstBaseTransform * trans)
 
259
{
 
260
 
 
261
  return TRUE;
 
262
}
 
263
 
 
264
static gboolean
 
265
gst_patchdetect_event (GstBaseTransform * trans, GstEvent * event)
 
266
{
 
267
 
 
268
  return TRUE;
 
269
}
 
270
 
 
271
typedef struct
 
272
{
 
273
  guint8 *y;
 
274
  int ystride;
 
275
  guint8 *u;
 
276
  int ustride;
 
277
  guint8 *v;
 
278
  int vstride;
 
279
  int width;
 
280
  int height;
 
281
  int t;
 
282
} Frame;
 
283
 
 
284
typedef struct
 
285
{
 
286
  int y, u, v;
 
287
  int diff_y, diff_u, diff_v;
 
288
  gboolean match;
 
289
  int patch_block;
 
290
  int color;
 
291
  int count;
 
292
  int sum_x;
 
293
  int sum_y;
 
294
} Stats;
 
295
 
 
296
typedef struct
 
297
{
 
298
  int r, g, b;
 
299
  int y, u, v;
 
300
} Color;
 
301
 
 
302
typedef struct
 
303
{
 
304
  int x, y;
 
305
  int patch1, patch2;
 
306
  gboolean valid;
 
307
} Point;
 
308
 
 
309
typedef struct
 
310
{
 
311
  int xmin, xmax;
 
312
  int ymin, ymax;
 
313
  int val;
 
314
  int y, u, v;
 
315
  int count;
 
316
  int cen_x, cen_y;
 
317
  gboolean valid;
 
318
} Patch;
 
319
 
 
320
static Color patch_colors[24] = {
 
321
  {115, 82, 68, 92, 119, 143},
 
322
  {194, 150, 130, 152, 115, 148},
 
323
  {98, 122, 157, 119, 146, 116},
 
324
  {87, 108, 67, 102, 112, 120},
 
325
  {133, 128, 177, 130, 149, 128},
 
326
  {103, 189, 170, 161, 128, 91},
 
327
  {214, 126, 44, 135, 83, 170},
 
328
  {80, 91, 166, 97, 162, 120},
 
329
  {193, 90, 99, 113, 122, 173},
 
330
  {94, 60, 108, 77, 146, 141},
 
331
  {157, 188, 64, 164, 77, 119},
 
332
  {224, 163, 46, 160, 70, 160},
 
333
  {56, 61, 150, 73, 168, 122},
 
334
  {70, 148, 73, 124, 103, 97},
 
335
  {175, 54, 60, 85, 118, 181},
 
336
  {231, 199, 31, 182, 51, 149},
 
337
  {187, 86, 149, 112, 146, 170},
 
338
  {8, 133, 161, 109, 153, 72},
 
339
  {243, 243, 243, 225, 128, 128},
 
340
  {200, 200, 200, 188, 128, 128},
 
341
  {160, 160, 160, 153, 128, 128},
 
342
  {122, 122, 122, 121, 128, 128},
 
343
  {85, 85, 85, 89, 128, 128},
 
344
  {52, 52, 52, 61, 128, 128}
 
345
};
 
346
 
 
347
static void
 
348
get_block_stats (Frame * frame, int x, int y, Stats * stats)
 
349
{
 
350
  int i, j;
 
351
  guint8 *data;
 
352
  int max;
 
353
  int min;
 
354
  int sum;
 
355
 
 
356
  max = 0;
 
357
  min = 255;
 
358
  sum = 0;
 
359
  for (j = 0; j < 8; j++) {
 
360
    data = frame->y + frame->ystride * (j + y) + x;
 
361
    for (i = 0; i < 8; i++) {
 
362
      max = MAX (max, data[i]);
 
363
      min = MIN (min, data[i]);
 
364
      sum += data[i];
 
365
    }
 
366
  }
 
367
  stats->y = sum / 64;
 
368
  stats->diff_y = MAX (max - stats->y, stats->y - min);
 
369
 
 
370
  max = 0;
 
371
  min = 255;
 
372
  sum = 0;
 
373
  for (j = 0; j < 4; j++) {
 
374
    data = frame->u + frame->ustride * (j + y / 2) + x / 2;
 
375
    for (i = 0; i < 4; i++) {
 
376
      max = MAX (max, data[i]);
 
377
      min = MIN (min, data[i]);
 
378
      sum += data[i];
 
379
    }
 
380
  }
 
381
  stats->u = sum / 16;
 
382
  stats->diff_u = MAX (max - stats->u, stats->u - min);
 
383
 
 
384
  max = 0;
 
385
  min = 255;
 
386
  sum = 0;
 
387
  for (j = 0; j < 4; j++) {
 
388
    data = frame->v + frame->vstride * (j + y / 2) + x / 2;
 
389
    for (i = 0; i < 4; i++) {
 
390
      max = MAX (max, data[i]);
 
391
      min = MIN (min, data[i]);
 
392
      sum += data[i];
 
393
    }
 
394
  }
 
395
  stats->v = sum / 16;
 
396
  stats->diff_v = MAX (max - stats->v, stats->v - min);
 
397
 
 
398
  stats->patch_block = -1;
 
399
  stats->match = FALSE;
 
400
#define MATCH 15
 
401
  if (stats->diff_y < MATCH && stats->diff_u < MATCH && stats->diff_v < MATCH) {
 
402
    stats->match = TRUE;
 
403
  }
 
404
}
 
405
 
 
406
static void
 
407
paint_block (Frame * frame, int x, int y, int value)
 
408
{
 
409
  int i, j;
 
410
  guint8 *data;
 
411
 
 
412
  for (j = 0; j < 8; j++) {
 
413
    data = frame->y + frame->ystride * (j + y) + x;
 
414
    for (i = 0; i < 8; i++) {
 
415
      data[i] = value;
 
416
    }
 
417
  }
 
418
 
 
419
  for (j = 0; j < 4; j++) {
 
420
    data = frame->u + frame->ustride * (j + y / 2) + x / 2;
 
421
    for (i = 0; i < 4; i++) {
 
422
      data[i] = 128;
 
423
    }
 
424
  }
 
425
 
 
426
  for (j = 0; j < 4; j++) {
 
427
    data = frame->v + frame->vstride * (j + y / 2) + x / 2;
 
428
    for (i = 0; i < 4; i++) {
 
429
      data[i] = 128;
 
430
    }
 
431
  }
 
432
}
 
433
 
 
434
static gboolean
 
435
patch_check (Frame * frame, guint8 * patchpix, int x, int y, int w, int h)
 
436
{
 
437
  int i, j;
 
438
 
 
439
  for (j = y; j < y + h; j++) {
 
440
    for (i = x; i < x + w; i++) {
 
441
      if (patchpix[j * frame->width + i] != 0)
 
442
        return FALSE;
 
443
    }
 
444
  }
 
445
 
 
446
  return TRUE;
 
447
}
 
448
 
 
449
static void
 
450
patch_start (Frame * frame, guint8 * patchpix, Patch * patch, int x, int y,
 
451
    int w, int h)
 
452
{
 
453
  int i, j;
 
454
 
 
455
  for (j = y; j < y + h; j++) {
 
456
    for (i = x; i < x + w; i++) {
 
457
      patchpix[j * frame->width + i] = patch->val;
 
458
    }
 
459
  }
 
460
  patch->xmin = MAX (1, x - 1);
 
461
  patch->xmax = MIN (x + w + 1, frame->width - 1);
 
462
  patch->ymin = MAX (1, y - 1);
 
463
  patch->ymax = MIN (y + h + 1, frame->height - 1);
 
464
  patch->count = w * h;
 
465
 
 
466
}
 
467
 
 
468
static void
 
469
patch_grow (Frame * frame, guint8 * patchpix, Patch * patch)
 
470
{
 
471
  gboolean growmore = FALSE;
 
472
  guint8 *ydata, *udata, *vdata;
 
473
  int i, j;
 
474
  int count = 5;
 
475
 
 
476
#define MAXDIFF 15
 
477
  do {
 
478
    for (j = patch->ymin; j < patch->ymax; j++) {
 
479
      ydata = frame->y + frame->ystride * j;
 
480
      udata = frame->u + frame->ustride * (j / 2);
 
481
      vdata = frame->v + frame->vstride * (j / 2);
 
482
      for (i = patch->xmin; i < patch->xmax; i++) {
 
483
        if (patchpix[j * frame->width + i] != 0)
 
484
          continue;
 
485
 
 
486
        if (patchpix[(j + 1) * frame->width + i] == patch->val ||
 
487
            patchpix[(j - 1) * frame->width + i] == patch->val ||
 
488
            patchpix[j * frame->width + i + 1] == patch->val ||
 
489
            patchpix[j * frame->width + i - 1] == patch->val) {
 
490
          int diff = ABS (ydata[i] - patch->y) +
 
491
              ABS (udata[i / 2] - patch->u) + ABS (vdata[i / 2] - patch->v);
 
492
 
 
493
          if (diff < MAXDIFF) {
 
494
            patchpix[j * frame->width + i] = patch->val;
 
495
            patch->xmin = MIN (patch->xmin, MAX (i - 1, 1));
 
496
            patch->xmax = MAX (patch->xmax, MIN (i + 2, frame->width - 1));
 
497
            patch->ymin = MIN (patch->ymin, MAX (j - 1, 1));
 
498
            patch->ymax = MAX (patch->ymax, MIN (j + 2, frame->height - 1));
 
499
            patch->count++;
 
500
            growmore = TRUE;
 
501
          }
 
502
        }
 
503
      }
 
504
    }
 
505
    for (j = patch->ymax - 1; j >= patch->ymin; j--) {
 
506
      ydata = frame->y + frame->ystride * j;
 
507
      udata = frame->u + frame->ustride * (j / 2);
 
508
      vdata = frame->v + frame->vstride * (j / 2);
 
509
      for (i = patch->xmax - 1; i >= patch->xmin; i--) {
 
510
        if (patchpix[j * frame->width + i] != 0)
 
511
          continue;
 
512
 
 
513
        if (patchpix[(j + 1) * frame->width + i] == patch->val ||
 
514
            patchpix[(j - 1) * frame->width + i] == patch->val ||
 
515
            patchpix[j * frame->width + i + 1] == patch->val ||
 
516
            patchpix[j * frame->width + i - 1] == patch->val) {
 
517
          int diff = ABS (ydata[i] - patch->y) +
 
518
              ABS (udata[i / 2] - patch->u) + ABS (vdata[i / 2] - patch->v);
 
519
 
 
520
          if (diff < MAXDIFF) {
 
521
            patchpix[j * frame->width + i] = patch->val;
 
522
            patch->xmin = MIN (patch->xmin, MAX (i - 1, 1));
 
523
            patch->xmax = MAX (patch->xmax, MIN (i + 2, frame->width - 1));
 
524
            patch->ymin = MIN (patch->ymin, MAX (j - 1, 1));
 
525
            patch->ymax = MAX (patch->ymax, MIN (j + 2, frame->height - 1));
 
526
            patch->count++;
 
527
            growmore = TRUE;
 
528
          }
 
529
        }
 
530
      }
 
531
    }
 
532
 
 
533
    count--;
 
534
  } while (growmore && count > 0);
 
535
 
 
536
#if 0
 
537
  for (j = patch->ymin; j < patch->ymax; j++) {
 
538
    guint8 *data;
 
539
    data = frame->y + frame->ystride * j;
 
540
    for (i = patch->xmin; i < patch->xmax; i++) {
 
541
      if (patchpix[j * frame->width + i] != patch->val)
 
542
        continue;
 
543
      if ((i + j + frame->t) & 0x4) {
 
544
        data[i] = 16;
 
545
      }
 
546
    }
 
547
  }
 
548
#endif
 
549
 
 
550
}
 
551
 
 
552
#if 0
 
553
static void
 
554
find_cluster (Point * points, int n_points, int *result_x, int *result_y)
 
555
{
 
556
  int dist;
 
557
  int ave_x, ave_y;
 
558
  int i;
 
559
 
 
560
  for (dist = 50; dist >= 10; dist -= 5) {
 
561
    int sum_x, sum_y;
 
562
    int n_valid;
 
563
 
 
564
    sum_x = 0;
 
565
    sum_y = 0;
 
566
    n_valid = 0;
 
567
    for (i = 0; i < n_points; i++) {
 
568
      if (!points[i].valid)
 
569
        continue;
 
570
      sum_x += points[i].x;
 
571
      sum_y += points[i].y;
 
572
      n_valid++;
 
573
    }
 
574
    ave_x = sum_x / n_valid;
 
575
    ave_y = sum_y / n_valid;
 
576
 
 
577
    for (i = 0; i < n_points; i++) {
 
578
      int d;
 
579
      if (!points[i].valid)
 
580
        continue;
 
581
      d = (points[i].x - ave_x) * (points[i].x - ave_x);
 
582
      d += (points[i].y - ave_y) * (points[i].y - ave_y);
 
583
      if (d > dist * dist)
 
584
        points[i].valid = FALSE;
 
585
    }
 
586
  }
 
587
  *result_x = ave_x;
 
588
  *result_y = ave_y;
 
589
}
 
590
#endif
 
591
 
 
592
typedef struct _Matrix Matrix;
 
593
struct _Matrix
 
594
{
 
595
  double m[4][4];
 
596
};
 
597
 
 
598
#if 0
 
599
static void
 
600
dump_4x4 (double a[4][4], double b[4][4])
 
601
{
 
602
  int j;
 
603
  int i;
 
604
 
 
605
  for (j = 0; j < 4; j++) {
 
606
    g_print ("[ ");
 
607
    for (i = 0; i < 4; i++) {
 
608
      g_print ("%8.2g", a[i][j]);
 
609
      if (i != 4 - 1)
 
610
        g_print (", ");
 
611
    }
 
612
    g_print ("|");
 
613
    for (i = 0; i < 4; i++) {
 
614
      g_print ("%8.2g", b[i][j]);
 
615
      if (i != 4 - 1)
 
616
        g_print (", ");
 
617
    }
 
618
    g_print ("]\n");
 
619
  }
 
620
  g_print ("\n");
 
621
 
 
622
}
 
623
#endif
 
624
 
 
625
static void
 
626
invert_matrix (double m[10][10], int n)
 
627
{
 
628
  int i, j, k;
 
629
  double tmp[10][10] = { {0} };
 
630
  double x;
 
631
 
 
632
  for (i = 0; i < n; i++) {
 
633
    tmp[i][i] = 1;
 
634
  }
 
635
 
 
636
  for (j = 0; j < n; j++) {
 
637
    for (k = 0; k < n; k++) {
 
638
      if (k == j)
 
639
        continue;
 
640
 
 
641
      x = m[j][k] / m[j][j];
 
642
      for (i = 0; i < n; i++) {
 
643
        m[i][k] -= x * m[i][j];
 
644
        tmp[i][k] -= x * tmp[i][j];
 
645
      }
 
646
    }
 
647
 
 
648
    x = m[j][j];
 
649
    for (i = 0; i < n; i++) {
 
650
      m[i][j] /= x;
 
651
      tmp[i][j] /= x;
 
652
    }
 
653
  }
 
654
 
 
655
  memcpy (m, tmp, sizeof (tmp));
 
656
}
 
657
 
 
658
static GstFlowReturn
 
659
gst_patchdetect_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
 
660
{
 
661
  GstPatchdetect *patchdetect = GST_PATCHDETECT (trans);
 
662
  Frame frame;
 
663
  Point *points;
 
664
  int i, j;
 
665
  int blocks_x, blocks_y;
 
666
  int n_points;
 
667
  int n_patches;
 
668
  Patch *patches;
 
669
  guint8 *patchpix;
 
670
  int vec1_x, vec1_y;
 
671
  int vec2_x, vec2_y;
 
672
  Color detected_colors[24];
 
673
  gboolean detected = FALSE;
 
674
 
 
675
  frame.y = GST_BUFFER_DATA (buf);
 
676
  frame.ystride = gst_video_format_get_row_stride (patchdetect->format,
 
677
      0, patchdetect->width);
 
678
  frame.u =
 
679
      frame.y + gst_video_format_get_component_offset (patchdetect->format, 1,
 
680
      patchdetect->width, patchdetect->height);
 
681
  frame.ustride =
 
682
      gst_video_format_get_row_stride (patchdetect->format, 1,
 
683
      patchdetect->width);
 
684
  frame.v =
 
685
      frame.y + gst_video_format_get_component_offset (patchdetect->format, 2,
 
686
      patchdetect->width, patchdetect->height);
 
687
  frame.vstride =
 
688
      gst_video_format_get_row_stride (patchdetect->format, 2,
 
689
      patchdetect->width);
 
690
  frame.width = patchdetect->width;
 
691
  frame.height = patchdetect->height;
 
692
  frame.t = patchdetect->t;
 
693
  patchdetect->t++;
 
694
 
 
695
  blocks_y = (patchdetect->height & (~7)) / 8;
 
696
  blocks_x = (patchdetect->width & (~7)) / 8;
 
697
 
 
698
  patchpix = g_malloc0 (patchdetect->width * patchdetect->height);
 
699
  patches = g_malloc0 (sizeof (Patch) * 256);
 
700
 
 
701
  n_patches = 0;
 
702
  for (j = 0; j < blocks_y; j += 4) {
 
703
    for (i = 0; i < blocks_x; i += 4) {
 
704
      Stats block = { 0 };
 
705
 
 
706
      get_block_stats (&frame, i * 8, j * 8, &block);
 
707
 
 
708
      patches[n_patches].val = n_patches + 2;
 
709
      if (block.match) {
 
710
        if (patch_check (&frame, patchpix, i * 8, j * 8, 8, 8)) {
 
711
          patch_start (&frame, patchpix, patches + n_patches, i * 8, j * 8, 8,
 
712
              8);
 
713
 
 
714
          patches[n_patches].y = block.y;
 
715
          patches[n_patches].u = block.u;
 
716
          patches[n_patches].v = block.v;
 
717
 
 
718
          patch_grow (&frame, patchpix, patches + n_patches);
 
719
          n_patches++;
 
720
          g_assert (n_patches < 256);
 
721
        }
 
722
      }
 
723
    }
 
724
  }
 
725
 
 
726
  {
 
727
    int n;
 
728
 
 
729
    for (n = 0; n < n_patches; n++) {
 
730
      Patch *patch = &patches[n];
 
731
      int xsum;
 
732
      int ysum;
 
733
 
 
734
      if (patch->count > 10000)
 
735
        continue;
 
736
      patch->valid = TRUE;
 
737
 
 
738
      xsum = 0;
 
739
      ysum = 0;
 
740
      for (j = patch->ymin; j < patch->ymax; j++) {
 
741
        for (i = patch->xmin; i < patch->xmax; i++) {
 
742
          if (patchpix[j * frame.width + i] != patch->val)
 
743
            continue;
 
744
          xsum += i;
 
745
          ysum += j;
 
746
        }
 
747
      }
 
748
 
 
749
      patch->cen_x = xsum / patch->count;
 
750
      patch->cen_y = ysum / patch->count;
 
751
    }
 
752
 
 
753
  }
 
754
 
 
755
  points = g_malloc0 (sizeof (Point) * 1000);
 
756
  n_points = 0;
 
757
 
 
758
  for (i = 0; i < n_patches; i++) {
 
759
    for (j = i + 1; j < n_patches; j++) {
 
760
      int dist_x, dist_y;
 
761
 
 
762
      if (i == j)
 
763
        continue;
 
764
 
 
765
      dist_x = patches[i].cen_x - patches[j].cen_x;
 
766
      dist_y = patches[i].cen_y - patches[j].cen_y;
 
767
 
 
768
      if (dist_x < 0) {
 
769
        dist_x = -dist_x;
 
770
        dist_y = -dist_y;
 
771
      }
 
772
      if (ABS (2 * dist_y) < dist_x && dist_x < 100) {
 
773
        points[n_points].x = dist_x;
 
774
        points[n_points].y = dist_y;
 
775
        points[n_points].valid = TRUE;
 
776
        points[n_points].patch1 = i;
 
777
        points[n_points].patch2 = j;
 
778
        n_points++;
 
779
        g_assert (n_points < 1000);
 
780
      }
 
781
    }
 
782
  }
 
783
 
 
784
  {
 
785
    int dist;
 
786
    int ave_x = 0, ave_y = 0;
 
787
    for (dist = 50; dist >= 10; dist -= 5) {
 
788
      int sum_x, sum_y;
 
789
      int n_valid;
 
790
 
 
791
      sum_x = 0;
 
792
      sum_y = 0;
 
793
      n_valid = 0;
 
794
      for (i = 0; i < n_points; i++) {
 
795
        if (!points[i].valid)
 
796
          continue;
 
797
        sum_x += points[i].x;
 
798
        sum_y += points[i].y;
 
799
        n_valid++;
 
800
      }
 
801
      if (n_valid == 0)
 
802
        continue;
 
803
      ave_x = sum_x / n_valid;
 
804
      ave_y = sum_y / n_valid;
 
805
 
 
806
      for (i = 0; i < n_points; i++) {
 
807
        int d;
 
808
        if (!points[i].valid)
 
809
          continue;
 
810
        d = (points[i].x - ave_x) * (points[i].x - ave_x);
 
811
        d += (points[i].y - ave_y) * (points[i].y - ave_y);
 
812
        if (d > dist * dist)
 
813
          points[i].valid = FALSE;
 
814
      }
 
815
    }
 
816
    vec1_x = ave_x;
 
817
    vec1_y = ave_y;
 
818
  }
 
819
 
 
820
  n_points = 0;
 
821
  for (i = 0; i < n_patches; i++) {
 
822
    for (j = i + 1; j < n_patches; j++) {
 
823
      int dist_x, dist_y;
 
824
 
 
825
      if (i == j)
 
826
        continue;
 
827
 
 
828
      dist_x = patches[i].cen_x - patches[j].cen_x;
 
829
      dist_y = patches[i].cen_y - patches[j].cen_y;
 
830
 
 
831
      if (dist_y < 0) {
 
832
        dist_x = -dist_x;
 
833
        dist_y = -dist_y;
 
834
      }
 
835
      if (ABS (2 * dist_x) < dist_y && dist_y < 100) {
 
836
        points[n_points].x = dist_x;
 
837
        points[n_points].y = dist_y;
 
838
        points[n_points].valid = TRUE;
 
839
        points[n_points].patch1 = i;
 
840
        points[n_points].patch2 = j;
 
841
        n_points++;
 
842
        g_assert (n_points < 1000);
 
843
      }
 
844
    }
 
845
  }
 
846
 
 
847
  {
 
848
    int dist;
 
849
    int ave_x = 0, ave_y = 0;
 
850
    for (dist = 50; dist >= 10; dist -= 5) {
 
851
      int sum_x, sum_y;
 
852
      int n_valid;
 
853
 
 
854
      sum_x = 0;
 
855
      sum_y = 0;
 
856
      n_valid = 0;
 
857
      for (i = 0; i < n_points; i++) {
 
858
        if (!points[i].valid)
 
859
          continue;
 
860
        sum_x += points[i].x;
 
861
        sum_y += points[i].y;
 
862
        n_valid++;
 
863
      }
 
864
      if (n_valid == 0)
 
865
        continue;
 
866
      ave_x = sum_x / n_valid;
 
867
      ave_y = sum_y / n_valid;
 
868
 
 
869
      for (i = 0; i < n_points; i++) {
 
870
        int d;
 
871
        if (!points[i].valid)
 
872
          continue;
 
873
        d = (points[i].x - ave_x) * (points[i].x - ave_x);
 
874
        d += (points[i].y - ave_y) * (points[i].y - ave_y);
 
875
        if (d > dist * dist)
 
876
          points[i].valid = FALSE;
 
877
      }
 
878
    }
 
879
    vec2_x = ave_x;
 
880
    vec2_y = ave_y;
 
881
  }
 
882
 
 
883
#if 0
 
884
  for (i = 0; i < n_points; i++) {
 
885
    if (!points[i].valid)
 
886
      continue;
 
887
    paint_block (&frame, 4 * points[i].x, 240 + 4 * points[i].y, 16);
 
888
  }
 
889
#endif
 
890
#if 0
 
891
  paint_block (&frame, 360, 240, 16);
 
892
  paint_block (&frame, 360 + vec1_x, 240 + vec1_y, 16);
 
893
  paint_block (&frame, 360 + vec2_x, 240 + vec2_y, 16);
 
894
#endif
 
895
 
 
896
  {
 
897
    double m00, m01, m10, m11;
 
898
    double det;
 
899
    double v1, v2;
 
900
    double ave_v1 = 0, ave_v2 = 0;
 
901
 
 
902
    det = vec1_x * vec2_y - vec1_y * vec2_x;
 
903
    m00 = vec2_y / det;
 
904
    m01 = -vec2_x / det;
 
905
    m10 = -vec1_y / det;
 
906
    m11 = vec1_x / det;
 
907
 
 
908
    for (i = 0; i < n_patches - 1; i++) {
 
909
      int count = 0;
 
910
      double sum_v1 = 0;
 
911
      double sum_v2 = 0;
 
912
 
 
913
      if (!patches[i].valid)
 
914
        continue;
 
915
 
 
916
      n_points = 0;
 
917
      for (j = i + 1; j < n_patches; j++) {
 
918
        int diff_x = patches[j].cen_x - patches[i].cen_x;
 
919
        int diff_y = patches[j].cen_y - patches[i].cen_y;
 
920
 
 
921
        if (!patches[j].valid)
 
922
          continue;
 
923
 
 
924
        v1 = diff_x * m00 + diff_y * m01;
 
925
        v2 = diff_x * m10 + diff_y * m11;
 
926
 
 
927
        if (v1 > -0.5 && v1 < 5.5 && v2 > -0.5 && v2 < 3.5 &&
 
928
            ABS (v1 - rint (v1)) < 0.1 && ABS (v2 - rint (v2)) < 0.1) {
 
929
          sum_v1 += v1 - rint (v1);
 
930
          sum_v2 += v2 - rint (v2);
 
931
          count++;
 
932
        }
 
933
      }
 
934
      ave_v1 = sum_v1 / count;
 
935
      ave_v2 = sum_v2 / count;
 
936
 
 
937
      if (count > 20) {
 
938
        int k;
 
939
        for (j = 0; j < 4; j++) {
 
940
          for (k = 0; k < 6; k++) {
 
941
            Stats block;
 
942
 
 
943
            int xx;
 
944
            int yy;
 
945
            xx = patches[i].cen_x + (ave_v1 + k) * vec1_x + (ave_v2 +
 
946
                j) * vec2_x;
 
947
            yy = patches[i].cen_y + (ave_v1 + k) * vec1_y + (ave_v2 +
 
948
                j) * vec2_y;
 
949
 
 
950
            get_block_stats (&frame, xx - 4, yy - 4, &block);
 
951
            //GST_ERROR("%d %d: %d %d %d", k, j, block.y, block.u, block.v);
 
952
 
 
953
            detected_colors[k + j * 6].y = block.y;
 
954
            detected_colors[k + j * 6].u = block.u;
 
955
            detected_colors[k + j * 6].v = block.v;
 
956
 
 
957
            paint_block (&frame, xx - 4, yy - 4, 16);
 
958
          }
 
959
        }
 
960
 
 
961
        detected = TRUE;
 
962
 
 
963
#if 0
 
964
        for (j = i + 1; j < n_patches; j++) {
 
965
          int diff_x = patches[j].cen_x - patches[i].cen_x;
 
966
          int diff_y = patches[j].cen_y - patches[i].cen_y;
 
967
          int xx;
 
968
          int yy;
 
969
 
 
970
          if (!patches[j].valid)
 
971
            continue;
 
972
 
 
973
          v1 = diff_x * m00 + diff_y * m01;
 
974
          v2 = diff_x * m10 + diff_y * m11;
 
975
 
 
976
          if (v1 > -0.5 && v1 < 5.5 && v2 > -0.5 && v2 < 3.5 &&
 
977
              ABS (v1 - rint (v1)) < 0.1 && ABS (v2 - rint (v2)) < 0.1) {
 
978
            v1 = rint (v1);
 
979
            v2 = rint (v2);
 
980
            xx = patches[i].cen_x + (ave_v1 + v1) * vec1_x + (ave_v2 +
 
981
                v2) * vec2_x;
 
982
            yy = patches[i].cen_y + (ave_v1 + v1) * vec1_y + (ave_v2 +
 
983
                v2) * vec2_y;
 
984
 
 
985
            paint_block (&frame, patches[j].cen_x, patches[j].cen_y, 128);
 
986
            paint_block (&frame, xx, yy, 16);
 
987
          }
 
988
        }
 
989
        paint_block (&frame, patches[i].cen_x, patches[i].cen_y, 240);
 
990
#endif
 
991
        break;
 
992
      }
 
993
    }
 
994
  }
 
995
 
 
996
#define N 10
 
997
  if (detected) {
 
998
    int i, j, k;
 
999
    int n = N;
 
1000
    double diff = 0;
 
1001
    double matrix[10][10] = { {0} };
 
1002
    double vy[10] = { 0 };
 
1003
    double vu[10] = { 0 };
 
1004
    double vv[10] = { 0 };
 
1005
    double *by = patchdetect->by;
 
1006
    double *bu = patchdetect->bu;
 
1007
    double *bv = patchdetect->bv;
 
1008
    double flip_diff = 0;
 
1009
 
 
1010
    for (i = 0; i < 24; i++) {
 
1011
      diff += ABS (detected_colors[i].y - patch_colors[i].y);
 
1012
      diff += ABS (detected_colors[i].u - patch_colors[i].u);
 
1013
      diff += ABS (detected_colors[i].v - patch_colors[i].v);
 
1014
 
 
1015
      flip_diff += ABS (detected_colors[23 - i].y - patch_colors[i].y);
 
1016
      flip_diff += ABS (detected_colors[23 - i].u - patch_colors[i].u);
 
1017
      flip_diff += ABS (detected_colors[23 - i].v - patch_colors[i].v);
 
1018
    }
 
1019
    GST_ERROR ("uncorrected error %g (flipped %g)", diff / 24.0,
 
1020
        flip_diff / 24.0);
 
1021
    if (flip_diff < diff) {
 
1022
      for (i = 0; i < 12; i++) {
 
1023
        Color tmp;
 
1024
        tmp = detected_colors[i];
 
1025
        detected_colors[i] = detected_colors[23 - i];
 
1026
        detected_colors[23 - i] = tmp;
 
1027
      }
 
1028
    }
 
1029
 
 
1030
    for (i = 0; i < 24; i++) {
 
1031
      int dy = detected_colors[i].y - patch_colors[i].y;
 
1032
      int du = detected_colors[i].u - patch_colors[i].u;
 
1033
      int dv = detected_colors[i].v - patch_colors[i].v;
 
1034
      int py = detected_colors[i].y - 128;
 
1035
      int pu = detected_colors[i].u - 128;
 
1036
      int pv = detected_colors[i].v - 128;
 
1037
      int w = (i < 18) ? 1 : 2;
 
1038
      double z[10];
 
1039
 
 
1040
      diff += ABS (dy) + ABS (du) + ABS (dv);
 
1041
 
 
1042
      z[0] = 1;
 
1043
      z[1] = py;
 
1044
      z[2] = pu;
 
1045
      z[3] = pv;
 
1046
      z[4] = py * py;
 
1047
      z[5] = py * pu;
 
1048
      z[6] = py * pv;
 
1049
      z[7] = pu * pu;
 
1050
      z[8] = pu * pv;
 
1051
      z[9] = pv * pv;
 
1052
 
 
1053
      for (j = 0; j < n; j++) {
 
1054
        for (k = 0; k < n; k++) {
 
1055
          matrix[j][k] += w * z[j] * z[k];
 
1056
        }
 
1057
 
 
1058
        vy[j] += w * dy * z[j];
 
1059
        vu[j] += w * du * z[j];
 
1060
        vv[j] += w * dv * z[j];
 
1061
      }
 
1062
    }
 
1063
 
 
1064
    invert_matrix (matrix, n);
 
1065
 
 
1066
    for (i = 0; i < n; i++) {
 
1067
      by[i] = 0;
 
1068
      bu[i] = 0;
 
1069
      bv[i] = 0;
 
1070
      for (j = 0; j < n; j++) {
 
1071
        by[i] += matrix[i][j] * vy[j];
 
1072
        bu[i] += matrix[i][j] * vu[j];
 
1073
        bv[i] += matrix[i][j] * vv[j];
 
1074
      }
 
1075
    }
 
1076
 
 
1077
    //GST_ERROR("a %g %g %g b %g %g %g", ay, au, av, by, bu, bv);
 
1078
 
 
1079
    diff = 0;
 
1080
    for (i = 0; i < 24; i++) {
 
1081
      double cy, cu, cv;
 
1082
      double z[10];
 
1083
      int py = detected_colors[i].y - 128;
 
1084
      int pu = detected_colors[i].u - 128;
 
1085
      int pv = detected_colors[i].v - 128;
 
1086
 
 
1087
      z[0] = 1;
 
1088
      z[1] = py;
 
1089
      z[2] = pu;
 
1090
      z[3] = pv;
 
1091
      z[4] = py * py;
 
1092
      z[5] = py * pu;
 
1093
      z[6] = py * pv;
 
1094
      z[7] = pu * pu;
 
1095
      z[8] = pu * pv;
 
1096
      z[9] = pv * pv;
 
1097
 
 
1098
      cy = 0;
 
1099
      cu = 0;
 
1100
      cv = 0;
 
1101
      for (j = 0; j < n; j++) {
 
1102
        cy += by[j] * z[j];
 
1103
        cu += bu[j] * z[j];
 
1104
        cv += bv[j] * z[j];
 
1105
      }
 
1106
 
 
1107
      diff += fabs (patch_colors[i].y - (128 + py - cy));
 
1108
      diff += fabs (patch_colors[i].u - (128 + pu - cu));
 
1109
      diff += fabs (patch_colors[i].v - (128 + pv - cv));
 
1110
    }
 
1111
    GST_ERROR ("average error %g", diff / 24.0);
 
1112
    patchdetect->valid = 3000;
 
1113
  }
 
1114
 
 
1115
  if (patchdetect->valid > 0) {
 
1116
    int n = N;
 
1117
    guint8 *u1, *u2;
 
1118
    guint8 *v1, *v2;
 
1119
    double *by = patchdetect->by;
 
1120
    double *bu = patchdetect->bu;
 
1121
    double *bv = patchdetect->bv;
 
1122
 
 
1123
    patchdetect->valid--;
 
1124
    u1 = g_malloc (frame.width);
 
1125
    u2 = g_malloc (frame.width);
 
1126
    v1 = g_malloc (frame.width);
 
1127
    v2 = g_malloc (frame.width);
 
1128
 
 
1129
    for (j = 0; j < frame.height; j += 2) {
 
1130
      for (i = 0; i < frame.width / 2; i++) {
 
1131
        u1[2 * i + 0] = frame.u[(j / 2) * frame.ustride + i];
 
1132
        u1[2 * i + 1] = u1[2 * i + 0];
 
1133
        u2[2 * i + 0] = u1[2 * i + 0];
 
1134
        u2[2 * i + 1] = u1[2 * i + 0];
 
1135
        v1[2 * i + 0] = frame.v[(j / 2) * frame.vstride + i];
 
1136
        v1[2 * i + 1] = v1[2 * i + 0];
 
1137
        v2[2 * i + 0] = v1[2 * i + 0];
 
1138
        v2[2 * i + 1] = v1[2 * i + 0];
 
1139
      }
 
1140
      for (i = 0; i < frame.width; i++) {
 
1141
        int k;
 
1142
        double z[10];
 
1143
        double cy, cu, cv;
 
1144
        int y, u, v;
 
1145
        int py, pu, pv;
 
1146
 
 
1147
        y = frame.y[(j + 0) * frame.ystride + i];
 
1148
        u = u1[i];
 
1149
        v = v1[i];
 
1150
 
 
1151
        py = y - 128;
 
1152
        pu = u - 128;
 
1153
        pv = v - 128;
 
1154
 
 
1155
        z[0] = 1;
 
1156
        z[1] = py;
 
1157
        z[2] = pu;
 
1158
        z[3] = pv;
 
1159
        z[4] = py * py;
 
1160
        z[5] = py * pu;
 
1161
        z[6] = py * pv;
 
1162
        z[7] = pu * pu;
 
1163
        z[8] = pu * pv;
 
1164
        z[9] = pv * pv;
 
1165
 
 
1166
        cy = 0;
 
1167
        cu = 0;
 
1168
        cv = 0;
 
1169
        for (k = 0; k < n; k++) {
 
1170
          cy += by[k] * z[k];
 
1171
          cu += bu[k] * z[k];
 
1172
          cv += bv[k] * z[k];
 
1173
        }
 
1174
 
 
1175
        frame.y[(j + 0) * frame.ystride + i] = CLAMP (rint (y - cy), 0, 255);
 
1176
        u1[i] = CLAMP (rint (u - cu), 0, 255);
 
1177
        v1[i] = CLAMP (rint (v - cv), 0, 255);
 
1178
 
 
1179
        y = frame.y[(j + 1) * frame.ystride + i];
 
1180
        u = u2[i];
 
1181
        v = v2[i];
 
1182
 
 
1183
        py = y - 128;
 
1184
        pu = u - 128;
 
1185
        pv = v - 128;
 
1186
 
 
1187
        z[0] = 1;
 
1188
        z[1] = py;
 
1189
        z[2] = pu;
 
1190
        z[3] = pv;
 
1191
        z[4] = py * py;
 
1192
        z[5] = py * pu;
 
1193
        z[6] = py * pv;
 
1194
        z[7] = pu * pu;
 
1195
        z[8] = pu * pv;
 
1196
        z[9] = pv * pv;
 
1197
 
 
1198
        cy = 0;
 
1199
        cu = 0;
 
1200
        cv = 0;
 
1201
        for (k = 0; k < n; k++) {
 
1202
          cy += by[k] * z[k];
 
1203
          cu += bu[k] * z[k];
 
1204
          cv += bv[k] * z[k];
 
1205
        }
 
1206
 
 
1207
        frame.y[(j + 1) * frame.ystride + i] = CLAMP (rint (y - cy), 0, 255);
 
1208
        u2[i] = CLAMP (rint (u - cu), 0, 255);
 
1209
        v2[i] = CLAMP (rint (v - cv), 0, 255);
 
1210
      }
 
1211
      for (i = 0; i < frame.width / 2; i++) {
 
1212
        frame.u[(j / 2) * frame.ustride + i] = (u1[2 * i + 0] +
 
1213
            u1[2 * i + 1] + u2[2 * i + 0] + u2[2 * i + 1] + 2) >> 2;
 
1214
        frame.v[(j / 2) * frame.vstride + i] = (v1[2 * i + 0] +
 
1215
            v1[2 * i + 1] + v2[2 * i + 0] + v2[2 * i + 1] + 2) >> 2;
 
1216
      }
 
1217
    }
 
1218
 
 
1219
    g_free (u1);
 
1220
    g_free (u2);
 
1221
    g_free (v1);
 
1222
    g_free (v2);
 
1223
  }
 
1224
 
 
1225
  g_free (points);
 
1226
  g_free (patches);
 
1227
  g_free (patchpix);
 
1228
 
 
1229
  return GST_FLOW_OK;
 
1230
}
 
1231
 
 
1232
static gboolean
 
1233
gst_patchdetect_src_event (GstBaseTransform * trans, GstEvent * event)
 
1234
{
 
1235
 
 
1236
  return TRUE;
 
1237
}
 
1238
 
 
1239
static gboolean
 
1240
plugin_init (GstPlugin * plugin)
 
1241
{
 
1242
 
 
1243
  gst_element_register (plugin, "patchdetect", GST_RANK_NONE,
 
1244
      gst_patchdetect_get_type ());
 
1245
 
 
1246
  return TRUE;
 
1247
}
 
1248
 
 
1249
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
 
1250
    GST_VERSION_MINOR,
 
1251
    "patchdetect",
 
1252
    "patchdetect element",
 
1253
    plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)