Page 1 of 1

Feature request: invoke command for each pixel

Posted: 2014-09-08T08:49:30-07:00
by jpka
Hi.
I wonder if this is already solved, i can't find myself anything relevant.
I need a command-line way to divide image by pixels, and for each enumerated pixel started from (0,0) execute custom (my) command and pass parameters to it: x, y, r, g, b, h, s, v, alpha.
Something like

Code: Select all

convert --divide-and-execute "my.sh"
and if i feed image say 3 by 2 pixels and first pixel is red, 2nd is green, and 4 others are white, i should get six executed commands:

Code: Select all

my.sh 0 0 255 0 0 0 100 100 100
my.sh 1 0 0 255 0 120 100 100 100
my.sh 2 0 255 255 255 0 0 100 100
my.sh 0 1 255 255 255 0 0 100 100
my.sh 1 1 255 255 255 0 0 100 100
my.sh 2 1 255 255 255 0 0 100 100
This will become only cross-platform way to prepare .prn files for dot matrix printers, PCB files labeling/imaging, etc.
I already have my own simple parser, but it work only with RAW images.
And most important, this looks like not so hard to implement.
Thanks so much!

Re: Feature request: invoke command for each pixel

Posted: 2014-09-08T09:06:04-07:00
by snibgo
If you "-crop 1x1", you can apply any operating system commands you want to the individual pixels, one pixel per file.

Many image operations can be performed within ImageMagick using the "-fx" command.

You can write an image to a text file, and loop though that in a script.

Those methods are very slow when there are millions of pixels.

Or you can write C-language code to operate on individual pixels. These could, if you want, execute a system command for each pixel (again, probably very slow).

Can you give an example of what your my.sh might do?

Re: Feature request: invoke command for each pixel

Posted: 2014-09-08T14:13:10-07:00
by jpka
I already have C code that does my task, but it is not cross-platform, and can't work on any image format except straight RAW (and i of course use IM to get RAW from anything, it performs very vell). I probably can add header processing myself to recognize other files, but even better way (and it is what i ask) is glueless method: if IM can do the task in subject, it is all i need. And it is (for me) better than dump raw image to text file.
I am aware that running external script for each pixel is too slow, but it is (in my case) intended to very small images, and runtime not so important.

One example of "my.sh" file is something like this (i am sorry, it is not done yet so i put C equivalent) i.e. it is should processing coordinates and color and fill binary buffer, text file, or so, with data according to coordinates and color:

Code: Select all

fprintf(file2,"    (line (pt %.2f %.2f) (pt %.2f %.2f) (width %.2f) )\n", pax, pay, pbx, pby, pcblinewidth);
fprintf(file2,"    (line (pt %.2f %.2f) (pt %.2f %.2f) (width %.2f) )\n", pbx, pby, pcx, pcy, pcblinewidth);
fprintf(file2,"    (line (pt %.2f %.2f) (pt %.2f %.2f) (width %.2f) )\n", pcx, pcy, pdx, pdy, pcblinewidth);
fprintf(file2,"    (line (pt %.2f %.2f) (pt %.2f %.2f) (width %.2f) )\n", pdx, pdy, pax, pay, pcblinewidth);
which should give for each pixel, text output, something like

Code: Select all

    (line (pt 25.30 3.00) (pt 25.45 3.00) (width 0.15) )
    (line (pt 25.45 3.00) (pt 25.45 3.15) (width 0.15) )
    (line (pt 25.45 3.15) (pt 25.30 3.15) (width 0.15) )
    (line (pt 25.30 3.15) (pt 25.30 3.00) (width 0.15) )
and finally when put in PCB file, it looks like this automatic stamping (when finished in vector Gerber and ready to production):
Image
Thanks.

Re: Feature request: invoke command for each pixel

Posted: 2014-09-08T14:43:05-07:00
by snibgo
If you've already got C code that does what you want, the obvious solution is to create a process module. This requires that you compile IM yourself, which is simple with Cygwin under Windows, and probably just as simple in other environments.

See my page "Customising ImageMagick": http://im.snibgo.com/customim.htm . On that page, my module "dumpimage.c" is a close approximation to what you want.

Re: Feature request: invoke command for each pixel

