fast way to border "inline"

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
robuntu
Posts: 41
Joined: 2012-01-22T10:56:10-07:00
Authentication code: 8675308

fast way to border "inline"

Post by robuntu »

Hi,
I have to border large images.
The images are about 5000x30000 Pixel an I have two jobs to do:
1) add a very small (3 pixel) line at the bottom of the page.
I think a -splice 0x10 with gravity south should do this, but is this the fastest way?

2) add two small (100 pixel) lines left and right but inline.
Meaning if the image is 5000 pixel wide, it must stay 5000 pixel wide and the
two lines have to be inside the image, cropping the picture.
I could do this with the -page option, but this is probably too slow and I have to
create an extra border-image first.
Is there a better way?

Unfortunatly the second task has to be with cmyk colors, so I need to
know how to name a color in cmyk

I need cyan, magenta, yellow and black as basic colors
but also two ore three of them mixed with always 0 or 100 percent.
E.g. cyan+magenta or cyan+magenta+yellow or yellow+black.

(Background for this strange task is that I need to extra-use toner
on a fast endless paper laser printer, because if an image has to less
of one of the four colors the toner gets jamed, so I need to "border" the image
inside the full pagewith with the unused color.)

By the way, time is relevant, memory is not!
I have a 32GByte ram server, so I have lots of ram,
but I have to produce these borders really fast,
there will be up to 1000 images every hour.
It is a special preprocessor in a printserver-queue.

Any ideas?

Greetings, Roland
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: fast way to border "inline"

Post by fmw42 »

I would think that -splice is probably your best bet as being fastest. But no one can say until they test any variations. It is certainly the most direct method.

To add colors to the edges of an image, I would suggest you convert your cmyk colors to rgb and then just draw lines at the sides of the images. -draw only works with rgb colors. Once you know what cmyk colors you want, you can convert by using the txt: output

convert -size 1x1 xc:"cmyk(...)" -colorspace RGB txt:

then pipe to sed to to extract the rgb(...) or color name at the end of the line.

Here is a test:

Get some cmyk value from an rgb value
convert -size 1x1 xc:"rgb(200,100,50)" -colorspace cmyk txt:
# ImageMagick pixel enumeration: 1,1,65535,cmyk
0,0: ( 0,17446,30515, 6656) #0000442677331A00 cmyk(0%,26.6209%,46.5629%,10.1564%)

Now convert cmyk value to rgb
convert -size 1x1 xc:"cmyk(0%,26.6209%,46.5629%,10.1564%)" -colorspace RGB txt:
# ImageMagick pixel enumeration: 1,1,65535,rgb
0,0: (51400,25700,12850) #C8C864643232 rgb(200,100,50)

Now filter to get last field
convert -size 1x1 xc:"cmyk(0%,26.6209%,46.5629%,10.1564%)" -colorspace RGB txt:- | tail -n 1 | sed -n 's/^.*#.* \(.*\)$/\1/p'
rgb(200,100,50)
robuntu
Posts: 41
Joined: 2012-01-22T10:56:10-07:00
Authentication code: 8675308

Re: fast way to border "inline"

Post by robuntu »

Hi fmw42,
thanks for your answer!

Converting from cmyk to rgb and back could change the colors of the final image.
I have to deal with designers rather than computing people like me and if they say:
"the colors changed" I have a problem.

So what about cropping the image and splicing?
This should work completely in cmyk, shouldn't it?

Spicing ist fast and I have to crop the images anyway.

Leading to the next problem:
I need to know which channel (c,m,y,k) is used less in an image.
If I use identify -verbose I can read the channel mean value and look for the smallest.
Is there an option I can use to get only this value ?
Something like identify -format %[get the mean value of channel c]
I would then use this command four times, one for each channel
and compare automaticly.

sorry, its a drift of topic...

Greeting Roland
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: fast way to border "inline"

Post by fmw42 »

I am not sure I am following. Are you images in cmyk format? Or do you just need to specify the colors for the borders as cmyk? I was not suggesting that you convert the whole image if the latter case, just convert the needed border color from cmyk to srgb.

