]> mj.ucw.cz Git - libucw.git/commitdiff
- reorganization of signatures code
authorPavel Charvat <pavel.charvat@netcentrum.cz>
Fri, 25 Aug 2006 11:43:30 +0000 (13:43 +0200)
committerPavel Charvat <pavel.charvat@netcentrum.cz>
Fri, 25 Aug 2006 11:43:30 +0000 (13:43 +0200)
- image-sim-test can display segmentations

images/image-sim-test.c
images/sig-init.c
images/sig-seg.c
images/signature.h

index f87298eb0737454236f83c6165e51c51377a069e..c58c9d08ed8ed1d399ec63c9e52af3440a780f87 100644 (file)
@@ -25,17 +25,19 @@ static void NONRET
 usage(void)
 {
   fputs("\
-Usage: image-sim-test [options] image1 image2 \n\
+Usage: image-sim-test [options] image1 [image2] \n\
 \n\
 -q --quiet           no progress messages\n\
 -f --format-1        image1 format (jpeg, gif, png)\n\
 -F --format-2        image2 format\n\
 -g --background      background color (hexadecimal RRGGBB)\n\
+-s --segmentation-1  writes image1 segmentation to given file\n\
+-S --segmentation-2  writes image2 segmentation to given file\n\
 ", stderr);
   exit(1);
 }
 
-static char *shortopts = "qf:F:g:t:" CF_SHORT_OPTS;
+static char *shortopts = "qf:F:g:t:s:S:" CF_SHORT_OPTS;
 static struct option longopts[] =
 {
   CF_LONG_OPTS
@@ -43,17 +45,22 @@ static struct option longopts[] =
   { "format-1",                0, 0, 'f' },
   { "format-2",                0, 0, 'F' },
   { "background",      0, 0, 'g' },
+  { "segmentation-1",  0, 0, 's' },
+  { "segmentation-2",  0, 0, 'S' },
   { NULL,              0, 0, 0 }
 };
-                                                         
+
 static uns verbose = 1;
 static byte *file_name_1;
 static byte *file_name_2;
 static enum image_format format_1;
 static enum image_format format_2;
 static struct color background_color;
+static byte *segmentation_name_1;
+static byte *segmentation_name_2;
 
 #define MSG(x...) do{ if (verbose) log(L_INFO, ##x); }while(0)
+#define TRY(x) do{ if (!(x)) die("Error: %s", it.err_msg); }while(0)
 
 static void
 dump_signature(struct image_signature *sig)
@@ -68,6 +75,56 @@ dump_signature(struct image_signature *sig)
     }
 }
 
+static struct image_thread it;
+static struct image_io io;
+
+static void
+write_segmentation(struct image_sig_data *data, byte *fn)
+{
+  MSG("Writing segmentation to %s", fn);
+  
+  struct fastbuf *fb = bopen(fn, O_WRONLY | O_CREAT | O_TRUNC, 4096);
+  struct image *img;
+  TRY(img = image_new(&it, data->image->cols, data->image->rows, COLOR_SPACE_RGB, NULL));
+  image_clear(&it, img);
+
+  for (uns i = 0; i < data->regions_count; i++)
+    {
+      byte c[3];
+      // FIXME: convert from Luv to RGB
+      c[0] = data->regions[i].a[0];
+      c[1] = data->regions[i].a[1];
+      c[2] = data->regions[i].a[2];
+      for (struct image_sig_block *block = data->regions[i].blocks; block; block = block->next)
+        {
+         uns x1 = block->x * 4;
+         uns y1 = block->y * 4;
+         uns x2 = MIN(x1 + 4, img->cols);
+         uns y2 = MIN(y1 + 4, img->rows);
+         byte *p = img->pixels + x1 * 3 + y1 * img->row_size;
+         for (uns y = y1; y < y2; y++, p += img->row_size)
+           {
+             byte *p2 = p;
+             for (uns x = x1; x < x2; x++, p2 += 3)
+               {
+                 p2[0] = c[0];
+                 p2[1] = c[1];
+                 p2[2] = c[2];
+               }
+           }
+        }
+    }
+
+  io.fastbuf = fb;
+  io.image = img;
+  io.format = image_file_name_to_format(fn); 
+  TRY(image_io_write(&io));
+  image_io_reset(&io);
+
+  image_destroy(img);
+  bclose(fb);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -99,69 +156,113 @@ main(int argc, char **argv)
            color_make_rgb(&background_color, (v >> 16) & 255, (v >> 8) & 255, v & 255);
          }
          break;