Posted: 2014-09-11T13:18:40-07:00
by jpka
You have great well-commented article! Using it, i immediately write my filter, and it work (but slower than i expect).
The problem remains is i can't make it as new filter, it only works as substitute for original analyze.c... In hope of my filter can be included in maintream IM suite, i try to write new filter according to article. But i get massive errors with version incompatibility for automake and autoconf, and finally ended up with unrecoverable errors with automake. I have Ubuntu 12.04.5.
Filter code:

Code: Select all

/*
Dump And Execute - for EACH PIXEL of image, execute user command and pass to it
as much info as possible about that pixel. It is slow, and typically not
intended for more than 10K px images. Output: x y cols rows r g b alpha h s b.

example:
	convert rose: -process "analyze ./my.sh" not-used.png
example content of my.sh:
	echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11
	return 0 (optional)

author: jopka@kvidex.ru, www.bdyssh.ru

Based on: 
1.  analyze.c Copyright 1999-2014 ImageMagick Studio LLC, 
2.  http://im.snibgo.com/customim.htm Copyright © 2014 Alan Gibson
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "magick/MagickCore.h"

ModuleExport size_t analyzeImage(Image **images,const int argc,
  const char **argv,ExceptionInfo *exception)
{

  double
    brightness,
    hue,
    saturation;

  Image
    *image;

  int
    exitcode=0;

/*  int
    debug=0;  */

  char
    s[256];

  assert(images != (Image **) NULL);
  assert(*images != (Image *) NULL);
  assert((*images)->signature == MagickSignature);
  (void) argc;
  (void) argv;
  image=(*images);
  for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
  {
    CacheView
      *image_view;

    ssize_t
      y;

    MagickBooleanType
      status;

    status=MagickTrue;
    image_view=AcquireVirtualCacheView(image,exception);
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      register const PixelPacket
        *p;

      register ssize_t
        x;

      if (status == MagickFalse)
        continue;

p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
      if (p == (const PixelPacket *) NULL)
        {
          status=MagickFalse;
          continue;
        }
      for (x=0; x < (ssize_t) image->columns; x++)
      {
        ConvertRGBToHSB(GetPixelRed(p),GetPixelGreen(p),GetPixelBlue(p),
          &hue,&saturation,&brightness);
        p++;
/*	if (debug>0) printf("Pixel: x=%d y=%d cols=%d rows=%d r=%d g=%d b=%d 
alpha=%d h=%d s=%d b=%d\n", x, y, image->columns, image->rows, 
((int)GetPixelRed(p))/256, ((int)GetPixelGreen(p))/256, 
((int)GetPixelBlue(p))/256, ((int)GetPixelAlpha(p))/256, (int)(hue*100.0),
 ((int)saturation)/256, ((int)brightness)/256 );           */
        sprintf(s, "%s %d %d %d %d %d %d %d %d %d %d %d", argv[0], x, y, 
                     image->columns, image->rows, ((int)GetPixelRed(p))/256,
                     ((int)GetPixelGreen(p))/256, ((int)GetPixelBlue(p))/256,
                     ((int)GetPixelAlpha(p))/256, (int)(hue*100.0),
                     ((int)saturation)/256,       ((int)brightness)/256 );
        exitcode=system(s);
        if (exitcode!=0)
          break;
      }
      if (exitcode!=0)
        break;
    }
    if (exitcode!=0) {
      if (exitcode==2)
        fprintf(stderr,"*BREAK*\n");
      else 
        fprintf(stderr,"Error running `%s`: return code %d\n", s, exitcode);
    }
    image_view=DestroyCacheView(image_view);
  }
  return(MagickImageFilterSignature);
}
Thank you so much!

Re: Feature request: invoke command for each pixel

Posted: 2014-09-11T13:43:05-07:00
by snibgo
jpka wrote:((int)GetPixelRed(p))/256
GetPixelRed() etc returns a value between 0 and QuantumRange, inclusive. QuantumRange depends on the Q-number of your build: 255, 65525, 4294967295 etc.

If using Q8, GetPixelRed() will always be 0 to 255, so GetPixelRed()/256 will always be zero.


automake uses instructions in filters/makefile.am. If that file is wrong, automake won't work properly.