For your first task, you could use -shave to remove two opposite edges and then use -extent with -geometry center to add back the color. Or use -splice to add the two ends back. Not sure without testing whether -extent or -splice will handle cmyk colors. Or just composite or flatten over a background image of the desired color.


With respect to the mean of some channel, use fx escapes

identify -format "%[fx:mean.r]" yourimage

will give the mean of the red channel in range 0 to 1. similarly for .g and .b

If you want in range 0-255, then

identify -format "%[fx:round(255*mean.r)]" yourimage

if you want the mean in the range of 0-quantumrange

identify -format "%[fx:round(quantumrange*mean.r)]" yourimage
or
convert yourimage -channel r -separate -format "%[mean]"

see
http://www.imagemagick.org/Usage/transform/#fx_escapes
http://www.imagemagick.org/script/fx.php
http://www.imagemagick.org/script/escape.php

Testing: The following seems to work whether the input is sRGB or CMYK.


convert -size 1x1 xc:blue -colorspace cmyk txt:
# ImageMagick pixel enumeration: 1,1,65535,cmyk
0,0: (65535,65535, 0, 0) #FFFFFFFF00000000 cmyk(255,255,0,0)


convert rose: -shave 10x0 -background "cmyk(255,255,0,0)" -gravity east -splice 10x0 -gravity west -splice 10x0 rose_tmp1.png

convert rose: -colorspace cmyk rose_cmyk.jpg
convert rose_cmyk.jpg -shave 10x0 -background "cmyk(255,255,0,0)" -gravity east -splice 10x0 -gravity west -splice 10x0 rose_tmp2.jpg
convert rose_tmp2.jpg -colorspace sRGB rose_tmp3.jpg

I cannot say which will be faster --- -draw, -splice twice, -extent once, or flatten over a background image. You will have to test. Please report back here what you find.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: fast way to border "inline"

Post by fmw42 »

Here are 4 alternates that work: (unix syntax)


convert rose: -colorspace cmyk rose_cmyk.jpg
convert rose_cmyk.jpg -shave 10x0 -background "cmyk(255,255,0,0)" -gravity east -splice 10x0 -gravity west -splice 10x0 rose_tmp1.jpg
convert rose_tmp1.jpg -colorspace sRGB rose_tmp1rgb.jpg

convert rose: -colorspace cmyk rose_cmyk.jpg
size=`convert rose_cmyk.jpg -format "%wx%h" info:`
convert rose_cmyk.jpg -shave 10x0 -background "cmyk(255,255,0,0)" -gravity center -extent $size rose_tmp2.jpg
convert rose_tmp2.jpg -colorspace sRGB rose_tmp2rgb.jpg

convert rose: -colorspace cmyk rose_cmyk.jpg
size=`convert rose_cmyk.jpg -format "%wx%h" info:`
convert rose_cmyk.jpg \
\( -size $size xc:"cmyk(255,255,0,0)" \) \
\( -clone 0 -shave 10x0 \) \
-delete 0 -gravity center -compose over -composite rose_tmp3.jpg
convert rose_tmp3.jpg -colorspace sRGB rose_tmp3rgb.jpg

convert rose: -colorspace cmyk rose_cmyk.jpg
size=`convert rose_cmyk.jpg -format "%wx%h" info:`
convert rose_cmyk.jpg -shave 10x0 -repage ${size}+10+0 -background "cmyk(255,255,0,0)" -gravity center -background "cmyk(255,255,0,0)" -flatten rose_tmp4.jpg
convert rose_tmp4.jpg -colorspace sRGB rose_tmp4rgb.jpg

-draw does not seem to work on cmyk images using either rgb colors or cmyk colors.
Last edited by fmw42 on 2012-05-09T14:17:32-07:00, edited 1 time in total.
robuntu
Posts: 41
Joined: 2012-01-22T10:56:10-07:00
Authentication code: 8675308

Re: fast way to border "inline"

Post by robuntu »

hi fmw42,
Thanks, you are my hero!

this is exactly what I want!

first step : shave
second step identify colors with your code -> select lowest channel
third step: extent with bgcolor "lowest channel from step 2"

Here is my test:

Code: Select all

identify bild1.tif
bild1.tif TIFF 17953x13465 17953x13465+0+0 8-bit DirectClass 771.9MB
I want to add a 50pixel Border at both sides.

