Further improvements with Imagemagick for text recognition with Tesseract-OCR - imagemagick

Original PNG:
[1
With this:
convert original.png -channel RGB -negate -white-threshold 70% -fuzz 10% -transparent white improved.png
Improved PNG:
The problem is that text cannot be extracted correctly with Tesseract-OCR, it only outputs part of the last two rows (no lat-long labels):
tesseract improved.png improved
cat improved.txt
14° 29.9808' S
76° 15.7617' W
How could the convert call be further improved to correctly extract the text? Any hints are appreciated.

In Imagemagick, you can try
convert original.png -colorspace gray -threshold 25% -morphology open diamond:1 result.png

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.

imagemagick mean image sequence and ignore alpha channel

I want to get the mean of a sequence of images by using Imagemagick. Therefore I use the following command:
convert *.png -evaluate-sequence mean MEAN.png
Each of my images does contain an alpha channel. What I want is: Combine all the images by ignoring the alpha channel.
When I combine the images, the alpha channel is considered in the "mean" method and my final image has transparency. That isn't what I want.
Result:
I tried to add the parameter -alpha off, but then Imagemagick converts the alpha channel to black.
convert *.png -alpha off -evaluate-sequence mean MEAN.png
Result:
Photoshop does it right. I load all images in a stack and create a smart object. When I use the "mean" method in Photoshop, the alpha channel is not considdered in the final result.
Result that I want with Imagemagick:
Does someone have an idea how to do that with Imagemagick?
What you need to do is to use the alpha channels as weighting images for each image. The total fraction of white values at each pixel from all the alpha channels would be the weight to use for the average. So something like this should do what you want or at least be close.
First, cd to your directory of images. Then run the following.
convert *.png -evaluate-sequence mean \
\( -clone 0 -alpha off \) \
\( -clone 0 -alpha extract \) \
-delete 0 +swap -compose divide -composite result.png
This will work if there is some image texture at each pixel coming from al least one image. That is at a given pixel all images are not totally black (transparent).
compare -metric rmse result.png mean_photoshop.png null:
125.167 (0.00190993)
So this shows that there is about 0.2% difference between my result and what you got from photoshop
Maybe this way of working will help you get there - or at least explain the problem:
convert xc:"rgba(255,0,0,1)" xc:"rgba(0,0,0,1)" xc:"rgba(0,0,0,0)" -depth 8 -evaluate-sequence mean txt:
Output
# ImageMagick pixel enumeration: 1,1,65535,srgba
0,0: (21845,0,0,43690) #550000AA srgba(85,0,0,0.666667)
Using IM 6.8.9.4 Q16 or IM 7.0.5.5 Q16 Mac OSX Sierra, this seems to work fine for me:
Make transparent image
convert logo: -transparent white logot.png
Get mean
convert logot.png logot.png logot.png -alpha off -evaluate-sequence mean result.png
magick logot.png logot.png logot.png -alpha off -evaluate-sequence mean result.png
This also seems to work:
convert logot.png logot.png logot.png -channel rgb -evaluate-sequence mean -alpha off result.png
So perhaps you need to upgrade your ImageMagick (and/or libpng?)
Can you post a zip file of some of your input images, so we can test with your images?
One problem that I see is that the PNG images that you provided have black under the transparent areas and not image texture. So when you disable alpha as in my commands above, you see black and the black gets averaged into the final result. Did you use these same PNG images in Photoshop or did you have Photoshop PSD images or some other images that you used and then exported to PNG, which may have put black under the transparent areas. Have you tried using the same PNG images in Photoshop to do the average?
In fact, you have 8-bit color (palette) images, which have one color (black) assigned to be the transparent color.

How to select all grayscale colors?

In ImageMagick convert, I can select a specific color with e.g. -opaque blue. How can I select all grayscale colors (e.g. #000000, #707070, #ffffff)?
Not sure what you are trying to do, but this may help. The greyscale pixels will have a saturation of zero, so that is probably the easiest way to identify them.
First, make a funky sample image:
convert -size 400x100 gradient:black-white -bordercolor red -border 80 image.png
Now make all grey areas (those with very low saturation) transparent:
convert image.png -alpha on -channel A -fx "saturation<0.01?0:1" result.png
Note
Note that the -fx operator is extremely powerful but notoriously slow because it is actually interpolated for each and every pixel. If your images are large, the following technique may be more appropriate.
Basically, I clone the image and convert the whole thing to HSL colorspace and separate the channels. Then I discard the Hue and Lightness channels so I am left with just the Saturation. I then threshold that and copy that back to the original image as the alpha channel. On a 2000x2000 pixel image, this method will run in under a second whereas the -fx method will require 5-6 seconds.
convert image.png \( +clone -colorspace hsl -separate -delete 0,2 -threshold 1% \) -compose copy-opacity -composite result.png

Changing exposure of jpeg

Given a jpeg, what is the formula to change the exposure of that jpeg by +/-1 stop or as known as 1 EV? I want to simulate this exposure change. Is there a formula/ method to do so?
I can demonstrate that using ImageMagick, which is included in most Linux distros and available for OSX and Windows from here.
First, at the Terminal command line create an image:
convert -size 512x512 gradient:black-yellow gradient.png
Now, the way to effect +1 stop exposure increase is to composite the image with itself using the Screen blending mode - it is available in Photoshop and ImageMagick and is described here.
So, the formula to composite image A with image B is:
1-stop brighter image = 1-(1-A)(1-B)
but as we are compositing the image with itself, A and B are the same, so we effectively have
1-(1-A)(1-A)
ImageMagick refers to the pixels of an image using p rather than A, so we can do a 1-stop increase like this:
convert gradient.png -colorspace RGB -fx "(1-(1-p)(1-p))" result.png
Note that the Wikipedia article, and ImageMagick's -fx both assume your pixel intensities vary between 0 and 1.0. If you are using 8-bit images, you should calculate with 255 in place of 1, namely
+1 stop brighter image = 255-(255-A)(255-A)
or if using 16-bit values
+1 stop brighter image = 65535-(65535-A)(65535-A)
The above fx-based method is however, very slow because the -fx is interpreted rather than compiled, so a faster way to do it is:
convert gradient.png gradient.png -colorspace RGB -compose screen -composite screen.png
Just for fun, another way of looking at that is that we take the inverse of A, that is 1-A, and square it, and then take the inverse, so it can be done like this:
convert gradient.png -colorspace RGB -negate -evaluate pow 2 -negate result.png
The equivalent of -1 stop exposure decrease is to composite the image with itself using the Multiply blend mode, the formula being
1-stop darker image = A x B
which you would do faster with
convert gradient.png gradient.png -colorspace RGB -compose multiply -composite result.png
or even faster, by using memory-to-memory cloning rather than reading from disk twice, with
convert gradient.png -colorspace RGB +clone -compose multiply -composite result.png
but could do equally with
convert gradient.png -colorspace RGB -evaluate pow 2 result.png

How to output white png version of my image ?**

With ImageMagick shell command (convert?)...
Given a colorful input.png image.
How to us input.png to produce a white output.jpg version with similar dimensions an opacity of 100% ?
I will later on use this layer in my workflow.
This should work:
convert input.png -threshold -1 output.jpg
This transforms any pixel with an intensity greater than (-1), i.e., all of them, to white.
It does not work with GraphicsMagick, though, because in GM the threshold value is unsigned (in ImageMagick it's a signed "double"). Neither of the applications documents exactly what is supposed to happen when the threshold is negative.
Here's a command that works on both ImageMagick and GraphicsMagick, and is documented:
[gm] convert input.png -fuzz 100% -fill white -opaque gray output.jpg
You could use fill, like this:
convert input.png -fill "#ffffff" output.jpg
or
convert input.png -fill white output.jpg
Or you can convert all three channels (red, green and blue) to "1" which is full intensity, like this:
convert input.png -channel red -fx "1" -channel green -fx "1" -channel blue -fx "1" output.jpg

Resources