Page 1 of 1

Sparse Color

Posted: 2011-06-20T09:59:31-07:00
by brute11k
So, basically, here is command-line script:

Code: Select all

convert m_f.png txt:- | sed '1d; / 0) /d; s/:.* /,/;' | convert m_f.png -alpha off -sparse-color shepards '\@-' m_f.png
I've already found function SparseColor, which can be used to interpret right side of the string:

Code: Select all

convert m_f.png -alpha off -sparse-color shepards '\@-' m_f.png
But haven't figured out what should I pass to this function as arguments yet.

Is there any way to Interpret this line:

Code: Select all

convert m_f.png txt:-
in PerlMagick API? Basically this is executing program which gets all the pixels from the source and writes them as rgba values:

pixels.txt:

Code: Select all

...
1676,57,rgba(225,243,250,1)
1677,57,rgba(225,243,250,1)
1678,57,rgba(225,243,250,1)
...
Also, there is argument "points=>array of float values" in SparseColor function — how should look like this array? Can I use data like this (in pixels.txt) as argument so its looks like:
$image->SparseColor(points=>"@pixels.txt",...); ?
Another question is what means '\@-' as argument and how to add it in PerlMagick API?

Any comments are welcome. Thanks for your time.

Re: How to interpret Image in txt

Posted: 2011-06-20T19:27:01-07:00
by anthony
I would be interested to know what you plan on using the 'shepards hole-fill' technique for!
brute11k wrote:So, basically, here is command-line script:

Code: Select all

convert m_f.png txt:- | sed '1d; / 0) /d; s/:.* /,/;' | convert m_f.png -alpha off -sparse-color shepards '\@-' m_f.png
NOTE that assumes the input image has a transparency channel so the 'sed' ignores any non-transparent pixel.
I will assume that you took care of that in previous steps that have not been given.

Also generally only the 'edge' or 'near-edge' pixels are wanted in the shepards hole fill method.

The '@' should not have a backslash as you want IM to interpret it as a 'read standard input'
I've already found function SparseColor, which can be used to interpret right side of the string:

Code: Select all

convert m_f.png -alpha off -sparse-color shepards '\@-' m_f.png
But haven't figured out what should I pass to this function as arguments yet.

Is there any way to Interpret this line:

Code: Select all

convert m_f.png txt:-
in PerlMagick API?
The output of 'txt:' Enumerated Pixel format, is essentually just a simple plain text file, with a one line header, and one entry per pixel. The s/:.* /,/ regular expression will work in perl too, but there is no real need.

The sed in the above basically just reformats the input to
junk the first line header
junk any fully transparent pixel
and format as X,Y,color which is the arguments needed by sparse color.
Also, there is argument "points=>array of float values" in SparseColor function — how should look like this array? Can I use data like this (in pixels.txt) as argument so its looks like:
$image->SparseColor(points=>"@pixels.txt",...); ?
Another question is what means '\@-' as argument and how to add it in PerlMagick API?

Any comments are welcome. Thanks for your time.
Now this I am not certain. I did not write the PerlMagick API interface, just the core library and CLI application interface.

Part of the CLI is a function that parses sparse color arguments from a X,Y,color format into a X,Y,R,G,B format where
R,G,B are floating point values. The exact number of color values needed however is variable and depend on the current -channel setting! Typically just RGB.

