Color reduction with ImageMagick - colors

There's an image I convert to grey in a first step using this:
convert out.jpg -colorspace GRAY -normalize png:out.png
In another step I would like to reduce colors to 12:
convert out.png +dither -colors 12 -filter box -normalize png:out.png
This works perfectly with a very old version of GraphicsMagick which I have installed on one machine. On another machine is the latest version of ImageMagick. Here the resulting image just has 8 colors.
Is there a way I can force ImageMagick to make exactly 12 colors? Not more, not less?

Use the -posterize switch
convert colors.png -colorspace gray +dither -posterize 12 mono12.png

You can create our own 12 color colorable image and use -remap to recolor your image. See http://www.imagemagick.org/Usage/quantize/#remap and use -dither none

Related

Convert jpg to png with predefined color codes?

I've got some maps, based on 66 colors, that I unfortunately saved in jpg for a couple of months ago.
I've discovered that I can convert to png, and set it to be 66 colors, BUT, is there anyway to predefine those 66 colors, so for example the colors close to #888888 will be converted to #888888 and not to 878787 and 878887.
One issue is also that the maps don't contain all 66 colors,(usually around 30) so now I might get 4 different type of white. (that's why I need this solution)
is this even possible with imagemagick?
You can make a 66x1 pixel "swatch" of the 66 colours you want by taking one of your original PNG images and extracting the unique colours like this:
magick original.png -unique-colors swatch.png
Then you can apply it like this:
magick unhappy.jpg -remap swatch.png result.png
More details here.
Here's a concrete example. Here's our map:
First, make a swatch of the 5 colours we want to appear in our output image:
magick xc:"rgb(10,100,140)" xc:"rgb(240,190,120)" xc:"rgb(70,130,30)" xc:"rgb(220,230,230)" xc:"rgb(40,80,50)" +append swatch.png
Now remap all the colours in the original to the 5 colours in the swatch:
magick map.jpg +dither -remap swatch.png result.png
Alternatively, we could let ImageMagick choose the best colours for the swatch like this:
magick map.jpg -colors 7 -unique-colors swatch.png
And remap just the same as before but using the colours ImageMagick chose:
magick map.jpg +dither -remap swatch.png result.png
Note that you can use hex codes (or HSL, or Lab colours) just the same:
convert xc:"#0a658c" xc:"#f0be78" xc:"#46821e" xc:"#dce6e6" xc:"#285032" +append swatch.png
Note that the above commands assume ImageMagick v7. If you are obliged to use old v6 syntax, replace magick with convert.

Graphics program that will generate a common palette from multiple jpgs

gimp has the ability to generate a palette from a loaded image. I am looking to have all images (i am not necessarily the author of these pictures) share a common palette since this makes it easier displaying them on an LCD screen.
is there a program that does this? or some script in gimp or imagemagick?
There are few ways to do this:
use dithering
with palette designed for dithering like default VGA or WEB palette. I do it like this:
my simple C++ dithering
on how to do this. There are also more sophisticated approaches for this out there just google dithering...
merge all images to single mosaic
and compute the palette for this big image containing all the images you want with tool you use now. After that just use this palette for each of the original images (or on the mosaic and then de-mosaic).
compute the palette yourself
You need to compute histogram of all images and then use some kind of clustering to lower the number of colors. To include more images to this just compute histogram for all the images (do not reset it between images) and the rest is same as for single image. So if you got access to the color quantization code of yours then just change the histogram part ... by adding loop through all the images you want (and clearing histogram just for the first image).
Here example of how I do the color quantization:
Effective gif/image color quantization?
I do not use gimp nor imagemagick so I can not help you there but now you at least know what to look for in their docs ...
I'm not sure what you are trying to do is applicable to JPEG images as they do not have a colour palette. However, a possible technique with ImageMagick at the command line would be to put all the images together, reduce the number of colours to whatever you want and then save that (minimised/de-duplicated) as a "palette" which you can apply to other images.
So, the first step is to extract a common palette, of say 250 colours:
magick image1.jpg image2.jpg ... +append -colors 250 -unique-colors palette.png
Now, before you display any image, map it to that palette:
magick image.jpg -remap palette.png result.png
You can also disable dithering, with:
magick +dither image.jpg -remap palette.png result.png
I have used PNG rather than JPEG throughout because of my issue with JPEG palettes, but you can try with your JPEGs using just the same commands. I would definitely suggest you use GIF, PNG or NetPBM PPM format to store the palette information at least.
Just for fun, let's try that with a picture of the White House:
Let's make a really poor palette of three colours - red, yellow and cyan:
convert xc:red xc:yellow xc:cyan +append palette.png
and apply it with dither:
convert whitehouse.jpg -remap palette.png dither.png
and again without:
convert whitehouse.jpg +dither -remap palette.png undither.png
As #Spektre points out in the comments below, you may be passing that palette to the LCD in some BYTE array or something like a lookup table. If that is the case, you can see the palette in human/ASCII terms like this:
convert palette.png txt:
# ImageMagick pixel enumeration: 3,1,65535,srgb
0,0: (65535,0,0) #FF0000 red
1,0: (65535,65535,0) #FFFF00 yellow
2,0: (0,65535,65535) #00FFFF cyan
And you can get a 9-byte file of the R, G & B values in binary like this - I am choosing to dump it in hex afterwards so you can see it:
convert palette.png -depth 8 rgb:palette.bin
xd palette.bin
00000000: ff00 00ff ff00 00ff ff .........

