What do the options of "deskew" mean? - imagemagick

It is talking about some scanned pages, which are not perfectly aligned. I would like to use ImageMagick to auto detect their skewed angles (less than 1 degree) then rotate them. There are a few discussions from people wanted to do the same thing as I am doing, yet those threads cannot solve my queries below. Examples of their discussions are here, here, and here.
(Please note that, as my images are scanned on a flatbed, I need only rotation to fix them. They will not be skewed into a trapezoid.)
1) What does the "threshold" percentage mean?
https://imagemagick.org/script/command-line-options.php#deskew
-deskew threshold{%}
Straighten an image. A threshold of 40% works for most images.
I thought it meant the angle of rotation. With a lower threshold, we tell the program to expect the image is not so skewed. Thus the fixing angle will not be too large. However it is not true.
I have a TIF image of 17MB 2368x2633px. -deskew 1% gives a rotation of -6.90 degrees. On the contrary -deskew 40% gives a much lower rotation angle. 0.32 degree is a lot closer to the correct rotation angle judged by human. -6.90 degree is way too much.
% identify Travel_photography_0011.TIF
Travel_photography_0011.TIF TIFF 2368x2633 2368x2633+0+0 8-bit sRGB 16.7365MiB 0.000u 0:00.000
% magick Travel_photography_0011.TIF +repage -deskew 1% -format '%[deskew:angle]' info:
-6.904543057049276733%
% magick Travel_photography_0011.TIF +repage -deskew 40% -format '%[deskew:angle]' info:
0.32172584926212061118%
2) What does +deskew mean? What is it different from -deskew threshold?
I see it in the first example discussion above.
It seems that +deskew gives me the correct rotation angle.
% identify Travel_photography_0011.TIF
Travel_photography_0011.TIF TIFF 2368x2633 2368x2633+0+0 8-bit sRGB 16.7365MiB 0.000u 0:00.000
% magick Travel_photography_0011.TIF +repage +deskew -format '%[deskew:angle]' info:
0.32172584926212061118%
Following the logic of -repage and +repage, it seems that the plus sign is a reset. However, it seems to me there is no deskew information for reset.
As a side note of Q1, ...
If the image is resized to smaller dimension, +repage -deskew 1% will also give the reasonable rotation angle.
% magick Travel_photography_0011.TIF +repage -resize 2400x2400 smaller.TIF
% identify smaller.TIF
smaller.TIF TIFF 2158x2400 2158x2400+0+0 8-bit sRGB 14.8182MiB 0.000u 0:00.000
% magick smaller.TIF +repage -deskew 1% -format '%[deskew:angle]' info:
0.34970134308438804993%
% magick smaller.TIF +repage -deskew 40% -format '%[deskew:angle]' info:
0.32172584926212061118%
% magick smaller.TIF +repage +deskew -format '%[deskew:angle]' info:
0.30773804399135001875%
Interestingly, -deskew 40% gives exactly the same rotation angle before or after resize.

Related

imagemagick check if image is of almost one single color

Friends,
I have a stack of color-scanned images. Some are from regular white paper with text or images, others were scanned from colored paper (blank pages, same green colored paper used.)
I'd like to identify these colored paper images. Problems:
paper's color ("background") is not scanned very uniformly, often has a wavy or structured pattern
green tone is quite different depending on the scanner used
scanner does not catch the full sheet resulting in a white or shadowed "border" around green area
My idea was to see if say 90% of the image is some sort of green and tried using a sorted histogram. But because of (1) and esp. (2) I have a hard time picking a working color value from the histogram data.
Any help appreciated!
Edit:
Here are three sample images, scanned from the same sheet of paper.
Have a look at HSV colourspace on Wikipedia - specifically this diagram.
It should be a better place to find the colour of your images, regardless of scanner and calibration.
Now, let's create a lime-green, yellow and cyan block and derive its colour using ImageMagick:
magick -size 100x100 xc:lime -colorspace HSV -channel 0 -separate -format "%[fx:mean*360]" info:
120
magick -size 100x100 xc:yellow -colorspace HSV -channel 0 -separate -format "%[fx:mean*360]" info:
60
magick -size 100x100 xc:magenta -colorspace HSV -channel 0 -separate -format "%[fx:mean*360]" info:
300
magick -size 100x100 xc:cyan -colorspace HSV -channel 0 -separate -format "%[fx:mean*360]" info:
180
Hopefully you can see we are correctly calculating the Hue angle. Now to your image. I have added an artificial frame so you can see how to remove the edges:
We can remove the frame like this:
magick YOURSCAN.jpg -gravity center -crop 80% cropped.jpg
So, my complete suggestion would be to crop and convert to HSV and check the mean Hue. You could also test if the image is fairly saturated so it doesn't pick up grey-ish, uncoloured images. You could also test the variance in the Hue channel to see if there are many different colours - or the spread of the hues is large and reject ones where it is large.
magick YOURSCAN.jpg -gravity center -crop 80% -colorspace HSV -channel 0 -separate -format "%[fx:mean*360]" info:
Just for reference, your 3 images come up with the following Hue angles on a scale of 0..360:
79, 68, 73
I would suggest you test a few more samples to establish a reasonable range.