+       case 's':
+         segmentation_name_1 = optarg;
+         break;
+       case 'S':
+         segmentation_name_2 = optarg;
+         break;
        default:
          usage();
       }
 
-  if (argc != optind + 2)
+  if (argc != optind + 2 && argc != optind + 1)
     usage();
   file_name_1 = argv[optind++];
-  file_name_2 = argv[optind];
-  
-#define TRY(x) do{ if (!(x)) die("Error: %s", it.err_msg); }while(0)
+  if (argc > optind)
+    file_name_2 = argv[optind++];
+
   MSG("Initializing image library");
   srandom(time(NULL) ^ getpid());
   srgb_to_luv_init();
-  struct image_thread it;
-  struct image_io io;
   image_thread_init(&it);
 
   struct image *img1, *img2;
 
   if (!image_io_init(&it, &io))
     die("Cannot initialize image I/O (%s)", it.err_msg);
-  MSG("Reading %s", file_name_1);
-  io.fastbuf = bopen(file_name_1, O_RDONLY, 1 << 18);
-  io.format = format_1 ? : image_file_name_to_format(file_name_1);
-  TRY(image_io_read_header(&io));
-  io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
-  if (background_color.color_space)
-    io.background_color = background_color;
-  else if (!io.background_color.color_space)
-    io.background_color = color_black;
-  TRY(image_io_read_data(&io, 1));
-  bclose(io.fastbuf);
-  img1 = io.image;
-  MSG("Image size=%ux%u", img1->cols, img1->rows);
-  
-  image_io_reset(&io);
-  MSG("Reading %s", file_name_2);
-  io.fastbuf = bopen(file_name_2, O_RDONLY, 1 << 18);
-  io.format = format_2 ? : image_file_name_to_format(file_name_2);
-  TRY(image_io_read_header(&io));
-  io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
-  if (background_color.color_space)
-    io.background_color = background_color;
-  else if (!io.background_color.color_space)
-    io.background_color = color_black;
-  TRY(image_io_read_data(&io, 1));
-  bclose(io.fastbuf);
-  img2 = io.image;
-  image_io_cleanup(&io);
-  MSG("Image size=%ux%u", img2->cols, img2->rows);
 
-  MSG("Computing signatures");
+  if (file_name_1)
+    {
+      MSG("Reading %s", file_name_1);
+      io.fastbuf = bopen(file_name_1, O_RDONLY, 1 << 18);
+      io.format = format_1 ? : image_file_name_to_format(file_name_1);
+      TRY(image_io_read_header(&io));
+      io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
+      if (background_color.color_space)
+        io.background_color = background_color;
+      else if (!io.background_color.color_space)
+        io.background_color = color_black;
+      TRY(image_io_read_data(&io, 1));
+      bclose(io.fastbuf);
+      img1 = io.image;
+      MSG("Image size=%ux%u", img1->cols, img1->rows);
+      image_io_reset(&io);
+    }
+  else
+    img1 = NULL;
+
+  if (file_name_2)
+    {
+      MSG("Reading %s", file_name_2);
+      io.fastbuf = bopen(file_name_2, O_RDONLY, 1 << 18);
+      io.format = format_2 ? : image_file_name_to_format(file_name_2);
+      TRY(image_io_read_header(&io));
+      io.flags = COLOR_SPACE_RGB | IMAGE_IO_USE_BACKGROUND;
+      if (background_color.color_space)
+        io.background_color = background_color;
+      else if (!io.background_color.color_space)
+        io.background_color = color_black;
+      TRY(image_io_read_data(&io, 1));
+      bclose(io.fastbuf);
+      img2 = io.image;
+      MSG("Image size=%ux%u", img2->cols, img2->rows);
+      image_io_reset(&io);
+    }
+  else
+    img2 = NULL;
+
   struct image_signature sig1, sig2;
