2
* Copyright (C) 2011 David Schleef <ds@entropywave.com>
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.
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.
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.
20
* SECTION:element-gstpatchdetect
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
30
* <title>Example launch line</title>
32
* gst-launch -v dv1394src ! dvdemux ! dvdec ! patchdetect ! xvimagesink
42
#include <gst/base/gstbasetransform.h>
43
#include <gst/video/video.h>
46
#include "gstpatchdetect.h"
48
GST_DEBUG_CATEGORY_STATIC (gst_patchdetect_debug_category);
49
#define GST_CAT_DEFAULT gst_patchdetect_debug_category
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);
62
gst_patchdetect_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
65
gst_patchdetect_set_caps (GstBaseTransform * trans, GstCaps * incaps,
67
static gboolean gst_patchdetect_start (GstBaseTransform * trans);
68
static gboolean gst_patchdetect_stop (GstBaseTransform * trans);
69
static gboolean gst_patchdetect_event (GstBaseTransform * trans,
71
static GstFlowReturn gst_patchdetect_transform_ip (GstBaseTransform * trans,
73
static gboolean gst_patchdetect_src_event (GstBaseTransform * trans,
83
static GstStaticPadTemplate gst_patchdetect_sink_template =
84
GST_STATIC_PAD_TEMPLATE ("sink",
87
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
90
static GstStaticPadTemplate gst_patchdetect_src_template =
91
GST_STATIC_PAD_TEMPLATE ("src",
94
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
98
/* class initialization */
100
#define DEBUG_INIT(bla) \
101
GST_DEBUG_CATEGORY_INIT (gst_patchdetect_debug_category, "patchdetect", 0, \
102
"debug category for patchdetect element");
104
GST_BOILERPLATE_FULL (GstPatchdetect, gst_patchdetect, GstBaseTransform,
105
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
108
gst_patchdetect_base_init (gpointer g_class)
110
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
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));
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>");
123
gst_patchdetect_class_init (GstPatchdetectClass * klass)
125
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
126
GstBaseTransformClass *base_transform_class =
127
GST_BASE_TRANSFORM_CLASS (klass);
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);
147
gst_patchdetect_init (GstPatchdetect * patchdetect,
148
GstPatchdetectClass * patchdetect_class)
151
patchdetect->sinkpad =
152
gst_pad_new_from_static_template (&gst_patchdetect_sink_template, "sink");
154
patchdetect->srcpad =
155
gst_pad_new_from_static_template (&gst_patchdetect_src_template, "src");
159
gst_patchdetect_set_property (GObject * object, guint property_id,
160
const GValue * value, GParamSpec * pspec)
162
GstPatchdetect *patchdetect;
164
g_return_if_fail (GST_IS_PATCHDETECT (object));
165
patchdetect = GST_PATCHDETECT (object);
167
switch (property_id) {
169
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
175
gst_patchdetect_get_property (GObject * object, guint property_id,
176
GValue * value, GParamSpec * pspec)
178
GstPatchdetect *patchdetect;
180
g_return_if_fail (GST_IS_PATCHDETECT (object));
181
patchdetect = GST_PATCHDETECT (object);
183
switch (property_id) {
185
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
191
gst_patchdetect_dispose (GObject * object)
193
GstPatchdetect *patchdetect;
195
g_return_if_fail (GST_IS_PATCHDETECT (object));
196
patchdetect = GST_PATCHDETECT (object);
198
/* clean up as possible. may be called multiple times */
200
G_OBJECT_CLASS (parent_class)->dispose (object);
204
gst_patchdetect_finalize (GObject * object)
206
GstPatchdetect *patchdetect;
208
g_return_if_fail (GST_IS_PATCHDETECT (object));
209
patchdetect = GST_PATCHDETECT (object);
211
/* clean up object here */
213
G_OBJECT_CLASS (parent_class)->finalize (object);
218
gst_patchdetect_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
222
GstVideoFormat format;
225
ret = gst_video_format_parse_caps (caps, &format, &width, &height);
226
*size = gst_video_format_get_size (format, width, height);
232
gst_patchdetect_set_caps (GstBaseTransform * trans, GstCaps * incaps,
235
GstPatchdetect *patchdetect = GST_PATCHDETECT (trans);
237
GstVideoFormat format;
240
ret = gst_video_format_parse_caps (incaps, &format, &width, &height);
242
patchdetect->format = format;
243
patchdetect->width = width;
244
patchdetect->height = height;
251
gst_patchdetect_start (GstBaseTransform * trans)
258
gst_patchdetect_stop (GstBaseTransform * trans)
265
gst_patchdetect_event (GstBaseTransform * trans, GstEvent * event)
287
int diff_y, diff_u, diff_v;
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}
348
get_block_stats (Frame * frame, int x, int y, Stats * stats)
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]);
368
stats->diff_y = MAX (max - stats->y, stats->y - min);
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]);
382
stats->diff_u = MAX (max - stats->u, stats->u - min);
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]);
396
stats->diff_v = MAX (max - stats->v, stats->v - min);
398
stats->patch_block = -1;
399
stats->match = FALSE;
401
if (stats->diff_y < MATCH && stats->diff_u < MATCH && stats->diff_v < MATCH) {
407
paint_block (Frame * frame, int x, int y, int value)
412
for (j = 0; j < 8; j++) {
413
data = frame->y + frame->ystride * (j + y) + x;
414
for (i = 0; i < 8; i++) {
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++) {
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++) {
435
patch_check (Frame * frame, guint8 * patchpix, int x, int y, int w, int h)
439
for (j = y; j < y + h; j++) {
440
for (i = x; i < x + w; i++) {
441
if (patchpix[j * frame->width + i] != 0)
450
patch_start (Frame * frame, guint8 * patchpix, Patch * patch, int x, int y,
455
for (j = y; j < y + h; j++) {
456
for (i = x; i < x + w; i++) {
457
patchpix[j * frame->width + i] = patch->val;
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;
469
patch_grow (Frame * frame, guint8 * patchpix, Patch * patch)
471
gboolean growmore = FALSE;
472
guint8 *ydata, *udata, *vdata;
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)
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);
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));
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)
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);
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));
534
} while (growmore && count > 0);
537
for (j = patch->ymin; j < patch->ymax; j++) {
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)
543
if ((i + j + frame->t) & 0x4) {
554
find_cluster (Point * points, int n_points, int *result_x, int *result_y)
560
for (dist = 50; dist >= 10; dist -= 5) {
567
for (i = 0; i < n_points; i++) {
568
if (!points[i].valid)
570
sum_x += points[i].x;
571
sum_y += points[i].y;
574
ave_x = sum_x / n_valid;
575
ave_y = sum_y / n_valid;
577
for (i = 0; i < n_points; i++) {
579
if (!points[i].valid)
581
d = (points[i].x - ave_x) * (points[i].x - ave_x);
582
d += (points[i].y - ave_y) * (points[i].y - ave_y);
584
points[i].valid = FALSE;
592
typedef struct _Matrix Matrix;
600
dump_4x4 (double a[4][4], double b[4][4])
605
for (j = 0; j < 4; j++) {
607
for (i = 0; i < 4; i++) {
608
g_print ("%8.2g", a[i][j]);
613
for (i = 0; i < 4; i++) {
614
g_print ("%8.2g", b[i][j]);
626
invert_matrix (double m[10][10], int n)
629
double tmp[10][10] = { {0} };
632
for (i = 0; i < n; i++) {
636
for (j = 0; j < n; j++) {
637
for (k = 0; k < n; k++) {
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];
649
for (i = 0; i < n; i++) {
655
memcpy (m, tmp, sizeof (tmp));
659
gst_patchdetect_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
661
GstPatchdetect *patchdetect = GST_PATCHDETECT (trans);
665
int blocks_x, blocks_y;
672
Color detected_colors[24];
673
gboolean detected = FALSE;
675
frame.y = GST_BUFFER_DATA (buf);
676
frame.ystride = gst_video_format_get_row_stride (patchdetect->format,
677
0, patchdetect->width);
679
frame.y + gst_video_format_get_component_offset (patchdetect->format, 1,
680
patchdetect->width, patchdetect->height);
682
gst_video_format_get_row_stride (patchdetect->format, 1,
685
frame.y + gst_video_format_get_component_offset (patchdetect->format, 2,
686
patchdetect->width, patchdetect->height);
688
gst_video_format_get_row_stride (patchdetect->format, 2,
690
frame.width = patchdetect->width;
691
frame.height = patchdetect->height;
692
frame.t = patchdetect->t;
695
blocks_y = (patchdetect->height & (~7)) / 8;
696
blocks_x = (patchdetect->width & (~7)) / 8;
698
patchpix = g_malloc0 (patchdetect->width * patchdetect->height);
699
patches = g_malloc0 (sizeof (Patch) * 256);
702
for (j = 0; j < blocks_y; j += 4) {
703
for (i = 0; i < blocks_x; i += 4) {
706
get_block_stats (&frame, i * 8, j * 8, &block);
708
patches[n_patches].val = n_patches + 2;
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,
714
patches[n_patches].y = block.y;
715
patches[n_patches].u = block.u;
716
patches[n_patches].v = block.v;
718
patch_grow (&frame, patchpix, patches + n_patches);
720
g_assert (n_patches < 256);
729
for (n = 0; n < n_patches; n++) {
730
Patch *patch = &patches[n];
734
if (patch->count > 10000)
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)
749
patch->cen_x = xsum / patch->count;
750
patch->cen_y = ysum / patch->count;
755
points = g_malloc0 (sizeof (Point) * 1000);
758
for (i = 0; i < n_patches; i++) {
759
for (j = i + 1; j < n_patches; j++) {
765
dist_x = patches[i].cen_x - patches[j].cen_x;
766
dist_y = patches[i].cen_y - patches[j].cen_y;
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;
779
g_assert (n_points < 1000);
786
int ave_x = 0, ave_y = 0;
787
for (dist = 50; dist >= 10; dist -= 5) {
794
for (i = 0; i < n_points; i++) {
795
if (!points[i].valid)
797
sum_x += points[i].x;
798
sum_y += points[i].y;
803
ave_x = sum_x / n_valid;
804
ave_y = sum_y / n_valid;
806
for (i = 0; i < n_points; i++) {
808
if (!points[i].valid)
810
d = (points[i].x - ave_x) * (points[i].x - ave_x);
811
d += (points[i].y - ave_y) * (points[i].y - ave_y);
813
points[i].valid = FALSE;
821
for (i = 0; i < n_patches; i++) {
822
for (j = i + 1; j < n_patches; j++) {
828
dist_x = patches[i].cen_x - patches[j].cen_x;
829
dist_y = patches[i].cen_y - patches[j].cen_y;
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;
842
g_assert (n_points < 1000);
849
int ave_x = 0, ave_y = 0;
850
for (dist = 50; dist >= 10; dist -= 5) {
857
for (i = 0; i < n_points; i++) {
858
if (!points[i].valid)
860
sum_x += points[i].x;
861
sum_y += points[i].y;
866
ave_x = sum_x / n_valid;
867
ave_y = sum_y / n_valid;
869
for (i = 0; i < n_points; i++) {
871
if (!points[i].valid)
873
d = (points[i].x - ave_x) * (points[i].x - ave_x);
874
d += (points[i].y - ave_y) * (points[i].y - ave_y);
876
points[i].valid = FALSE;
884
for (i = 0; i < n_points; i++) {
885
if (!points[i].valid)
887
paint_block (&frame, 4 * points[i].x, 240 + 4 * points[i].y, 16);
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);
897
double m00, m01, m10, m11;
900
double ave_v1 = 0, ave_v2 = 0;
902
det = vec1_x * vec2_y - vec1_y * vec2_x;
908
for (i = 0; i < n_patches - 1; i++) {
913
if (!patches[i].valid)
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;
921
if (!patches[j].valid)
924
v1 = diff_x * m00 + diff_y * m01;
925
v2 = diff_x * m10 + diff_y * m11;
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);
934
ave_v1 = sum_v1 / count;
935
ave_v2 = sum_v2 / count;
939
for (j = 0; j < 4; j++) {
940
for (k = 0; k < 6; k++) {
945
xx = patches[i].cen_x + (ave_v1 + k) * vec1_x + (ave_v2 +
947
yy = patches[i].cen_y + (ave_v1 + k) * vec1_y + (ave_v2 +
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);
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;
957
paint_block (&frame, xx - 4, yy - 4, 16);
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;
970
if (!patches[j].valid)
973
v1 = diff_x * m00 + diff_y * m01;
974
v2 = diff_x * m10 + diff_y * m11;
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) {
980
xx = patches[i].cen_x + (ave_v1 + v1) * vec1_x + (ave_v2 +
982
yy = patches[i].cen_y + (ave_v1 + v1) * vec1_y + (ave_v2 +
985
paint_block (&frame, patches[j].cen_x, patches[j].cen_y, 128);
986
paint_block (&frame, xx, yy, 16);
989
paint_block (&frame, patches[i].cen_x, patches[i].cen_y, 240);
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;
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);
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);
1019
GST_ERROR ("uncorrected error %g (flipped %g)", diff / 24.0,
1021
if (flip_diff < diff) {
1022
for (i = 0; i < 12; i++) {
1024
tmp = detected_colors[i];
1025
detected_colors[i] = detected_colors[23 - i];
1026
detected_colors[23 - i] = tmp;
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;
1040
diff += ABS (dy) + ABS (du) + ABS (dv);
1053
for (j = 0; j < n; j++) {
1054
for (k = 0; k < n; k++) {
1055
matrix[j][k] += w * z[j] * z[k];
1058
vy[j] += w * dy * z[j];
1059
vu[j] += w * du * z[j];
1060
vv[j] += w * dv * z[j];
1064
invert_matrix (matrix, n);
1066
for (i = 0; i < n; i++) {
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];
1077
//GST_ERROR("a %g %g %g b %g %g %g", ay, au, av, by, bu, bv);
1080
for (i = 0; i < 24; i++) {
1083
int py = detected_colors[i].y - 128;
1084
int pu = detected_colors[i].u - 128;
1085
int pv = detected_colors[i].v - 128;
1101
for (j = 0; j < n; j++) {
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));
1111
GST_ERROR ("average error %g", diff / 24.0);
1112
patchdetect->valid = 3000;
1115
if (patchdetect->valid > 0) {
1119
double *by = patchdetect->by;
1120
double *bu = patchdetect->bu;
1121
double *bv = patchdetect->bv;
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);
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];
1140
for (i = 0; i < frame.width; i++) {
1147
y = frame.y[(j + 0) * frame.ystride + i];
1169
for (k = 0; k < n; k++) {
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);
1179
y = frame.y[(j + 1) * frame.ystride + i];
1201
for (k = 0; k < n; k++) {
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);
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;
1233
gst_patchdetect_src_event (GstBaseTransform * trans, GstEvent * event)
1240
plugin_init (GstPlugin * plugin)
1243
gst_element_register (plugin, "patchdetect", GST_RANK_NONE,
1244
gst_patchdetect_get_type ());
1249
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1252
"patchdetect element",
1253
plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)