convert doesn't conserve size when scaling down and up

In order to make applying blur faster I'm first scaling my image down and then scale it back up:
convert - -scale 10% -blur 0x2.5 -resize 1000% RGB:-
This works most of the time but sometimes the output resolution is slightly different from the original input. Is there a way to force the pipeline to be size-preserving?
You should be able to access the original geometry of the image via %G, so you can do:
convert input.jpg -scale 10% -blur 0x2.5 -resize '%G!' RGB:-
If you are using Windows, you probably want "%G!" in double rather than single quotes.
If you are using v7 ImageMagick, replace convert with magick.
I think you are getting errors because if you take 10% of 72 pixels (say), you will get a whole number of pixels, i.e. 7 pixels and then when you scale back up by a factor of 10 you'll get 70 rather than your initial 72.
If you are using Imagemagick 7, you can do the following:
magick input.jpg -set option:wd "%w" -set option:ht "%h" -scale "%[fx:wd/10]x%[fx:ht/10]" -blur 0x2.5 -resize "%[fx:wd]x%[fx:ht]\!" RGB:-
This stores the input width and height. Then uses the stored values to scale by 1/10 of those dimensions, then does the blur, then resizes exactly back to the origin input size. Note the ! that forces the resize to the exact dimensions.
or simpler without storing the input width and height:
magick lena.jpg -scale "%[fx:w/10]x%[fx:h/10]" -blur 0x2.5 -resize "%[fx:w]x%[fx:h]\!" lena_x.jpg

crop image with imagemagick offset given in percentage

imagemagick's crop command supports cropping to a percentage of an image but the offset values must be specified in pixel values, e.g.:
convert image.png -crop 50%x+10+20
I want to crop with offset values x and y given in percentage of the image width, and height respectively. The pixel values can be calculated, for instance if the image size is 100x200 an offset of 10% would result in 10 and 20 respectively. Is it possible to do this calculation as part of the call to convert? Width and height are available as %w and %h at some places, but this does not work:
convert image.png -crop 50%x+(0.1*%w)+(0.1*%h)
If you're running IM v6 you can use FX expressions with "-set" to set image attributes. By setting the page geometry you can specify the offsets to a calculated percentage and do the crop like this...
convert image.png -set page -%[fx:w*0.1]-%[fx:h*0.1] -crop 50%x+0+0 result.png
That reads the image, sets the geometry for the upper left corner to a location outside the original canvas, and crops to the new top left corner specified by the geometry.
Note the offsets are negative numbers.
Also, if you're doing additional processing in the same command you'll probably want to "+repage" after the crop in order to reset the page geometry to the new WxH+0+0.
Edited to add: You can even include the width and height dimensions for the crop when using "-set page". This command would crop an output of 50% the input width and height, and starting at 10% in from the left and top...
convert image.png \
-set page %[fx:w*0.5]x%[fx:h*0.5]-%[fx:w*0.1]-%[fx:h*0.1] -crop +0+0 result.png
Notice how the crop operation is simply "-crop +0+0" since the dimensions and offsets are in the page geometry.
This method lets you use more complex calculations than just using a percent or number of pixels for the cropped output dimensions.
You cannot do that in ImageMagick 6. But you can do that in ImageMagick 7.
magick image.png -crop "50%x+%[fx:0.1*w]+%[fx:0.1*h]" +repage result.png
In ImageMagick 6, you need to do the computations ahead of the command, store them in a variable and use the variable in the crop command.
However, in ImageMagick 6, you can do the equivalent using -distort with viewport processing as follows:
convert image.png -set option:distort:viewport "%[fx:0.5*w]x%[fx:0.5*h]+%[fx:0.1*w]+%[fx:0.1*h]" -filter point -distort SRT 0 result.png
With v7 ImageMagick, make start image:
magick -size 200x100 gradient: a.jpg
Now crop using lots of calculated widths, heights, offsets:
magick a.jpg -crop "%[fx:w*0.9]x%[fx:h*0.8]+%[fx:w*0.1]+%[fx:h*0.05]" b.png
Check:
identify b.png
b.png PNG 180x80 200x100+20+5 8-bit Gray 256c 408B 0.000u 0:00.000
If you only have v6, use bash and integer arithmetic:
read w h < <(identify -format "%w %h" a.jpg)
convert a.jpg -crop $((w*80/100))x$((h*90/100))+$((w*10/100))+$((h*5/100)) result.png
Check:
identify result.png
result.png PNG 160x90 200x100+20+5 8-bit Gray 256c 412B 0.000u 0:00.000