I had originally meant for that sparse color 'argument string' to 'float array' to be in the core library so that other API's like PerlMagick, can also use it, but it was moved directly into the CLI api module instead (no my choice), so is not available to other API's. :-( As such you will need to do that color to floats conversion yourself!

All is not lost however. You can generate a shepard's sparse color fill of transparent pixels using a different technique.
See IM Examples, Canvas Creation, Sparse Color Shepards - a Blur Alternative
http://www.imagemagick.org/Usage/canvas/#sparse_blur
Particularly the last resize or 'pyramid image' blurring example. That should be much easier to generate in PerlMagick, and should be faster too.

Note however that shepard's interpolation method is a global interpolation, which uses ALL the inputs, Not just the nearest or direct line of sight inputs. (see notes in section above the link given). Basically shepards may look like a 'diffusion' method but it is NOT a true 'diffusion' method.

I have plans on implementing a true diffusion technique, as a more direct 'hole filling' operator. But this is on hold until after I finish IMv7 CLI interface revisions (IMv7 is currently in pre-alpha development).

Re: Sparse Color

Posted: 2011-06-25T05:16:49-07:00
by brute11k
Okay thanks for replies, I've almost done with my script that creates Diffuse Borders like this: http://i.imgur.com/ZyNE6.jpg

By the time, I have all preparations done like check files, resize, add transparent borders, write to file, etc.

This is what I'm trying to do:

Code: Select all

$image->Extent(geometry=>$geometry,background=>'rgba(255, 255, 255, 0.0)',gravity=>"center");
$first  = $image->Clone();
$second = $image->Clone();
$first  = $first ->Transform(crop=>'x'.(($desired_h-$h)/2+1).'x+0+0', gravity=>'North');
$second = $second->Transform(crop=>'x'.(($desired_h-$h)/2+1).'x+0+0', gravity=>'South');
# extract pixels from last and first line and write to array => pass to SparseColor => profit!
# my @pixels = $first->GetPixels(map=>'RGBA', y=>53, height=>1, width=>5, normalize=>'false');
# my @pixels = $first->GetPixels(map=>'D', y=>53, height=>1, width=>5, normalize=>'false');
$w = $first->Get('columns');
$h = $first->Get('rows');
for ($x = 0; $x < $w; $x++) {
push @xypixels, "$x,$h,".$first->GetPixel(map=>'D', x=>$x, y=>$h, normalize=>'true');
}
for ($x = 0; $x < $w; $x++) {
push @xypixels2, "$x,0,".$second->GetPixel(map=>'D', x=>$x, y=>0, normalize=>'true');
}
$first->Set(alpha=>'Off');
$first->SparseColor(points=>@xypixels,method=>'Shepards');
$second->Set(alpha=>'Off');
$second->SparseColor(points=>@xypixels2,method=>'Shepards');
$image->Composite(image=>$first,gravity=>'North');
$image->Composite(image=>$second,gravity=>'South');
So basically what I need is how to pass params to SparseColor function.
Currently I'm calling it with next params:

Code: Select all

$first->Set(alpha=>'Off');
$first->SparseColor(points=>@xypixels,method=>'Shepards'); 
Where @xypixels described below.
I've tried array @xypixels with next formats (for each element):
"x,y, value(from 0 to 1)",
"x,y,value",
"x, y, value", (spaces)
"x y value", (no commas)
"x", "y", "value" (yes, 3 elements instead of 1)...
and after that my ideas run out.
Result is always the same and looks like this: http://i.imgur.com/oVYBQ.jpg

How should @xypixels array look like?

Btw, here is the full source of the script: http://paste.pocoo.org/show/419049/

Re: Sparse Color

Posted: 2011-06-25T21:15:45-07:00
by anthony
For Magick Core function it an array of floats.

For example..
x,y, value
with value in the range 0 to 1. BUT only with 'channels' set to ONE channel only.
For every valid channel present in 'channels' you need another value.

As such for the default channel setting RGBK (and K (black) is not valid in a RGB image) you will need 3 values
x,y,r,g,b

That is the format! of the MagickCore function. Not strings!

What it is for PERL should be defined by the API using the Magick Core function!
In CLI the API defines it as a single string which it converts to the array of floating point values.
BUT it also allows you to use the floating point values directly! Though it is rarely used.

I would have prefered the PERL API to have made use of the CLI string to array function, but it does not seem to do so.
I did not write it!
Result is always the same and looks like this: http://i.imgur.com/oVYBQ.jpg
Then there should be an error!!!! from the function aborting.


Start simplier, say just one color (should replace all colors in the image to that one color).

Re: Sparse Color

Posted: 2011-06-25T21:37:55-07:00
by anthony
Hmmm looks like at least 4 color values are needed for a rose: image! I do not know why!

I got this to work... (just sets one color! a gray)

Code: Select all

#!/usr/bin/perl
#
use strict;
use warnings;
use Image::Magick;

my $image = Image::Magick->new();
my $err;

$err = $image->Read("rose:");
if (length $err) {
  $err =~ /(\d+)/;
  print "Read Error $err\n";         # print the error number
}

#                X,Y, --color values--
my @xypixels = ( 5,5, 0.5,0.5,0.5,0.5 );

$err = $image->SparseColor(points=>\@xypixels, method=>"Shepards");
if (length $err) {
  $err =~ /(\d+)/;
  print "Sparse Error $err\n";         # print the error number
}

$image->write("show:");

Re: Sparse Color

Posted: 2011-06-26T02:06:19-07:00
by brute11k
Finally, it works like a charm: http://paste.pocoo.org/show/420016/

There is a little fixes should come because I don't like the way it interferes with the edges (they are too sharp). So I need to blur an image with blur mask around edges, where the diffuse effect is applied.

Already tested it with my 246 files (some of them were already resized) and it is shows very nice results: takes about 2-3 seconds on each file (with checking each file in directory if image or not and then reading them again while resizing, adding borders, etc).
So I'm wrote TODO list and wonder if there any way to improve my CheckFiles function so it work a little bit faster? Without reading entire file? Because I/O is very slow atm.
Btw, Thank you very much!

Update: Also currently I'm seeking a method which can remove borders (that have monotone color) if they are already exists. My idea is check 2-3 pixels from the edges and if they are same, get the height or width of this monotone borders until pixels are start to change and then just crop them (+2-5 pixels in case borders are little gradiented or blurred).

Tested

Code: Select all

Done.
Total files processed: 246 of 246
Total time:
User: 642.16
System: 233.29

Re: Sparse Color

Posted: 2011-06-26T03:39:16-07:00
by brute11k
I've found a little "bug" (basically it's not but anyway this is not what I've expected):
So here is original:
http://i.imgur.com/qFg7Z.png
Output:
http://i.imgur.com/UzQIg.png
As you can see there is black points where should be alpha channel, but there is also should be black points here (and they shouldn't take up all the space.
First solution I came with is a disabling alpha channel on whole image:

Code: Select all

$image->Set(alpha=>'Off');
It's producing a black background image like this: http://i.imgur.com/JtSBZ.png
I don't know how to change it to white because:

Code: Select all

$image->Set(transparent-color=>'white');
is producing next error:

Code: Select all

Bareword "transparent" not allowed while "strict subs" in use at /usr/bin/imresize line 110.
BEGIN not safe after errors--compilation aborted at /usr/bin/imresize line 220.
Upd: Okay, I've managed to kinda "fix" this: http://i.imgur.com/GS0O3.png
But aliased edges on picture is really annoying :(

Here is latest code: http://paste.pocoo.org/show/420112/ (added removing transparency )

Re: Sparse Color

Posted: 2011-06-26T17:58:03-07:00
by anthony
brute11k wrote:

Code: Select all

$image->Set(transparent-color=>'white');
is producing next error:

Code: Select all

Bareword "transparent" not allowed while "strict subs" in use at /usr/bin/imresize line 110.
BEGIN not safe after errors--compilation aborted at /usr/bin/imresize line 220.
Perl is seeing an expression "transparent" "-" "color" before it sees the special "=>" comma operator.
(ASIDE: perl treats "=>" simply as a "," but converting identifier before it into a string. As such
a => "b"
becomes equivalent to
"a" , "b"

To fix you will need to quote transparent-color yourself.
$image->Set('transparent-color'=>'white');

HOWEVER that will not do anything in this case! It sets a color to use for the transparent index in index images, like GIF. It is not used fro PNG images.

What you really want to do is find out what is trashing your transparency channel, and more likely it is your 'edge fading' effect that you were implementing previously.

I am not however going to wade through your whole perl application again.