Get only hex values from imagemagick - imagemagick

I can get the 10 most frequent colors from an image with this command
convert MYIMAG.JPG +dither -colors 10 -unique-colors
The output is the following:
# ImageMagick pixel enumeration: 10,1,65535,srgb
0,0: (17797.7,15058.3,10214.1) #453B28 srgb(69,59,40)
1,0: (26745.1,24530.8,20814.7) #685F51 srgb(104,95,81)
2,0: (35510.4,30224.2,23717.1) #8A765C srgb(138,118,92)
3,0: (33428.3,32608.7,27562.4) #827F6B srgb(130,127,107)
4,0: (42221,36875.3,29255.8) #A48F72 srgb(164,143,114)
5,0: (53896.7,44085.9,24988.3) #D2AC61 srgb(210,172,97)
6,0: (45384.3,42509,38801.6) #B1A597 srgb(177,165,151)
7,0: (54519.7,46803.7,37705.7) #D4B693 srgb(212,182,147)
8,0: (56368.6,48645.3,40350) #DBBD9D srgb(219,189,157)
9,0: (58605,50733.4,41256.9) #E4C5A1 srgb(228,197,161)
Now I would like to either convert that or simply just get it in the following format:
#453B28
#685F51
#8A765C
#827F6B
#A48F72
#D2AC61
#B1A597
#D4B693
#DBBD9D
#E4C5A1
Is there a way to just get the hex values without the Rest ?
Thank you

convert ... | tail -n +2 | awk '{ print $3 }'
Use tail to skip the undesired first line of output.
Then use a simple awk program to keep just the 3rd column.

If you only have 10 colours. you may be prepared to put up with this awkwardness:
convert -size 10x1 gradient: -depth 8 -format "%[hex:p{0,0}]\n%[hex:p{1,0}]\n%[hex:p{2,0}]\n%[hex:p{3,0}]\n%[hex:p{4,0}]\n%[hex:p{5,0}]\n%[hex:p{6,0}]\n%[hex:p{7,0}]\n%[hex:p{8,0}]\n%[hex:p{9,0}]\n" info:
FFFFFF
E3E3E3
C6C6C6
AAAAAA
8E8E8E
717171
555555
393939
1C1C1C
000000
Other than that, I don't know of a native way to do as you ask, and Jonathon's method is as good as any. Another option may be like this, where I create a little image with a red, green, blue and white pixel then dump it as RGB and use xxd to format it in columns of 3 for R,G,B:
convert xc:red xc:lime xc:blue xc:white +append -depth 8 rgb: | xxd -p -c3
ff0000 # red
00ff00 # green
0000ff # blue
ffffff # white
I added the colour names for clarification - they don't actually come out of the process.

Related

Can I get a list of the number of different color pixels with ImageMagick?

Let's say I have the following image:
When I use the ImageMagick, the command identify -format %k image.png counts the number of different colors on this image. My output for this image is 1031, which would mean that this image has 1031 different colors. However, visually saying I have around 5 different colors:
black
white
grey
light green
dark green
I'd like to find a way of getting a list of the number of major color pixels. For example, let's say that I have 1000 pixels on the last image, so I'd expect something like:
black:10
white:50
grey:200
light green:690
dark green:50
Is there any way to make ImageMagick display output values like the last ones? Just so I'll know the percentage of the main colors on my image?
You can load the image, tell ImageMagick you want it reduced to 5 colours and then get the histogram like this:
magick 0N9iv.png -colors 5 -verbose info: | grep -A5 Histogram:
Histogram:
459: (181.83,198.952,162.503,229.414) #B6C7A3E5 srgba(71.306%,78.0204%,63.7265%,0.899662)
26749: (182.035,228.807,158.076,254.874) #B6E59EFF srgba(71.3861%,89.7283%,61.9907%,0.999506)
577: (191.945,227.688,174.459,100.095) #C0E4AE64 srgba(75.2725%,89.2894%,68.4152%,0.392528)
727: (196.666,220.169,180.959,255) #C5DCB5FF srgba(77.124%,86.3407%,70.9642%,1)
4384: (219.415,217.829,213.189,255) #DBDAD5FF srgba(86.045%,85.423%,83.6034%,1)
Note that means that ImageMagick chooses the colours itself. If you specifically want your image mapped to your own particular set of colours, make a palette of those colours like this:
magick xc:black xc:white xc:gray xc:lightgreen xc:darkgreen +append palette.png
And then tell ImageMagick to map all the colours to those 5 colours and see the output:
magick 0N9iv.png +dither -remap palette.png -verbose info: | grep -A5 Histogram:
Sample output
Histogram:
81: (0,0,0,255) #000000FF black
22: (126,126,126,255) #7E7E7EFF gray
28270: (144,238,144,255) #90EE90FF LightGreen
4523: (255,255,255,255) #FFFFFFFF white
Colormap entries: 5
You can also select just the histogram like this:
magick 0N9iv.png +dither -remap palette.png -format %c histogram:info:-
Sample Output
81: (0,0,0,255) #000000FF black
22: (126,126,126,255) #7E7E7EFF gray
28270: (144,238,144,255) #90EE90FF LightGreen
4523: (255,255,255,255) #FFFFFFFF white