Applying watermark on an image

I'm trying to apply watermark on an image using the following imagemagick command
convert input.png watermark.png.png -gravity northwest -composite output.png
The input png file size is 16KB and the watermark file size is 900bytes, but when I executed the above command to apply a watermark, the output png size is 61KB which is almost 4X the size of the original input png file. Is there any better way of applying a watermark to an image file with much better result in terms of output filesize
Test Image: https://res.cloudinary.com/deks86ilr/image/upload/v1533015495/1_rnpbye.png
Test watermark: https://res.cloudinary.com/deks86ilr/image/upload/v1533015494/2_usmonh.png
Here are my results of processing of your images with my PNG8 output using ImageMagick 6.9.10.8 Q16 with libpng 1.6.34.
I note that your input image was type palette, which means it is 8-bits of color per pixel and not 24-bit color. So it is already a low quality image.
Input (~16 KB):
Watermark Image (white on transparency -- so it is invisible here):
Convert to 24-bit PNG:
convert input.png watermark.png -gravity northwest -compose over -composite input_with_watermark.png
I see no significant visible quality loss but the output is now increase from 16 KB to 60 KB. But you can use tools such as pngcrush to compress it further.
Convert to 8-bit PNG:
convert input.png watermark.png -gravity northwest -compose over -composite PNG8:input_with_watermark2.png
The file size is now back to about 16 KB. But as you note the quality is a little poorer. This is likely because the input image (at 8-bits and has 217 colors) was first read back to 24-bits, then watermarked, which included new shades of white and then quantized back to 8-bits, but contains only 84 colors colors.
Another way is to add +dither -colors 256 to the command (the +dither turns off dithering):
convert 1_rnpbye.png 2_usmonh.png -gravity northwest -compose over -composite +dither -colors 256 PNG8:watermark3.png
This is a bit better, since it now uses 189 colors and still has a file size of 16 KB.
One final method is to save the colors from your input to a colortable image. Then use -remap to recolor the output using that colortable:
convert 1_rnpbye.png -unique-colors colortable.gif
convert 1_rnpbye.png 2_usmonh.png -gravity northwest -compose over -composite +dither -remap colortable.gif PNG8:watermark4.png
This results in 8-bit output with 227 colors and still a file size of about 16 KB. So it has a few more colors than your input and visually looks about the same quality as your input.
If you cannot reproduce these results, then perhaps you should upgrade either or both ImageMagick and libpng.

Image Magick - trim and repage - loss of quality

When I use this command to trim a PDF file:
convert -fuzz 1% -trim +repage multi0.pdf multi0new.pdf
The result is very disappointing and the trimmed image size becomes more than 10 times lower than the source.
Is there any way to make a clean image trimming without loss of quality?
(here it is, before and after)
You probably have to use the -density option with a higher value than the default of 72 dpi. Try 300 for a start:
convert -density 300 -fuzz 1% -trim +repage multi0.pdf multi0new.pdf
Note that higher density values will increase the output file size.

Resources