Code: Select all

date; convert bild1.tif -shave 50x0 -background "cmyk(255,255,0,0)" -gravity east -splice 50x0 -gravity west -splice 50x0  bild2.tif; date
and the output
Mi 9. Mai 22:56:03 CEST 2012
Mi 9. Mai 22:58:06 CEST 2012
and the other version:

Code: Select all

date; convert bild1.tif -shave 50x0 -background "cmyk(255,255,0,0)" -gravity center -extent 18053x bild3.tif; date
with the output
Mi 9. Mai 23:06:38 CEST 2012
Mi 9. Mai 23:08:11 CEST 2012
The winner ist extend with only 3/4 of the "double splice" time.
Great!

Roland
robuntu
Posts: 41
Joined: 2012-01-22T10:56:10-07:00
Authentication code: 8675308

Re: fast way to border "inline"

Post by robuntu »

Oh I just noticed you posted again...
I will check the other options as well

Roland
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: fast way to border "inline"

Post by fmw42 »

use time rather than date. It will give you the precise time. you don't need to follow the command with another time. And repeat it several times. Note it will vary a few msec.


time convert rose_cmyk.jpg -shave 10x0 -background "cmyk(255,255,0,0)" -gravity east -splice 10x0 -gravity west -splice 10x0 rose_tmp1.jpg

real 0m0.019s
user 0m0.007s
sys 0m0.007s



time convert rose_cmyk.jpg -shave 10x0 -background "cmyk(255,255,0,0)" -gravity center -extent $size rose_tmp2.jpg

real 0m0.019s
user 0m0.007s
sys 0m0.007s



time convert rose_cmyk.jpg -shave 10x0 -repage ${size}+10+0 -background "cmyk(255,255,0,0)" -gravity center -background "cmyk(255,255,0,0)" -flatten rose_tmp4.jpg

real 0m0.019s
user 0m0.007s
sys 0m0.006s

At least on my small test image. But try with a larger image and see.

Please report on the size of your test image (width x height) with your timings
robuntu
Posts: 41
Joined: 2012-01-22T10:56:10-07:00
Authentication code: 8675308

Re: fast way to border "inline"

Post by robuntu »

Ok here we go:

Picture size: 17953x13465

Code: Select all

time convert bild1.tif -shave 50x0 -background "cmyk(255,255,0,0)" -gravity east -splice 50x0 -gravity west -splice 50x0  bild2.tif
real 2m8.164s
user 0m25.390s
sys 0m19.769s

Code: Select all

time convert bild1.tif -shave 50x0 -background "cmyk(255,255,0,0)" -gravity center -extent $size bild3.tif
real 1m41.174s
user 0m48.767s
sys 0m14.285s

Code: Select all

time convert bild1.tif -shave 50x0 -repage ${size}+50+0 -background "cmyk(255,255,0,0)" -gravity center -background "cmyk(255,255,0,0)" -flatten bild4.tif
real 1m42.839s
user 0m48.555s
sys 0m14.721s
Even if the "extent" and the "repage" methods are similar in time, I prefer the extent version.

While testing this, I noticed that only one processor is used.
Is there a chance to speed it up with something like "force multiprocessor"?

Greetings
Roland
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: fast way to border "inline"

Post by fmw42 »

what does

convert -version

show you. Does it say OpenMP? If you have more than one processor and it says OpenMP, then it should be doing multiprocessing. But I am not an expert on when that engages. OpenMP should be the default configure unless you expressly say to disable it when compiling.


On another point, it may take time for you to get each of the channel means by repeating the convert command for each channel. Here are two ways to get it at one time and put the results in an array. Let us know which one is faster for your test image.


convert logo: -colorspace cmyk logo_cmyk.jpg
meanArr=(`convert logo_cmyk.jpg -format "%[fx:mean.c] %[fx:mean.m] %[fx:mean.y] %[fx:mean.k]" info:`)
echo "${meanArr[*]}"

convert logo: -colorspace cmyk logo_cmyk.jpg
meanArr=(`convert logo_cmyk.jpg -verbose info:- | sed -n 's/^.*[Mm]ean:.*[(]\([0-9.]*\).*$/\1/p' | head -n 4`)
echo "${meanArr[*]}"