How can I fix PNG's gamma using ImageMagick?

I'd like to fix a PNG's gamma value to 1/2.2. For example, let's say there is a png image whose gAMA value is 1/4.4. For some reasons, I have to fix the value to 1/2.2. So I try convert command like below.
# 0.5 is led by (1/4.4)/(1/2.2)
# 0.45455 is led by 1/2.2
$ convert orig.png -gamma 0.5 +gamma 0.45455 new.png
Then, I compare two images, orig.png and new.png, but they appear to be different.
I guess the formula, (1/4.4)/(1/2.2), is wrong. Does anyone know the correct way to do it?
Thanks.
EDITED:
Sorry, but maybe I could not tell you what I really want to do. So, I added more information and sample images.
First of all, I have the below image. This image's gAMA is about 0.227(1/4.4).
And then, I need this image. The image's gAMA is 0.4545(1/2.2) but the appearance is same as the above one.
So, I don't need this. This image's gAMA is also 0.4545(1/2.2), but the appearance is different from the first one.
This seems to work for me in Imagemagick.
convert red44.png -gamma 0.5 -set gamma 0.4545 red22_new.png
identify -verbose red22_new.png
...
Gamma: 0.4545
...
I have been experimenting some more and I am not sure this answer is correct, but I'll leave it a while so that Fred and Eric and Glenn (#GlennRandersPehrson) can see it and maybe correct it or comment on it. I also don't understand why this:
convert start.png -set png:gAMA 2 -verbose info: | grep -i -C5 gam
differs from this:
convert start.png -set png:gAMA 2 tmp.png
identify -verbose tmp.png | grep -i -C5 gam
I think I see what is happening - in a nutshell, I don't think the PNG encoder is picking up the gamma correctly.
Let's make a single pixel image with value 100 so we can see what happens to it when transformed:
convert xc:"gray(100)" start.png
Let's inspect it:
convert start.png txt:
# ImageMagick pixel enumeration: 1,1,65535,gray
0,0: (25700) #646464 gray(100)
Yes, it's definitely 100. Let's check the gamma:
identify -verbose start.png | grep -i gam
Gamma: 0.45455
png:gAMA: gamma=0.45455 (See Gamma, above)
Now let's change the gamma parameter, using either my way, or Fred's (#fmw42) way:
# Change gamma parameter my way
convert start.png +gamma 2 -verbose info: | grep -i gam
Gamma: 2
png:gAMA: gamma=0.45455 (See Gamma, above)
convert start.png +gamma 2 txt:
# ImageMagick pixel enumeration: 1,1,65535,gray
0,0: (25700) #646464 gray(100)
# Change gamma parameter Fred's way
convert start.png -set gamma 2 -verbose info: | grep -i gam
Gamma: 2
png:gAMA: gamma=0.45455 (See Gamma, above)
convert start.png -set gamma 2 txt:
# ImageMagick pixel enumeration: 1,1,65535,gray
0,0: (25700) #646464 gray(100)
As you can see, neither way has changed the pixel values themselves, both ways have changed the ImageMagick internal gamma, but crucially neither has done what you need, which is to change the PNG encoder's gamma. A little experimentation shows you need:
convert start.png -set png:gAMA 2 -verbose info: | grep -i gam
Gamma: 0.45455
png:gAMA: 2
So, I think that is the answer - namely use:
convert input.png -set png:gAMA XYZ result.png
Just for future readers, if you want to change the pixel values themselves rather than just the gamma parameter, do this:
# Set gamma of 2, initial pixel value 100 becomes 160
convert start.png -gamma 2 txt:
# ImageMagick pixel enumeration: 1,1,65535,gray
0,0: (41039.6) #A0A0A0 gray(160)
# Set gamma of 0.5, initial pixel value 100 becomes 39
convert start.png -gamma 0.5 txt:
# ImageMagick pixel enumeration: 1,1,65535,gray
0,0: (10078.4) #272727 gray(39)
In Imagemagick, just use -set gamma:
convert image.png -set gamma 0.4545 image.png
That will simply change the gamma value, but not change the pixel values. If you need to do that, then you should use (as Mark Setchell suggested). But if you want 1/2.2 and have 1/4.4, then you need a value of (1/2.2)/(1/4.4)=2
convert image.png -gamma 2 image.png

Extracting data digitally

I have 200 copies of this page(15 * 10 matrix) and i have to write all the numbers from 0 - 9 in each corresponding cell and then extract those digits digitally in a seperate image of (32*32 pixels) for each digit, after scanning each page once. How can i achieve this? This is required for my research purpose. I am a CS student so i can code too.
Update:
For mark : Here is one of the scanned image
This is for some local language ( 0 - 9) ..
Update 2:
The commands for the previous image are working fine but on new images,something is getting wrong(some kind of offsets)..
I am attaching the image below
What changes do u suggest ?
Updated Answer
I have taken your feedback and improved the algorithm to the following bash script now...
#!/bin/bash
################################################################################
# dice
#
# Trim borders off an image (twice) and then dice into 10x15 cells.
#
# Usage: ./dice image
################################################################################
# Pick up image name from first parameter
image="$1"
echo DEBUG: Processing image $image...
# Apply median filter to remove noisy black dots around image and then get the
# dimensions of the "trim box" - note we don't use the (degraded) median-filtered image in
# later steps.
trimbox=$(convert "$image" -median 9x9 -fuzz 50% -format %# info:)
echo DEBUG: trimbox $trimbox
# Now trim original unfiltered image into stage1-$$.png (for debug)
convert "$1" -crop $trimbox +repage stage1-$$.png
echo DEBUG: Trimmed outer: stage1-$$.png
# Now trim column headings
convert stage1-$$.png -crop 2000x2590+120+190 +repage stage2-$$.png
echo DEBUG: Trimmed inner: stage2-$$.png
# Now slice into 10x15 rectangles
echo DEBUG: Slicing and dicing
convert stage2-$$.png -crop 10x15# +repage rectangles-%03d.png
# Now trim the edges off the rectangles and resize all to a constant size
for f in rectangles*png; do
echo DEBUG: Trimming and resizing $f
trimbox=$(convert "$f" -median 9x9 -shave 15x15 -bordercolor black -border 15 -threshold 50% -floodfill +0+0 white -fuzz 50% -format %# info:)
echo DEBUG: Cell trimbox $trimbox
convert "$f" -crop $trimbox +repage -resize 32x32! "$f"
done
Here are the resulting cells - i.e. 150 separate image files. I have put a red border around the individual cells/files so you can see their extent:
Original Answer
I would do that with ImageMagick which is free and installed on most Linux distros and is available for OSX and Windows too. There are Perl, PHP, Java, node, .NET, Ruby, C/C++ bindings too if you prefer those languages. Here I am using the command line in Terminal.
First job is to get rid of noise and trim the outer edges:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage trimmed1.png
Now, trim again to get rid of outer frame and column titles across the top:
convert trimmed1.png -crop 2000x2590+120+190 +repage trimmed2.png
Now divide into 10 cells by 15 cells and save as rectangles-nnn.png
convert trimmed2.png -crop 10x15# rectangles-%03d.png
Check what we got - yes, 150 images:
ls -l rect*
rectangles-000.png rectangles-022.png rectangles-044.png rectangles-066.png rectangles-088.png rectangles-110.png rectangles-132.png
rectangles-001.png rectangles-023.png rectangles-045.png rectangles-067.png rectangles-089.png rectangles-111.png rectangles-133.png
rectangles-002.png rectangles-024.png rectangles-046.png rectangles-068.png rectangles-090.png rectangles-112.png rectangles-134.png
rectangles-003.png rectangles-025.png rectangles-047.png rectangles-069.png rectangles-091.png rectangles-113.png rectangles-135.png
rectangles-004.png rectangles-026.png rectangles-048.png rectangles-070.png rectangles-092.png rectangles-114.png rectangles-136.png
rectangles-005.png rectangles-027.png rectangles-049.png rectangles-071.png rectangles-093.png rectangles-115.png rectangles-137.png
rectangles-006.png rectangles-028.png rectangles-050.png rectangles-072.png rectangles-094.png rectangles-116.png rectangles-138.png
rectangles-007.png rectangles-029.png rectangles-051.png rectangles-073.png rectangles-095.png rectangles-117.png rectangles-139.png
rectangles-008.png rectangles-030.png rectangles-052.png rectangles-074.png rectangles-096.png rectangles-118.png rectangles-140.png
rectangles-009.png rectangles-031.png rectangles-053.png rectangles-075.png rectangles-097.png rectangles-119.png rectangles-141.png
rectangles-010.png rectangles-032.png rectangles-054.png rectangles-076.png rectangles-098.png rectangles-120.png rectangles-142.png
rectangles-011.png rectangles-033.png rectangles-055.png rectangles-077.png rectangles-099.png rectangles-121.png rectangles-143.png
rectangles-012.png rectangles-034.png rectangles-056.png rectangles-078.png rectangles-100.png rectangles-122.png rectangles-144.png
rectangles-013.png rectangles-035.png rectangles-057.png rectangles-079.png rectangles-101.png rectangles-123.png rectangles-145.png
rectangles-014.png rectangles-036.png rectangles-058.png rectangles-080.png rectangles-102.png rectangles-124.png rectangles-146.png
rectangles-015.png rectangles-037.png rectangles-059.png rectangles-081.png rectangles-103.png rectangles-125.png rectangles-147.png
rectangles-016.png rectangles-038.png rectangles-060.png rectangles-082.png rectangles-104.png rectangles-126.png rectangles-148.png
rectangles-017.png rectangles-039.png rectangles-061.png rectangles-083.png rectangles-105.png rectangles-127.png rectangles-149.png
rectangles-018.png rectangles-040.png rectangles-062.png rectangles-084.png rectangles-106.png rectangles-128.png
rectangles-019.png rectangles-041.png rectangles-063.png rectangles-085.png rectangles-107.png rectangles-129.png
rectangles-020.png rectangles-042.png rectangles-064.png rectangles-086.png rectangles-108.png rectangles-130.png
rectangles-021.png rectangles-043.png rectangles-065.png rectangles-087.png rectangles-109.png rectangles-131.png
Look at first couple:
You can do those 3 steps in 1 like this:
convert scan.jpg -median 3x3 -fuzz 50% -trim +repage \
-crop 2000x2590+120+190 +repage \
-crop 10x15# rectangles-%03d.png
You may want to shave a few pixels off each side of each image and resize to 32x32 with something like (untested):
mogrify -shave 3x3 -resize 32x32! rectangles*png

IMAGEMAGICK: Filling when label contains blanks

I am using imagemagick to create some simple graphics using the Dymo font. Here is an example:
convert -background White -fill DarkRed -font Dymo -pointsize 72 label:"DYMO FONT" -trim name.png
This command creates a file that looks like this:
I would like the red to fill all the way across, so that the image looks like a single label. I plan to use this on a page with a black background, which makes it look even worse.
I have played around with this for a while with no luck. Help would be appreciated.
Version: ImageMagick 6.9.2-7 Q16 x86_64 2015-12-06
O/S: Fedora 23
I don't know why it does that, but you can generate the text you want by replacing the space with a UTF non-breaking space and sending that to the stdin of convert and asking -label to read its text from the "file" called stdin:
printf "DYMO\xc2\xa0FONT" |
convert -background white -fill DarkRed -font DYMO -pointsize 72 label:#- result.png
Add -trim just before the output filename if you want the extraneous white space trimmed off from around the edges.
If you had more complicated text and didn't want to do that for all spaces, you could replace spaces using a short piece of Perl or sed to do it for you...
echo -n "Text with lots of spaces." | sed 's/ /\xC2\xA0/g' | convert -background white -fill DarkRed -font dymo -pointsize 72 label:#- -trim label.png

ImageMagick: How can i work with histogram result?

im getting the most existing colors of an image and display it with the "histogram" funktion like
convert image.jpg -scale 100x100 -gravity \
center -crop 50% -dither None -remap color_map.gif \
-format %c histogram:info:
22: ( 0, 0, 0) #000000 black
881: (119,133,142) #77858E rgb(119,133,142)
268: (186, 84, 29) #BA541D rgb(186,84,29)
662: (212,212,212) #D4D4D4 grey83
20: (244,203, 98) #F4CB62 rgb(244,203,98)
647: (255,255,255) #FFFFFF white
Ho can i work now with this output? i want to save the most existing color in my database, but i dont know how to get now only the color with the number 881.
Can any one help me?
If you want to do this purely from the shell (assuming Bash-like Unix environment), something like this would work:
convert image.jpg -scale 100x100 -gravity center \
-crop 50% -dither None -remap color_map.gif \
-format %c histogram:info: | sort | tail -n1 | \
sed -e 's/.*\(#[0-9A-F]\+\).*/\1/'
That takes the output from ImageMagick, sorts it so the largest color count is on the bottom, takes just that line, then extracts the color hex from the line. You can tweak the sed regex if your goal is to get the decimal rgb values instead of the hex.
So for your example image, the output should be just:
#77858E

Resources