-  TRY(compute_image_signature(&it, &sig1, img1));
-  TRY(compute_image_signature(&it, &sig2, img2));
-  dump_signature(&sig1);
-  dump_signature(&sig2);
+  MSG("Computing signatures");
+  if (img1)
+    {
+      struct image_sig_data data;
+      TRY(image_sig_init(&it, &data, img1));
+      image_sig_preprocess(&data);
+      if (data.valid)
+       image_sig_segmentation(&data);
+      if (segmentation_name_1)
+       write_segmentation(&data, segmentation_name_1);
+      image_sig_finish(&data, &sig1);
+      image_sig_cleanup(&data);
+      dump_signature(&sig1);
+    }
+  if (img2)
+    {
+      struct image_sig_data data;
+      TRY(image_sig_init(&it, &data, img2));
+      image_sig_preprocess(&data);
+      if (data.valid)
+       image_sig_segmentation(&data);
+      if (segmentation_name_2)
+       write_segmentation(&data, segmentation_name_2);
+      image_sig_finish(&data, &sig2);
+      image_sig_cleanup(&data);
+      dump_signature(&sig2);
+    }
 
-  uns dist = image_signatures_dist(&sig1, &sig2);
-  MSG("dist=%.6f", dist / (double)(1 << IMAGE_SIG_DIST_SCALE));
-  
-  image_destroy(img1);
-  image_destroy(img2);
+  if (img1 && img2)
+    {
+      uns dist = image_signatures_dist(&sig1, &sig2);
+      MSG("dist=%.6f", dist / (double)(1 << IMAGE_SIG_DIST_SCALE));
+    }
+
+  if (img1)
+    image_destroy(img1);
+  if (img2)
+    image_destroy(img2);
+
+  image_io_cleanup(&io);
   image_thread_cleanup(&it);
   MSG("Done.");
   return 0;
index 6b99e34309a51253582bce21b621c7aa25bdec65..2c6ca2d4425e9a56639b4b286a37c228a6b8d127 100644 (file)
@@ -13,7 +13,6 @@
 #include "lib/math.h"
 #include "lib/fastbuf.h"
 #include "lib/conf.h"
-#include "lib/heap.h"
 #include "images/math.h"
 #include "images/images.h"
 #include "images/color.h"
 
 #include <alloca.h>
 
-static double image_sig_inertia_scale[3] = { 3, 1, 0.3 };
-
-struct block {
-  u32 area;            /* block area in pixels (usually 16) */
-  u32 v[IMAGE_VEC_F];
-  u32 x, y;            /* block position */
-  struct block *next;
-};
-
 int
-compute_image_signature(struct image_thread *thread UNUSED, struct image_signature *sig, struct image *image)
+image_sig_init(struct image_thread *thread UNUSED, struct image_sig_data *data, struct image *image)
 {
-  bzero(sig, sizeof(*sig));
   ASSERT((image->flags & IMAGE_PIXEL_FORMAT) == COLOR_SPACE_RGB);
-  uns cols = image->cols;
-  uns rows = image->rows;
-  uns row_size = image->row_size;
-
-  uns w = (cols + 3) >> 2;
-  uns h = (rows + 3) >> 2;
-
-  DBG("Computing signature for image of %ux%u pixels (%ux%u blocks)", cols, rows, w, h);
+  data->image = image;
+  data->cols = (image->cols + 3) >> 2;
+  data->rows = (image->rows + 3) >> 2;
+  data->full_cols = image->cols >> 2;
+  data->full_rows = image->rows >> 2;
+  data->blocks_count = data->cols * data->rows;
+  data->blocks = xmalloc(data->blocks_count * sizeof(struct image_sig_block));
+  data->area = image->cols * image->rows;
+  DBG("Computing signature for image of %ux%u pixels (%ux%u blocks)",
+      image->cols, image->rows, data->cols, data->rows);
+  return 1;
+}
 