How to offset image contents by X,Y pixels using ImageMagick?

I need to offset the pixels in a PNG image by -1 in X and -4 in Y axis.
The images were converted from a PDF created by Corel Draw, which adds an offset, breaking the image processing system I'm working on.
align_image_stack from hugin-tools package crashes when processing these files, that's why I resort to trying a fixed offest correction.
I tried this these commands:
$ convert a.png: -geometry 100%-100-100 b.png
$ convert -region '100%+500px+100px' a.png b.png
$ convert -page '100%+500px+100px' a.png b.png
$ convert -repage '100%+500px+100px' a.png b.png
$ convert -crop '100%+500px+100px' a.png b.png
$ convert a.png -geometry 100%-100px-100px b.png
They have all finished without an error, but the gave me the same image I fed them as input.
a.png = b.png
What am I doing wrong? Why the Covert command does not shift the image contents?
EDIT:
Here's a pair of images to illustrate my problem. The first image is what I want, the second is what comes out of Corel Draw, I want to apply an arbitrary X/Y offset to compensate for this difference. The images are faked only to illustrate the problem, this is not authentic data.
New point is that I was able to produce the offset once, but I can't reproduce this. It looks to me like a bug in ImageMagick, because I'm trying the same command that I used before and it doesn't work now.
I also tried using GraphicsMagick to doublechek this.
I was able to get an offset written to PNG header, but that doesn't make Blender use that offset, so I need to "burn" that offset into the bitmap data, not just specify it in the metadata.
This command did a change, but only GIMP seems understands that and I need to make Blender apply the offset:
convert a.png -repage '100%x100%+100+1000' b.png
I tried using -sample to apply the transformation, but it's not alpplied and stays in the metadata - I can check this with GIMP.
convert a.png -repage '100%x100%+100+1000' -sample 100% b.png
I can't believe I am unable to do such a simple thing.
Updated Answer
It is hard to understand what you want without proper images, but here is another attempt at guessing a solution for you. Let's start with this image - ignore the colours as I only added them so you can see the extent of the images and you can remove/change them anyway:
The new plan is to trim your image so there is no border around the letters at all and then to add in whatever border you want afterwards. So, trimming the existing border and adding a 10px border left and right and a 50px border top and bottom:
convert start.png -trim -bordercolor red -border 10x50 result.png
Or, trimming the original border and adding a 10px border to the right side only:
convert start.png -trim -gravity east -background blue -splice 10x0 result.png
Hopefully that will give you an approach to achieve what you seek.
Original Answer
If you want to reset the page offsets back to zero, the easiest way is:
mogrify +repage image.png
Or, slightly harder:
convert image.png +repage result.png

How to convert SVG image to 32-bit RGBA with ImageMagick?

How to convert SVG image to 32-bit RGBA with ImageMagick?
Background must be transparent.
Simply try this command:
convert in.svg -transparent white out.png
(Assuming the original SVG uses a transparent or white background. Otherwise, if SVG background is red or blue or '#235689': use -transparent red, -transparent blue or -transparent '#235689'....)
If your version of ImageMagick doesn't do it right, check if convert -list configure | grep svg shows rsvg output in the DELEGATES and CONFIGURE lines.
I found that setting background to none worked for me:
convert -background none in.svg out.png

Cropping two transparent png images using Imagick gives different results

I am having different result when cropping two png files.
Imagick Version using convert -version:
Version: ImageMagick 6.6.5-10 2010-11-26 Q16
Copyright: Copyright (C) 1999-2010 ImageMagick Studio LLC
Features: OpenMP
The two files using identify:
works.png PNG 1218x610 1218x610+0+0 8-bit DirectClass 755KB 0.000u 0:00.000
doesntwork.png PNG 70x70 70x70+0+0 8-bit DirectClass 1.64KB 0.000u 0:00.000
I am using this command:
convert <original>.png -crop 50x50+0+0 <target>.png
The problem is that works.png is 100% correct, while doesntwork.png is a black square.
Both original images seem to be the same - and do display correctly on windows 7.
The images:
works.png:
doesntwork.png:
Works for me using convert -versionImageMagick 6.4.0 04/17/08 Q16 (which is the "Current" version under cygwin), running via cygwin on Windows XP SP3.
It may be a bug in your particular version of ImageMagick. The shark works.png is a full color image with alpha (4 8-bit channels). The doesntwork.png is a 1-bit black and white image with 8 bits of alpha, and the shading is done by varying the alpha. That seems to me a rather rare format, so I can imagine a bug slipping into the conversion code.
You might try converting the image to true color first.
In the case of the two images posted, this seems like it might be a case of tools doing what they're told instead of what's intended.
Using -crop 50x50+0+0 on the shark image above gives a completely transparent 50 by 50 image because the 50 by 50 block of pixels in the upper left corner (+0+0) of the shark image is completely transparent. Using -crop 50x200+0+0 captures the tip of the shark's tail as well. -crop 50x50+950+250 gets the eye.
Does all this match your results?

Resources