2005-07-08 07:45:38 +08:00
|
|
|
/*
|
2005-07-08 07:48:58 +08:00
|
|
|
* The GIMP Foreground Extraction Utility
|
2005-07-08 07:45:38 +08:00
|
|
|
* segmentator.c - main algorithm.
|
|
|
|
*
|
|
|
|
* For algorithm documentation refer to:
|
2005-07-08 07:48:58 +08:00
|
|
|
* G. Friedland, K. Jantz, L. Knipping, R. Rojas:
|
|
|
|
* "Image Segmentation by Uniform Color Clustering
|
|
|
|
* -- Approach and Benchmark Results",
|
|
|
|
* Technical Report B-05-07, Department of Computer Science,
|
|
|
|
* Freie Universitaet Berlin, June 2005.
|
2005-07-08 07:45:38 +08:00
|
|
|
* http://www.inf.fu-berlin.de/inst/pubs/tr-b-05-07.pdf
|
2005-07-08 07:48:58 +08:00
|
|
|
*
|
|
|
|
* Algorithm idea by Gerald Friedland.
|
|
|
|
* This implementation is Copyright (C) 2005
|
|
|
|
* by Gerald Friedland <fland@inf.fu-berlin.de>
|
|
|
|
* and Kristian Jantz <jantz@inf.fu-berlin.de>.
|
|
|
|
*
|
2005-07-08 07:45:38 +08:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2005-07-08 07:48:58 +08:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301, USA.
|
2005-07-08 07:45:38 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2005-07-08 07:48:58 +08:00
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <glib-object.h>
|
|
|
|
|
2005-07-08 07:45:38 +08:00
|
|
|
#include "segmentator.h"
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
/* Please look all the way down for an explanation of JNI_COMPILE.
|
|
|
|
*/
|
|
|
|
#ifdef JNI_COMPILE
|
|
|
|
#include "NativeExperimentalPipe.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2005-07-08 07:45:38 +08:00
|
|
|
/* Simulate a java.util.ArrayList */
|
|
|
|
/* These methods are NOT generic */
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
float l;
|
|
|
|
float a;
|
|
|
|
float b;
|
|
|
|
int cardinality;
|
2005-07-08 07:45:38 +08:00
|
|
|
} lab;
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
typedef struct _ArrayList ArrayList;
|
2005-07-08 07:45:38 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
struct _ArrayList
|
|
|
|
{
|
|
|
|
lab *array;
|
2005-07-09 06:33:18 +08:00
|
|
|
guint arraylength;
|
|
|
|
gboolean owned;
|
2005-07-08 07:48:58 +08:00
|
|
|
ArrayList *next;
|
|
|
|
};
|
2005-07-08 07:45:38 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
2005-07-09 05:24:55 +08:00
|
|
|
add_to_list (ArrayList *list,
|
2005-07-09 06:33:18 +08:00
|
|
|
lab *array,
|
|
|
|
guint arraylength,
|
|
|
|
gboolean take)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
ArrayList *cur = list;
|
|
|
|
ArrayList *prev;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
prev = cur;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
while (cur);
|
|
|
|
|
|
|
|
prev->next = g_new0 (ArrayList, 1);
|
|
|
|
|
2005-07-09 06:33:18 +08:00
|
|
|
prev->array = array;
|
|
|
|
prev->arraylength = arraylength;
|
|
|
|
prev->owned = take;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
static int
|
2005-07-09 05:24:55 +08:00
|
|
|
list_size (ArrayList *list)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
ArrayList *cur = list;
|
2005-07-09 03:42:29 +08:00
|
|
|
int count = 0;
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
while (cur->array)
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
static lab *
|
2005-07-09 05:24:55 +08:00
|
|
|
list_to_array (ArrayList *list,
|
|
|
|
int *returnlength)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
ArrayList *cur = list;
|
|
|
|
lab *arraytoreturn;
|
2005-07-09 03:42:29 +08:00
|
|
|
int i = 0;
|
|
|
|
int len;
|
2005-07-08 07:48:58 +08:00
|
|
|
|
2005-07-09 05:24:55 +08:00
|
|
|
len = list_size (list);
|
2005-07-08 07:48:58 +08:00
|
|
|
arraytoreturn = g_new (lab, len);
|
2005-07-09 05:24:55 +08:00
|
|
|
*returnlength = len;
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
while (cur->array)
|
|
|
|
{
|
|
|
|
arraytoreturn[i++] = cur->array[0];
|
2005-07-09 05:24:55 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
/* Every array in the list node has only one point
|
|
|
|
* when we call this method
|
|
|
|
*/
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return arraytoreturn;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
2005-07-09 06:33:18 +08:00
|
|
|
free_list (ArrayList *list)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
ArrayList *cur = list;
|
|
|
|
|
2005-07-09 05:24:55 +08:00
|
|
|
while (cur)
|
2005-07-08 07:48:58 +08:00
|
|
|
{
|
2005-07-09 05:24:55 +08:00
|
|
|
ArrayList *prev = cur;
|
2005-07-08 07:48:58 +08:00
|
|
|
|
2005-07-09 05:24:55 +08:00
|
|
|
cur = cur->next;
|
2005-07-08 07:48:58 +08:00
|
|
|
|
2005-07-09 06:33:18 +08:00
|
|
|
if (prev->owned)
|
|
|
|
g_free (prev->array);
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
g_free (prev);
|
2005-07-09 05:24:55 +08:00
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* RGB -> CIELAB and other interesting methods... */
|
|
|
|
|
2005-07-09 07:58:45 +08:00
|
|
|
#ifdef JNI_COMPILE
|
|
|
|
|
|
|
|
/* Java */
|
|
|
|
static guchar getRed (int rgb)
|
|
|
|
{
|
|
|
|
return (rgb >> 16) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static guchar getGreen (int rgb)
|
|
|
|
{
|
|
|
|
return (rgb >> 8) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static guchar getBlue (int rgb)
|
|
|
|
{
|
|
|
|
return (rgb) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* GIMP */
|
2005-07-08 07:48:58 +08:00
|
|
|
static guchar getRed (guint rgb)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
return (rgb) & 0xFF;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
static guchar getGreen (guint rgb)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
return (rgb >> 8) & 0xFF;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
static guchar getBlue (guint rgb)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-09 07:58:45 +08:00
|
|
|
return (rgb >> 16) & 0xFF;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-09 07:58:45 +08:00
|
|
|
#endif
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
#if 0
|
|
|
|
static guchar getAlpha (guint rgb)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
return (rgb >> 24) & 0xFF;
|
|
|
|
}
|
|
|
|
#endif
|
2005-07-08 07:45:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* Gets an int containing rgb, and an lab struct */
|
2005-07-09 06:33:18 +08:00
|
|
|
static lab *
|
|
|
|
calcLAB (guint rgb,
|
|
|
|
lab *newpixel)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
float var_R = (getRed (rgb) / 255.0);
|
|
|
|
float var_G = (getGreen (rgb) / 255.0);
|
|
|
|
float var_B = (getBlue (rgb) / 255.0);
|
|
|
|
|
|
|
|
float X, Y, Z, var_X, var_Y, var_Z;
|
|
|
|
|
|
|
|
if (var_R > 0.04045)
|
|
|
|
var_R = (float) pow ((var_R + 0.055) / 1.055, 2.4);
|
|
|
|
else
|
|
|
|
var_R = var_R / 12.92;
|
|
|
|
|
|
|
|
if (var_G > 0.04045)
|
|
|
|
var_G = (float) pow ((var_G + 0.055) / 1.055, 2.4);
|
|
|
|
else
|
|
|
|
var_G = var_G / 12.92;
|
|
|
|
|
|
|
|
if (var_B > 0.04045)
|
|
|
|
var_B = (float) pow ((var_B + 0.055) / 1.055, 2.4);
|
|
|
|
else
|
|
|
|
var_B = var_B / 12.92;
|
|
|
|
|
|
|
|
var_R = var_R * 100.0;
|
|
|
|
var_G = var_G * 100.0;
|
|
|
|
var_B = var_B * 100.0;
|
|
|
|
|
|
|
|
/* Observer. = 2°, Illuminant = D65 */
|
|
|
|
X = (float) (var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805);
|
|
|
|
Y = (float) (var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722);
|
|
|
|
Z = (float) (var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505);
|
|
|
|
|
|
|
|
var_X = X / 95.047; /* Observer = 2, Illuminant = D65 */
|
|
|
|
var_Y = Y / 100.0;
|
|
|
|
var_Z = Z / 108.883;
|
|
|
|
|
|
|
|
if (var_X > 0.008856)
|
|
|
|
var_X = (float) pow (var_X, (1.0 / 3));
|
|
|
|
else
|
|
|
|
var_X = (7.787 * var_X) + (16.0 / 116);
|
|
|
|
|
|
|
|
if (var_Y > 0.008856)
|
|
|
|
var_Y = (float) pow (var_Y, (1.0 / 3));
|
|
|
|
else
|
|
|
|
var_Y = (7.787 * var_Y) + (16.0 / 116);
|
|
|
|
|
|
|
|
if (var_Z > 0.008856)
|
|
|
|
var_Z = (float) pow (var_Z, (1.0 / 3));
|
|
|
|
else
|
|
|
|
var_Z = (7.787 * var_Z) + (16.0 / 116);
|
|
|
|
|
|
|
|
newpixel->l = (116 * var_Y) - 16;
|
|
|
|
newpixel->a = 500 * (var_X - var_Y);
|
|
|
|
newpixel->b = 200 * (var_Y - var_Z);
|
|
|
|
|
|
|
|
return newpixel;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
#if 0
|
|
|
|
static float cie_f (float t)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
return t > 0.008856 ? (1 / 3.0) : 7.787 * t + 16.0 / 116.0;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
2005-07-08 07:48:58 +08:00
|
|
|
#endif
|
2005-07-08 07:45:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* Stage one of modified KD-Tree algorithm */
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
|
|
|
stageone (lab *points,
|
|
|
|
int dims,
|
|
|
|
int depth,
|
|
|
|
ArrayList *clusters,
|
|
|
|
float limits[DIMS],
|
|
|
|
int length)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
int curdim = depth % dims;
|
|
|
|
float min, max;
|
|
|
|
/* find maximum and minimum */
|
|
|
|
int i, countsm, countgr, smallc, bigc;
|
|
|
|
float pivotvalue, curval;
|
|
|
|
lab *smallerpoints;
|
|
|
|
lab *biggerpoints;
|
|
|
|
|
|
|
|
if (length < 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[0].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[0].a;
|
|
|
|
else
|
|
|
|
curval = points[0].b;
|
|
|
|
|
|
|
|
min = curval;
|
|
|
|
max = curval;
|
|
|
|
|
|
|
|
for (i = 1; i < length; i++)
|
|
|
|
{
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[i].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[i].a;
|
|
|
|
else if (curdim == 2)
|
|
|
|
curval = points[i].b;
|
|
|
|
|
|
|
|
if (min > curval)
|
|
|
|
min = curval;
|
2005-07-08 07:45:38 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
if (max < curval)
|
|
|
|
max = curval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Split according to Rubner-Rule */
|
|
|
|
if (max - min > limits[curdim])
|
|
|
|
{
|
|
|
|
pivotvalue = ((max - min) / 2.0) + min;
|
|
|
|
countsm = 0;
|
|
|
|
countgr = 0;
|
|
|
|
|
|
|
|
/* find out cluster sizes */
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[i].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[i].a;
|
|
|
|
else if (curdim == 2)
|
|
|
|
curval = points[i].b;
|
|
|
|
|
|
|
|
if (curval <= pivotvalue)
|
|
|
|
{
|
|
|
|
countsm++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
countgr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
smallerpoints = g_new (lab, countsm);
|
|
|
|
biggerpoints = g_new (lab, countgr);
|
|
|
|
smallc = 0;
|
|
|
|
bigc = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{ /* do actual split */
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[i].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[i].a;
|
|
|
|
else if (curdim == 2)
|
|
|
|
curval = points[i].b;
|
|
|
|
|
|
|
|
if (curval <= pivotvalue)
|
|
|
|
{
|
|
|
|
smallerpoints[smallc++] = points[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
biggerpoints[bigc++] = points[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-09 06:33:18 +08:00
|
|
|
if (depth > 0)
|
|
|
|
g_free (points);
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
/* create subtrees */
|
|
|
|
stageone (smallerpoints, dims, depth + 1, clusters, limits, countsm);
|
|
|
|
stageone (biggerpoints, dims, depth + 1, clusters, limits, countgr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* create leave */
|
2005-07-09 06:33:18 +08:00
|
|
|
add_to_list (clusters, points, length, depth != 0);
|
2005-07-08 07:48:58 +08:00
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
|
2005-07-08 07:45:38 +08:00
|
|
|
/* Stage two of modified KD-Tree algorithm */
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
/* This is very similar to stageone... but in future there will be more
|
|
|
|
* differences => not integrated into method stageone()
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
stagetwo (lab *points,
|
|
|
|
int dims,
|
|
|
|
int depth,
|
|
|
|
ArrayList *clusters,
|
|
|
|
float limits[DIMS],
|
|
|
|
int length,
|
|
|
|
int total,
|
|
|
|
float threshold)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
int curdim = depth % dims;
|
|
|
|
float min, max;
|
|
|
|
/* find maximum and minimum */
|
|
|
|
int i, countsm, countgr, smallc, bigc;
|
|
|
|
float pivotvalue, curval;
|
|
|
|
int sum;
|
|
|
|
lab *point;
|
|
|
|
lab *smallerpoints;
|
|
|
|
lab *biggerpoints;
|
|
|
|
|
|
|
|
if (length < 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[0].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[0].a;
|
|
|
|
else
|
|
|
|
curval = points[0].b;
|
|
|
|
|
|
|
|
min = curval;
|
|
|
|
max = curval;
|
|
|
|
|
|
|
|
for (i = 1; i < length; i++)
|
|
|
|
{
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[i].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[i].a;
|
|
|
|
else if (curdim == 2)
|
|
|
|
curval = points[i].b;
|
|
|
|
|
|
|
|
if (min > curval)
|
|
|
|
min = curval;
|
|
|
|
|
|
|
|
if (max < curval)
|
|
|
|
max = curval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Split according to Rubner-Rule */
|
|
|
|
if (max - min > limits[curdim])
|
|
|
|
{
|
|
|
|
pivotvalue = ((max - min) / 2.0) + min;
|
|
|
|
|
|
|
|
/* g_printerr ("max=%f min=%f pivot=%f\n",max,min,pivotvalue); */
|
|
|
|
countsm = 0;
|
|
|
|
countgr = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{ /* find out cluster sizes */
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[i].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[i].a;
|
|
|
|
else if (curdim == 2)
|
|
|
|
curval = points[i].b;
|
|
|
|
|
|
|
|
if (curval <= pivotvalue)
|
|
|
|
{
|
|
|
|
countsm++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
countgr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-09 03:42:29 +08:00
|
|
|
smallerpoints = g_new (lab, countsm);
|
|
|
|
biggerpoints = g_new (lab, countgr);
|
2005-07-08 07:48:58 +08:00
|
|
|
smallc = 0;
|
|
|
|
bigc = 0;
|
|
|
|
|
|
|
|
/* do actual split */
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
if (curdim == 0)
|
|
|
|
curval = points[i].l;
|
|
|
|
else if (curdim == 1)
|
|
|
|
curval = points[i].a;
|
|
|
|
else if (curdim == 2)
|
|
|
|
curval = points[i].b;
|
|
|
|
|
|
|
|
if (curval <= pivotvalue)
|
|
|
|
{
|
|
|
|
smallerpoints[smallc++] = points[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
biggerpoints[bigc++] = points[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-09 05:24:55 +08:00
|
|
|
g_free (points);
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
/* create subtrees */
|
|
|
|
stagetwo (smallerpoints, dims, depth + 1, clusters, limits,
|
|
|
|
countsm, total, threshold);
|
|
|
|
stagetwo (biggerpoints, dims, depth + 1, clusters, limits,
|
|
|
|
countgr, total, threshold);
|
|
|
|
}
|
|
|
|
else /* create leave */
|
|
|
|
{
|
|
|
|
sum = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
sum += points[i].cardinality;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (((sum * 100.0) / total) >= threshold)
|
|
|
|
{
|
|
|
|
point = g_new0 (lab, 1);
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
point->l += points[i].l;
|
|
|
|
point->a += points[i].a;
|
|
|
|
point->b += points[i].b;
|
|
|
|
}
|
|
|
|
|
|
|
|
point->l /= (length * 1.0);
|
|
|
|
point->a /= (length * 1.0);
|
|
|
|
point->b /= (length * 1.0);
|
2005-07-09 03:42:29 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
/* g_printerr ("cluster=%f, %f, %f sum=%d\n",
|
|
|
|
point->l, point->a, point->b, sum);
|
|
|
|
*/
|
|
|
|
|
2005-07-09 06:33:18 +08:00
|
|
|
add_to_list (clusters, point, 1, TRUE);
|
2005-07-08 07:48:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free (points);
|
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* squared euclidean distance */
|
2005-07-08 07:48:58 +08:00
|
|
|
static inline float
|
|
|
|
euklid (const lab p,
|
|
|
|
const lab q)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
return ((p.l - q.l) * (p.l - q.l) +
|
|
|
|
(p.a - q.a) * (p.a - q.a) +
|
|
|
|
(p.b - q.b) * (p.b - q.b));
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Creates a color signature for a given set of pixels */
|
2005-07-08 07:48:58 +08:00
|
|
|
static lab *
|
2005-07-09 03:42:29 +08:00
|
|
|
create_signature (lab *input,
|
|
|
|
int length,
|
|
|
|
float limits[DIMS],
|
|
|
|
int *returnlength)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
ArrayList *clusters1;
|
|
|
|
ArrayList *clusters2;
|
|
|
|
ArrayList *curelem;
|
|
|
|
lab *centroids;
|
|
|
|
lab *cluster;
|
|
|
|
lab centroid;
|
|
|
|
lab *rval;
|
|
|
|
int k, i;
|
|
|
|
int clusters1size;
|
|
|
|
|
2005-07-09 06:33:18 +08:00
|
|
|
if (length < 1)
|
|
|
|
{
|
|
|
|
*returnlength = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
clusters1 = g_new0 (ArrayList, 1);
|
|
|
|
|
|
|
|
stageone (input, DIMS, 0, clusters1, limits, length);
|
2005-07-09 05:24:55 +08:00
|
|
|
clusters1size = list_size (clusters1);
|
2005-07-08 07:48:58 +08:00
|
|
|
centroids = g_new (lab, clusters1size);
|
|
|
|
curelem = clusters1;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (curelem->array)
|
|
|
|
{
|
|
|
|
centroid.l = 0;
|
|
|
|
centroid.a = 0;
|
|
|
|
centroid.b = 0;
|
|
|
|
cluster = curelem->array;
|
|
|
|
|
|
|
|
for (k = 0; k < curelem->arraylength; k++)
|
|
|
|
{
|
|
|
|
centroid.l += cluster[k].l;
|
|
|
|
centroid.a += cluster[k].a;
|
|
|
|
centroid.b += cluster[k].b;
|
|
|
|
}
|
|
|
|
|
|
|
|
centroids[i].l = centroid.l / (curelem->arraylength * 1.0);
|
|
|
|
centroids[i].a = centroid.a / (curelem->arraylength * 1.0);
|
|
|
|
centroids[i].b = centroid.b / (curelem->arraylength * 1.0);
|
|
|
|
centroids[i].cardinality = curelem->arraylength;
|
|
|
|
i++;
|
|
|
|
curelem = curelem->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* g_printerr ("step #1 -> %d clusters\n", clusters1size); */
|
|
|
|
|
|
|
|
clusters2 = g_new0 (ArrayList, 1);
|
|
|
|
|
2005-07-09 05:24:55 +08:00
|
|
|
stagetwo (centroids, DIMS, 0, clusters2, limits, clusters1size, length, 0.1);
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
/* see paper by tomasi */
|
2005-07-09 05:24:55 +08:00
|
|
|
rval = list_to_array (clusters2, returnlength);
|
2005-07-09 03:42:29 +08:00
|
|
|
|
2005-07-09 06:33:18 +08:00
|
|
|
free_list (clusters2);
|
|
|
|
free_list (clusters1);
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
/* g_printerr ("step #2 -> %d clusters\n", returnlength[0]); */
|
|
|
|
|
|
|
|
return rval;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Smoothes the confidence matrix */
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
|
|
|
smoothcm (float *cm,
|
|
|
|
int xres,
|
|
|
|
int yres,
|
|
|
|
float f1,
|
|
|
|
float f2,
|
|
|
|
float f3)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
int y, x, idx;
|
|
|
|
|
|
|
|
/* Smoothright */
|
|
|
|
for (y = 0; y < yres; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres - 2; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] =
|
|
|
|
f1 * cm[idx] +
|
|
|
|
f2 * cm[idx + 1] +
|
|
|
|
f3 * cm[idx + 2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Smoothleft */
|
|
|
|
for (y = 0; y < yres; y++)
|
|
|
|
{
|
|
|
|
for (x = xres - 1; x >= 2; x--)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] =
|
|
|
|
f3 * cm[idx - 2] +
|
|
|
|
f2 * cm[idx - 1] +
|
|
|
|
f1 * cm[idx];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Smoothdown */
|
|
|
|
for (y = 0; y < yres - 2; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] =
|
|
|
|
f1 * cm[idx] +
|
|
|
|
f2 * cm[((y + 1) * xres) + x] +
|
|
|
|
f3 * cm[((y + 2) * xres) + x];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Smoothup */
|
|
|
|
for (y = yres - 1; y >= 2; y--)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] =
|
|
|
|
f3 * cm[((y - 2) * xres) + x] +
|
|
|
|
f2 * cm[((y - 1) * xres) + x] +
|
|
|
|
f1 * cm[idx];
|
|
|
|
}
|
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Region growing */
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
|
|
|
findmaxblob (float *cm,
|
|
|
|
guint *image,
|
|
|
|
int xres,
|
|
|
|
int yres)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-09 05:24:55 +08:00
|
|
|
int i;
|
|
|
|
int curlabel = 1;
|
|
|
|
int maxregion = 0;
|
|
|
|
int maxblob = 0;
|
|
|
|
int regioncount = 0;
|
|
|
|
int pos = 0;
|
|
|
|
int length = xres * yres;
|
|
|
|
int *labelfield = g_new0 (int, length);
|
|
|
|
GQueue *q = g_queue_new ();
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
regioncount = 0;
|
2005-07-09 05:24:55 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
if (labelfield[i] == 0 && cm[i] >= 0.5)
|
2005-07-09 05:24:55 +08:00
|
|
|
g_queue_push_tail (q, GINT_TO_POINTER (i));
|
2005-07-08 07:48:58 +08:00
|
|
|
|
2005-07-09 05:24:55 +08:00
|
|
|
while (! g_queue_is_empty (q))
|
2005-07-08 07:48:58 +08:00
|
|
|
{
|
2005-07-09 05:24:55 +08:00
|
|
|
pos = GPOINTER_TO_INT (g_queue_pop_head (q));
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
if (pos < 0 || pos >= length)
|
2005-07-09 05:24:55 +08:00
|
|
|
continue;
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
if (labelfield[pos] == 0 && cm[pos] >= 0.5f)
|
|
|
|
{
|
|
|
|
labelfield[pos] = curlabel;
|
2005-07-09 05:24:55 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
regioncount++;
|
2005-07-09 05:24:55 +08:00
|
|
|
|
|
|
|
g_queue_push_tail (q, GINT_TO_POINTER (pos + 1));
|
|
|
|
g_queue_push_tail (q, GINT_TO_POINTER (pos - 1));
|
|
|
|
g_queue_push_tail (q, GINT_TO_POINTER (pos + xres));
|
|
|
|
g_queue_push_tail (q, GINT_TO_POINTER (pos - xres));
|
2005-07-08 07:48:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (regioncount > maxregion)
|
|
|
|
{
|
|
|
|
maxregion = regioncount;
|
|
|
|
maxblob = curlabel;
|
|
|
|
}
|
2005-07-09 05:24:55 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
curlabel++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{ /* Kill everything that is not biggest blob! */
|
|
|
|
if (labelfield[i] != 0 && labelfield[i] != maxblob)
|
|
|
|
{
|
|
|
|
cm[i] = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-09 05:24:55 +08:00
|
|
|
g_queue_free (q);
|
2005-07-09 03:42:29 +08:00
|
|
|
g_free (labelfield);
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Returns squared clustersize */
|
2005-07-08 07:48:58 +08:00
|
|
|
static float
|
|
|
|
getclustersize (float limits[DIMS])
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
float sum = (limits[0] - (-limits[0])) * (limits[0] - (-limits[0]));
|
|
|
|
|
|
|
|
sum += (limits[1] - (-limits[1])) * (limits[1] - (-limits[1]));
|
|
|
|
sum += (limits[2] - (-limits[2])) * (limits[2] - (-limits[2]));
|
|
|
|
|
|
|
|
return sum;
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2005-07-09 03:42:29 +08:00
|
|
|
/* calculates alpha \times Confidencematrix */
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
2005-07-09 03:42:29 +08:00
|
|
|
premultiply_matrix (float alpha,
|
|
|
|
float *cm,
|
|
|
|
int length)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
2005-07-09 05:24:55 +08:00
|
|
|
cm[i] = alpha * cm[i];
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Normalizes a confidencematrix */
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
2005-07-09 03:42:29 +08:00
|
|
|
normalize_matrix (float *cm,
|
|
|
|
int length)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
float max = 0.0;
|
|
|
|
float alpha = 0.0;
|
|
|
|
int i;
|
2005-07-08 07:45:38 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
if (max < cm[i])
|
|
|
|
max = cm[i];
|
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
|
2005-07-08 07:48:58 +08:00
|
|
|
if (max <= 0.0)
|
|
|
|
return;
|
|
|
|
if (max == 1.00)
|
|
|
|
return;
|
|
|
|
|
|
|
|
alpha = 1.00f / max;
|
2005-07-09 03:42:29 +08:00
|
|
|
premultiply_matrix (alpha, cm, length);
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* A confidence matrix eroder */
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
|
|
|
erode2 (float *cm,
|
|
|
|
int xres,
|
|
|
|
int yres)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
int idx, x, y;
|
|
|
|
|
|
|
|
/* From right */
|
|
|
|
for (y = 0; y < yres; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres - 1; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MIN (cm[idx], cm[idx + 1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* From left */
|
|
|
|
for (y = 0; y < yres; y++)
|
|
|
|
{
|
|
|
|
for (x = xres - 1; x >= 1; x--)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MIN (cm[idx - 1], cm[idx]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* From down */
|
|
|
|
for (y = 0; y < yres - 1; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MIN (cm[idx], cm[((y + 1) * xres) + x]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* From up */
|
|
|
|
for (y = yres - 1; y >= 1; y--)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MIN (cm[((y - 1) * xres) + x], cm[idx]);
|
|
|
|
}
|
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* A confidence matrix dilater */
|
2005-07-08 07:48:58 +08:00
|
|
|
static void
|
|
|
|
dilate2 (float *cm,
|
|
|
|
int xres,
|
|
|
|
int yres)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-08 07:48:58 +08:00
|
|
|
int x, y, idx;
|
|
|
|
|
|
|
|
/* From right */
|
|
|
|
for (y = 0; y < yres; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres - 1; x++) {
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MAX (cm[idx], cm[idx + 1]);
|
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
/* From left */
|
|
|
|
for (y = 0; y < yres; y++)
|
|
|
|
{
|
|
|
|
for (x = xres - 1; x >= 1; x--)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MAX (cm[idx - 1], cm[idx]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* From down */
|
|
|
|
for (y = 0; y < yres - 1; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MAX (cm[idx], cm[((y + 1) * xres) + x]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-08 07:45:38 +08:00
|
|
|
/* From up */
|
2005-07-08 07:48:58 +08:00
|
|
|
for (y = yres - 1; y >= 1; y--)
|
|
|
|
{
|
|
|
|
for (x = 0; x < xres; x++)
|
|
|
|
{
|
|
|
|
idx = (y * xres) + x;
|
|
|
|
cm[idx] = MAX (cm[((y - 1) * xres) + x], cm[idx]);
|
|
|
|
}
|
|
|
|
}
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Call this method:
|
|
|
|
* rgbs - the picture
|
2005-07-08 07:48:58 +08:00
|
|
|
* confidencematrix - a confidencematrix with values <=0.1 is sure background,
|
|
|
|
* >=0.9 is sure foreground, rest unknown
|
2005-07-08 07:45:38 +08:00
|
|
|
* xres, yres - the dimensions of the picture and the confidencematrix
|
2005-07-08 07:48:58 +08:00
|
|
|
* limits - a three dimensional float array specifing the accuracy
|
|
|
|
* a good value is: {0.66,1.25,2.5}
|
|
|
|
* int smoothness - specifies how smooth the boundaries of a picture should
|
|
|
|
* be made (value greater or equal to 0).
|
|
|
|
* More smooth = fault tolerant,
|
|
|
|
* less smooth = exact boundaries - try 3 for a first guess.
|
2005-07-08 07:45:38 +08:00
|
|
|
* returns and writes into the confidencematrix the resulting segmentation
|
|
|
|
*/
|
2005-07-08 07:48:58 +08:00
|
|
|
float *
|
|
|
|
segmentate (guint *rgbs,
|
|
|
|
float *confidencematrix,
|
|
|
|
int xres,
|
|
|
|
int yres,
|
|
|
|
float limits[DIMS],
|
|
|
|
int smoothness)
|
2005-07-08 07:45:38 +08:00
|
|
|
{
|
2005-07-09 03:42:29 +08:00
|
|
|
float clustersize = getclustersize (limits);
|
2005-07-08 07:48:58 +08:00
|
|
|
int length = xres * yres;
|
|
|
|
int surebgcount = 0, surefgcount = 0;
|
|
|
|
int i, k, j;
|
|
|
|
int bgsiglen, fgsiglen;
|
2005-07-09 05:24:55 +08:00
|
|
|
lab *surebg, *surefg, *bgsig, *fgsig = NULL;
|
2005-07-08 07:48:58 +08:00
|
|
|
char background = 0;
|
|
|
|
float min, d;
|
|
|
|
lab labpixel;
|
|
|
|
|
|
|
|
/* count given foreground and background pixels */
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
if (confidencematrix[i] <= 0.10f)
|
|
|
|
{
|
|
|
|
surebgcount++;
|
|
|
|
}
|
|
|
|
else if (confidencematrix[i] >= 0.90f)
|
|
|
|
{
|
|
|
|
surefgcount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
surebg = g_new (lab, surebgcount);
|
2005-07-09 05:24:55 +08:00
|
|
|
surefg = g_new (lab, surefgcount);
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
k = 0;
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
/* create inputs for colorsignatures */
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
if (confidencematrix[i] <= 0.10f)
|
|
|
|
{
|
|
|
|
calcLAB (rgbs[i], &surebg[k]);
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
else if (confidencematrix[i] >= 0.90f)
|
|
|
|
{
|
|
|
|
calcLAB (rgbs[i], &surefg[j]);
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create color signature for bg */
|
2005-07-09 03:42:29 +08:00
|
|
|
bgsig = create_signature (surebg, surebgcount, limits, &bgsiglen);
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
if (bgsiglen < 1)
|
|
|
|
return confidencematrix; /* No segmentation possible */
|
|
|
|
|
2005-07-09 06:33:18 +08:00
|
|
|
/* Create color signature for fg */
|
|
|
|
fgsig = create_signature (surefg, surefgcount, limits, &fgsiglen);
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
/* Classify - the slow way....Better: Tree traversation */
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
if (confidencematrix[i] >= 0.90)
|
|
|
|
{
|
|
|
|
confidencematrix[i] = 1.0f;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (confidencematrix[i] <= 0.10)
|
|
|
|
{
|
|
|
|
confidencematrix[i] = 0.0f;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
calcLAB (rgbs[i], &labpixel);
|
|
|
|
background = 1;
|
|
|
|
min = euklid (labpixel, bgsig[0]);
|
|
|
|
|
|
|
|
for (j = 1; j < bgsiglen; j++)
|
|
|
|
{
|
|
|
|
d = euklid(labpixel, bgsig[j]);
|
|
|
|
if (d < min)
|
|
|
|
{
|
|
|
|
min = d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fgsiglen == 0)
|
|
|
|
{
|
|
|
|
if (min < clustersize)
|
|
|
|
background = 1;
|
|
|
|
else
|
|
|
|
background = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (j = 0; j < fgsiglen; j++)
|
|
|
|
{
|
|
|
|
d = euklid (labpixel, fgsig[j]);
|
|
|
|
if (d < min)
|
|
|
|
{
|
|
|
|
min = d;
|
|
|
|
background = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (background == 0)
|
|
|
|
{
|
|
|
|
confidencematrix[i] = 1.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
confidencematrix[i] = 0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Smooth a bit for error killing */
|
|
|
|
smoothcm (confidencematrix, xres, yres, 0.33, 0.33, 0.33);
|
|
|
|
|
2005-07-09 03:42:29 +08:00
|
|
|
normalize_matrix (confidencematrix, length);
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
/* Now erode, to make sure only "strongly connected components"
|
|
|
|
* keep being connected
|
|
|
|
*/
|
|
|
|
erode2 (confidencematrix, xres, yres);
|
|
|
|
|
|
|
|
/* search the biggest connected component */
|
|
|
|
findmaxblob (confidencematrix, rgbs, xres, yres);
|
|
|
|
|
|
|
|
for (i = 0; i < smoothness; i++)
|
|
|
|
{
|
|
|
|
/* smooth again - as user specified */
|
|
|
|
smoothcm (confidencematrix, xres, yres, 0.33, 0.33, 0.33);
|
|
|
|
}
|
|
|
|
|
2005-07-09 03:42:29 +08:00
|
|
|
normalize_matrix (confidencematrix, length);
|
2005-07-08 07:48:58 +08:00
|
|
|
|
|
|
|
/* Threshold the values */
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
if (confidencematrix[i] >= 0.5)
|
|
|
|
confidencematrix[i] = 1.0;
|
|
|
|
else
|
|
|
|
confidencematrix[i] = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* search the biggest connected component again
|
|
|
|
to make sure jitter is killed
|
|
|
|
*/
|
|
|
|
findmaxblob (confidencematrix, rgbs, xres, yres);
|
|
|
|
|
|
|
|
/* Now dilate, to fill up boundary pixels killed by erode */
|
|
|
|
dilate2 (confidencematrix, xres, yres);
|
|
|
|
|
|
|
|
g_free (surefg);
|
|
|
|
g_free (surebg);
|
|
|
|
g_free (bgsig);
|
|
|
|
g_free (fgsig);
|
|
|
|
|
|
|
|
return confidencematrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* If JNI_COMPILE is defined, we provide a Java binding for the segmentate
|
|
|
|
* funtion. This allows me to use an existing benchmark as a unit test.
|
|
|
|
* The plan is to implement this test as a GIMP plug-in later. Until then,
|
|
|
|
* please leave this code in.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef JNI_COMPILE
|
|
|
|
JNIEXPORT void JNICALL Java_NativeExperimentalPipe_segmentate
|
|
|
|
(JNIEnv * env, jobject obj, jintArray rgbs, jfloatArray cm, jint xres,
|
|
|
|
jint yres, jfloatArray limits) {
|
|
|
|
jint *jrgbs = (*env)->GetIntArrayElements(env, rgbs, 0);
|
|
|
|
jfloat *jcm = (*env)->GetFloatArrayElements(env, cm, 0);
|
|
|
|
jfloat *jlimits = (*env)->GetFloatArrayElements(env, limits, 0);
|
|
|
|
segmentate(jrgbs, jcm, xres, yres, jlimits, 6);
|
|
|
|
(*env)->ReleaseFloatArrayElements(env, cm, jcm, 0);
|
2005-07-08 07:45:38 +08:00
|
|
|
}
|
2005-07-08 07:48:58 +08:00
|
|
|
#endif
|