-  uns blocks_count = w * h;
-  struct image_sig_block *blocks = xmalloc(blocks_count * sizeof(struct image_sig_block)), *block = blocks;
+void
+image_sig_preprocess(struct image_sig_data *data)
+{
+  struct image *image = data->image;
+  struct image_sig_block *block = data->blocks;
+  uns sum[IMAGE_VEC_F];
+  bzero(sum, sizeof(sum));
 
   /* Every block of 4x4 pixels */
   byte *row_start = image->pixels;
-  for (uns block_y = 0; block_y < h; block_y++, row_start += row_size * 4)
+  for (uns block_y = 0; block_y < data->rows; block_y++, row_start += image->row_size * 4)
     {
       byte *p = row_start;
-      for (uns block_x = 0; block_x < w; block_x++, p += 12, block++)
+      for (uns block_x = 0; block_x < data->cols; block_x++, p += 12, block++)
         {
           int t[16], s[16], *tp = t;
          block->x = block_x;
          block->y = block_y;
 
          /* Convert pixels to Luv color space and compute average coefficients */
-         uns l_sum = 0;
-         uns u_sum = 0;
-         uns v_sum = 0;
+         uns l_sum = 0, u_sum = 0, v_sum = 0;
          byte *p2 = p;
-         if ((!(cols & 3) || block_x < w - 1) && (!(rows & 3) || block_y < h - 1))
+         if (block_x < data->full_cols && block_y < data->full_rows)
            {
-             for (uns y = 0; y < 4; y++, p2 += row_size - 12)
+             for (uns y = 0; y < 4; y++, p2 += image->row_size - 12)
                for (uns x = 0; x < 4; x++, p2 += 3)
                  {
                    byte luv[3];
@@ -75,6 +71,9 @@ compute_image_signature(struct image_thread *thread UNUSED, struct image_signatu
                    v_sum += luv[2];
                  }
              block->area = 16;
+             sum[0] += l_sum;
+             sum[1] += u_sum;
+             sum[2] += v_sum;
              block->v[0] = (l_sum >> 4);
              block->v[1] = (u_sum >> 4);
              block->v[2] = (v_sum >> 4);
@@ -83,9 +82,9 @@ compute_image_signature(struct image_thread *thread UNUSED, struct image_signatu
          else
            {
              uns x, y;
-             uns square_cols = (block_x < w - 1 || !(cols & 3)) ? 4 : cols & 3;
-             uns square_rows = (block_y < h - 1 || !(rows & 3)) ? 4 : rows & 3;
-             for (y = 0; y < square_rows; y++, p2 += row_size)
+             uns square_cols = (block_x < data->full_cols) ? 4 : image->cols & 3;
+             uns square_rows = (block_y < data->full_rows) ? 4 : image->rows & 3;
+             for (y = 0; y < square_rows; y++, p2 += image->row_size)
                {
                  byte *p3 = p2;
                  for (x = 0; x < square_cols; x++, p3 += 3)
@@ -109,10 +108,13 @@ compute_image_signature(struct image_thread *thread UNUSED, struct image_signatu
                    tp++;
                  }
              block->area = square_cols * square_rows;
-             uns div = 0x10000 / block->area;
-             block->v[0] = (l_sum * div) >> 16;
-             block->v[1] = (u_sum * div) >> 16;
-             block->v[2] = (v_sum * div) >> 16;
+             uns inv = 0x10000 / block->area;
+             sum[0] += l_sum;
+             sum[1] += u_sum;
+             sum[2] += v_sum;
+             block->v[0] = (l_sum * inv) >> 16;
+             block->v[1] = (u_sum * inv) >> 16;
+             block->v[2] = (v_sum * inv) >> 16;
            }
 
          /* Apply Daubechies wavelet transformation */
@@ -150,50 +152,44 @@ compute_image_signature(struct image_thread *thread UNUSED, struct image_signatu
          block->v[3] = fast_sqrt_u16(isqr(t[8]) + isqr(t[9]) + isqr(t[12]) + isqr(t[13]));
          block->v[4] = fast_sqrt_u16(isqr(t[2]) + isqr(t[3]) + isqr(t[6]) + isqr(t[7]));
          block->v[5] = fast_sqrt_u16(isqr(t[10]) + isqr(t[11]) + isqr(t[14]) + isqr(t[15]));
+         sum[3] += block->v[3] * block->area;
+         sum[4] += block->v[4] * block->area;
+         sum[5] += block->v[5] * block->area;
         }
     }
 
-  /* FIXME: simple average is for testing pusposes only */
-  uns l_sum = 0;
-  uns u_sum = 0;
-  uns v_sum = 0;
-  uns lh_sum = 0;
-  uns hl_sum = 0;
-  uns hh_sum = 0;
-  for (uns i = 0; i < blocks_count; i++)
-    {
-      l_sum += blocks[i].v[0];
-      u_sum += blocks[i].v[1];
-      v_sum += blocks[i].v[2];
-      lh_sum += blocks[i].v[3];
-      hl_sum += blocks[i].v[4];
-      hh_sum += blocks[i].v[5];
-    }
-
-  sig->vec.f[0] = l_sum / blocks_count;
-  sig->vec.f[1] = u_sum / blocks_count;
-  sig->vec.f[2] = v_sum / blocks_count;
-  sig->vec.f[3] = lh_sum / blocks_count;
-  sig->vec.f[4] = hl_sum / blocks_count;
-  sig->vec.f[5] = hh_sum / blocks_count;
+  /* Compute featrures average */
+  uns inv = 0xffffffffU / data->area;
+  for (uns i = 0; i < IMAGE_VEC_F; i++)
+    data->f[i] = ((u64)sum[i] * inv) >> 32;
 
-  if (cols < image_sig_min_width || rows < image_sig_min_height)
+  if (image->cols < image_sig_min_width || image->rows < image_sig_min_height)
     {
-      xfree(blocks);
-      return 1;
+      data->valid = 0;
+      data->regions_count = 0;
     }
+  else
+    data->valid = 1;
+}
 
-  /* Quantize blocks to image regions */
-  struct image_sig_region regions[IMAGE_REG_MAX];
-  sig->len = image_sig_segmentation(blocks, blocks_count, regions);
+static double image_sig_inertia_scale[3] = { 3, 1, 0.3 };
 
+void
+image_sig_finish(struct image_sig_data *data, struct image_signature *sig)
+{
+  for (uns i = 0; i < IMAGE_VEC_F; i++)
+    sig->vec.f[i] = data->f[i];
+  sig->len = data->regions_count;
+  if (!sig->len)
+    return;
+  
   /* For each region */
   u64 w_total = 0;
-  uns w_border = (MIN(w, h) + 3) / 4;
+  uns w_border = (MIN(data->cols, data->rows) + 3) / 4;
   uns w_mul = 127 * 256 / w_border;
   for (uns i = 0; i < sig->len; i++)
     {
-      struct image_sig_region *r = regions + i;
+      struct image_sig_region *r = data->regions + i;
       DBG("Processing region %u: count=%u", i, r->count);
       ASSERT(r->count);
 
@@ -213,8 +209,8 @@ compute_image_signature(struct image_thread *thread UNUSED, struct image_signatu
          y_avg += b->y;
          uns d = b->x;
          d = MIN(d, b->y);
-         d = MIN(d, w - b->x - 1);
-         d = MIN(d, h - b->y - 1);
+         d = MIN(d, data->cols - b->x - 1);
+         d = MIN(d, data->rows - b->y - 1);
          if (d >= w_border)
            w_sum += 128;
          else
@@ -275,8 +271,8 @@ compute_image_signature(struct image_thread *thread UNUSED, struct image_signatu
   uns wa = 128, wb = 128;
   for (uns i = sig->len; --i > 0; )
     {
-      struct image_sig_region *r = regions + i;
-      wa -= sig->reg[i].wa = CLAMP(r->count * 128 / blocks_count, 1, (int)(wa - i));
+      struct image_sig_region *r = data->regions + i;
+      wa -= sig->reg[i].wa = CLAMP(r->count * 128 / data->blocks_count, 1, (int)(wa - i));
       wb -= sig->reg[i].wb = CLAMP(r->w_sum * 128 / w_total, 1, (int)(wa - i));
     }
   sig->reg[0].wa = wa;
@@ -291,9 +287,23 @@ compute_image_signature(struct image_thread *thread UNUSED, struct image_signatu
       DBG("region %u: features=%s", i, buf);
     }
 #endif
+}
 
-  xfree(blocks);
-
-  return 1;
+void
+image_sig_cleanup(struct image_sig_data *data)
+{
+  xfree(data->blocks);
 }
 
+int
+compute_image_signature(struct image_thread *thread, struct image_signature *sig, struct image *image)
+{
+  struct image_sig_data data;
+  if (!image_sig_init(thread, &data, image))
+    return 0;
+  image_sig_preprocess(&data);
+  if (data.valid)
+    image_sig_segmentation(&data);
+  image_sig_finish(&data, sig);
+  image_sig_cleanup(&data);
+}
index 7bd2db01cf54a26ecad0118d64be5c0ba3a9779d..948305735ce39e68df08b70a3a1f75891ae073b0 100644 (file)
@@ -301,18 +301,16 @@ postquant(struct image_sig_block *blocks, uns blocks_count, struct image_sig_reg
   return regions_end - regions;
 }
 
-uns
-image_sig_segmentation(struct image_sig_block *blocks, uns blocks_count, struct image_sig_region *regions)
+void
+image_sig_segmentation(struct image_sig_data *data)
 {
-  uns regions_count;
-  regions_count = prequant(blocks, blocks_count, regions);
+  data->regions_count = prequant(data->blocks, data->blocks_count, data->regions);
 #ifdef LOCAL_DEBUG
-  dump_segmentation(regions, regions_count);
+  dump_segmentation(data->regions, data->regions_count);
 #endif
-  regions_count = postquant(blocks, blocks_count, regions, regions_count);
+  data->regions_count = postquant(data->blocks, data->blocks_count, data->regions, data->regions_count);
 #ifdef LOCAL_DEBUG
-  dump_segmentation(regions, regions_count);
+  dump_segmentation(data->regions, data->regions_count);
 #endif
-  return regions_count;
 }
 
index 544526387cfc6583373bf478bc5ca446f41ce70f..3511f914fbb728a2856562c9ab8c09ed8d3240af 100644 (file)
@@ -64,14 +64,34 @@ struct image_sig_region {
   u64 w_sum;
 };
 
-/* sig-seg.c */
-
-uns image_sig_segmentation(struct image_sig_block *blocks, uns blocks_count, struct image_sig_region *regions);
+struct image_sig_data {
+  struct image *image;
+  struct image_sig_block *blocks;
+  struct image_sig_region regions[IMAGE_REG_MAX];
+  u32 cols;
+  u32 rows;
+  u32 full_cols;
+  u32 full_rows;
+  u32 area;
+  u32 valid;
+  u32 blocks_count;
+  u32 regions_count;
+  u32 f[IMAGE_VEC_F];
+};
 
 /* sig-init.c */
 
 int compute_image_signature(struct image_thread *thread, struct image_signature *sig, struct image *image);
 
+int image_sig_init(struct image_thread *thread, struct image_sig_data *data, struct image *image);
+void image_sig_preprocess(struct image_sig_data *data);
+void image_sig_finish(struct image_sig_data *data, struct image_signature *sig);
+void image_sig_cleanup(struct image_sig_data *data);
+
+/* sig-seg.c */
+
+void image_sig_segmentation(struct image_sig_data *data);
+
 /* sig-cmp.c */
 
 #define IMAGE_SIG_DIST_SCALE (3 + 3 + 8 + 16)