In the last case, I specified 4 because there is one more afterwards which is the overall mean from all channels.
robuntu
Posts: 41
Joined: 2012-01-22T10:56:10-07:00
Authentication code: 8675308

Re: fast way to border "inline"

Post by robuntu »

it says: OpenMP.

...but on the other hand I have to do multiple jobs a time anyway,
so I just place my commands with a following "&" and I will get my multiprocessing...

I think this is faster than using the same image four times, even if I only select one channel.

Next week I can test my commands on the real machine.
At the moment I use my PC (still a fast one...)

But on my server I will have a ramdisk and convert my images to mpc in a first step,
which then is located on the ramdisk.
I am sure this will speed up the whole thing to an entirely new level.

I will report...

Roland
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: fast way to border "inline"

Post by anthony »

robuntu wrote:Converting from cmyk to rgb and back could change the colors of the final image.
I have to deal with designers rather than computing people like me and if they say:
"the colors changed" I have a problem.
With a Q16 version of IM, that should not be a problem! The Q16 provides enough leeway that colors that map from CYMK to RGB (or sRGB) and back should remain exact enough that their is no loss at the 8 bit level.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: fast way to border "inline"

Post by anthony »

robuntu wrote: Even if the "extent" and the "repage" methods are similar in time, I prefer the extent version.
Both extent and page-flatten will generate new (large) images and need lots of copying of data. Draw draws on the existing image and should be a lot faster.

Compose with smaller images (overlay side parts) should be about as fast a draw.

-splice will also generate a new image - but as you are enlarging the image that can not be helped.


The rule of thumb. If the image size could change (splice, extent, crop, resize, distort, flatten), OR the result needs to refer to multiple places in the old image (convolve, morphology, blur, sharp, distort, fx, and any form of image mapping), THEN a new image is needed and the old data transferred (appropriately) to it.

Note that Composite and Draw (which includes text annotation) is NOT on that list! Both of these write directly into the destination image! Nor are per-pixel color modification operators (level, clut, halt, color-matrix, tint, sparse-color)
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: fast way to border "inline"

Post by anthony »

robuntu wrote:it says: OpenMP.

...but on the other hand I have to do multiple jobs a time anyway,
so I just place my commands with a following "&" and I will get my multiprocessing...
OpenMP generates threads, not processes, with each thread using a 'core' to do its job. IM uses threads the processing of most individual operations (typically one thread per row to a maximum thread count limit). You can see it by adding a monitor program to watch individual processes, though when you have a 8 core processor, that can use up a lot of screen space. It will however still appear as a single 'process' in the UNIX process table.

Using '&' generates completely unrelated but complete processes, that only communicate via file streams (pipes) or through shared memory. If you are processing multiple images I would be inclined to turn of threading and run a seperate process on each image. The GNU "parrellel" program is a good handler for this, launching new programs as old ones finish with a new file (image), or N images, to each program.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: fast way to border "inline"

Post by anthony »

fmw42 wrote:convert logo: -colorspace cmyk logo_cmyk.jpg
meanArr=(`convert logo_cmyk.jpg -format "%[fx:mean.c] %[fx:mean.m] %[fx:mean.y] %[fx:mean.k]" info:`)
echo "${meanArr[*]}"

convert logo: -colorspace cmyk logo_cmyk.jpg
meanArr=(`convert logo_cmyk.jpg -verbose info:- | sed -n 's/^.*[Mm]ean:.*[(]\([0-9.]*\).*$/\1/p' | head -n 4`)
echo "${meanArr[*]}"

The Future...
You will be able to ask for and use image information like 'mean' within the same ImageMagick command in IMv7. That is do things like set the fill color to the 'mean' the draw with it, without needing a wrapper shell script and two (or more) separate IM commands. I am working on the aspect at this time.

Also shell wrapped IM will be easier with IMv7 able to do 'co-processing'. That is run one IM command in background, which holds and processes the actual images in memory, and have the shell 'pipe' requests, and recieve results about those images. That is the shell will be able to do 'control' the image processing, while the sub-process IM command handles the images.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Post Reply