Pixel RGB with ImageMagick and Rails
Your ImageMagick is compiled for a quantum depth of 16 bits, versus 8 bits. See this article in the RMagick Hints & Tips Forum for more information.
rmagick pixel color value
They are stored in a 'quantum depth' of 16-bits. You can rebuild the library to change this. Or you can simply divide each value by 257.
There's a function called MagickExportImagePixels which can get you the 8-bit pixel data that you want. Whenever you perform a transformation etc on an image it will get converted back to 16-bit pixels.
Read an image pixel by pixel in Ruby
You can use Rmagick
's each_pixel
method for this. each_pixel
receives a block. For each pixel, the block is passed the pixel, the column number and the row number of the pixel. It iterates over the pixels from left-to-right and top-to-bottom.
So something like:
pixels = []
img.each_pixel do |pixel, c, r|
pixels.push(pixel)
end
# pixels now contains each individual pixel of img
ImageMagick: Decreasing RGB values of all pixels in an image
Honestly, I don't really understand what the value 25700
in your commandline should achieve.
However, I suggest a different commandline to you, using the more powerful -fx
operator. A bit more complicated looking, but hopefully more intuitively to understand...
But first, I'm looking at your description and see you want to subtract a fixed number of 120
from each of the current R, G, and B color values. So this is a gray pixel color... and as you can look up in ImageMagick's color built-in color list, its name is gray47
:
convert -list color | grep '(120,120,120)'
gray47 srgb(120,120,120) X11 XPM
grey47 srgb(120,120,120) SVG X11
This leads me to the following command:
convert \
input.jpg \
-channel red -fx 'r - gray47' \
-channel green -fx 'g - gray47' \
-channel blue -fx 'b - gray47' \
output.jpg
This way or writing the command will probably open your eyes to some easily derived modifications should you need those in future...
To have an immediate preview window of the result popping up (without writing it to a file) you can also use -show:
as output, like this:
convert \
input.jpg \
-channel red -fx 'r - gray47' \
-channel green -fx 'g - gray47' \
-channel blue -fx 'b - gray47' \
-show:
Update
If you want to check for the real differences of each pixel, you can make ImageMagick print out the color value for each pixel:
convert input.jpg input.txt
convert output.jpg output.txt
The format of the .txt file is pretty easy to understand, once you know that the first columns give the Pixel zero-based coordinates: 123,456:
means: 124th (!) column, 457th () row.
Now you can compare the two .txt files to your heart's content even in an automated, scripted version, without a need to resort to Gimp. :-)
You could even use input.txt
and apply a Perl-, Ruby-, Python- or Shellscript onto each of the pixel values to distract your 120
value from each channel, save it as output2.txt and then convert it back to JPEG:
convert output2.txt output2.jpg
Then look for pixel differences between the two output images:
compare output.jpg output2.jpg delta.jpg
compare output.jpg output2.jpg view:
An all-white plane will mean 'no differences' , any red pixels will hint to some sort of delta.
Now if that answer doesn't earn me an upvote, I don't know which would... :-)
ImageMagick get pixel color by x y coordinates
If you want pixel at (19,14), you need:
magick image.png -format "%[hex:u.p{19,14}]\n" info:
Or:
magick image.png -crop 1x1+19+14 -format "%[hex:u.p{0,0}]\n" info:
How to get RGB pixel values in text for whole image with ImageMagick?
A Further Option
If you want to amortize the cost of running identify
across lots of images for better performance, you can do something like this - where %k
gives you the number of colours and %n
gives you the filename:
identify -format "%k:%f\n" *.jpg
Output
290972:7T6Dj.jpg
3641:a.jpg
8349:b.jpg
3019:back.jpg
3122:background.jpg
83155:blion.jpg
35136:brDaP.jpg
37106:cartesian.jpg
There must be a system()
or shell_exec()
or popen()
in Java that could run that so you could get the output.
Updated Answer
If you simply want to check whether the image consists of only a single colour, you can ask ImageMagick to count the colours, like this (using the same image as below):
identify -format "%k" a.gif
3
I am not sure how you do that with Java, but in Ruby you do:
image["%[k]"]
and in Perl you do:
my $image = Image::Magick->new;
$image->ReadImage("c.png");
print $image->Get("%[k]");
Original Answer
You provided no details of your environment, programming language, application or anything much, however, this may get you started.
Let's create a small image from the command line, with 3 squares, each 4x4 pixels, one red, one green and one blue all in a horizontal row:
convert -size 4x4 xc:red xc:green xc:blue +append a.gif
I'll zoom it in so you can see it:
Now, we can look at it in text format:
convert -size 4x4 xc:red xc:green xc:blue +append -depth 8 txt:
# ImageMagick pixel enumeration: 12,4,255,srgb
0,0: (255,0,0) #FF0000 red
1,0: (255,0,0) #FF0000 red
2,0: (255,0,0) #FF0000 red
3,0: (255,0,0) #FF0000 red
4,0: (0,128,0) #008000 green
5,0: (0,128,0) #008000 green
6,0: (0,128,0) #008000 green
7,0: (0,128,0) #008000 green
8,0: (0,0,255) #0000FF blue
9,0: (0,0,255) #0000FF blue
10,0: (0,0,255) #0000FF blue
11,0: (0,0,255) #0000FF blue
0,1: (255,0,0) #FF0000 red
1,1: (255,0,0) #FF0000 red
2,1: (255,0,0) #FF0000 red
3,1: (255,0,0) #FF0000 red
4,1: (0,128,0) #008000 green
5,1: (0,128,0) #008000 green
6,1: (0,128,0) #008000 green
7,1: (0,128,0) #008000 green
8,1: (0,0,255) #0000FF blue
9,1: (0,0,255) #0000FF blue
10,1: (0,0,255) #0000FF blue
11,1: (0,0,255) #0000FF blue
0,2: (255,0,0) #FF0000 red
1,2: (255,0,0) #FF0000 red
2,2: (255,0,0) #FF0000 red
3,2: (255,0,0) #FF0000 red
4,2: (0,128,0) #008000 green
5,2: (0,128,0) #008000 green
6,2: (0,128,0) #008000 green
7,2: (0,128,0) #008000 green
8,2: (0,0,255) #0000FF blue
9,2: (0,0,255) #0000FF blue
10,2: (0,0,255) #0000FF blue
11,2: (0,0,255) #0000FF blue
0,3: (255,0,0) #FF0000 red
1,3: (255,0,0) #FF0000 red
2,3: (255,0,0) #FF0000 red
3,3: (255,0,0) #FF0000 red
4,3: (0,128,0) #008000 green
5,3: (0,128,0) #008000 green
6,3: (0,128,0) #008000 green
7,3: (0,128,0) #008000 green
8,3: (0,0,255) #0000FF blue
9,3: (0,0,255) #0000FF blue
10,3: (0,0,255) #0000FF blue
11,3: (0,0,255) #0000FF blue
But you say that it takes too long to get one 1 pixel, so you can convert the image to a file that is just pure RGB values and read that:
convert -size 4x4 xc:red xc:green xc:blue +append -depth 8 x.rgb
If we look at the file, we can see it is 144 pixels long, 16 red pixels, 16 green pixels, 16 blue pixels - therefore 48 pixels altogether - and each one with a single byte of R, G and B. (48x3=144)
ls -l x.rgb
-rw-r--r-- 1 mark staff 144 29 Oct 11:06 x.rgb
ImageMagick uses the file extension to determine the format, and rgb
means RGB
!. If you want to use an extension different from .rgb
, you can tell ImageMagick like this:
convert -size 4x4 xc:red xc:green xc:blue +append -depth 8 RGB:x.raw
Now let's look at the file in hex:
xxd -g3 -c12 x.rgb
0000000: ff0000 ff0000 ff0000 ff0000 ............
000000c: 008000 008000 008000 008000 ............
0000018: 0000ff 0000ff 0000ff 0000ff ............
0000024: ff0000 ff0000 ff0000 ff0000 ............
0000030: 008000 008000 008000 008000 ............
000003c: 0000ff 0000ff 0000ff 0000ff ............
0000048: ff0000 ff0000 ff0000 ff0000 ............
0000054: 008000 008000 008000 008000 ............
0000060: 0000ff 0000ff 0000ff 0000ff ............
000006c: ff0000 ff0000 ff0000 ff0000 ............
0000078: 008000 008000 008000 008000 ............
0000084: 0000ff 0000ff 0000ff 0000ff ............
Hopefully you can see the first line is 4 red pixels, the second line is 4 green ones...
So, in short, if you want to just read pure binary data from an image into a C program, you can do this:
convert YourImage.jpg -depth 8 RGB:- | YourProgram
Converting colors (not images) with ImageMagick
In ImageMagick, you can do the following:
convert xc:"cmyk(0,255,255,0)" -colorspace sRGB -format "%[pixel:u.p{0,0}]\n" info:
red
convert xc:"cmyk(0,255,255,0)" -profile /Users/fred/images/profiles/USWebCoatedSWOP.icc -profile /Users/fred/images/profiles/sRGB.icc -format "%[pixel:u.p{0,0}]\n" info:
srgb(93%,11%,14%)
Imagemagick: How does RGB work with this software?
I am not 100% certain what you mean as you haven't provided a sample of what other software does, but I'll have a try and see if we can get there.
So, if we make a starting image, including your presumed shades of magenta on the left and some test colours on the right:
convert -size 256x256 gradient:black-magenta -size 50x256 \
xc:black xc:white xc:red xc:lime xc:blue +append start.png
And, you want to change magenta shades into blue. I would call that a hue modulation, so I would want to find out the hue angle between blue and magenta, so I would create a 2x1 image with one magenta and one blue pixel and get their HSI values:
convert xc:magenta xc:blue -append -colorspace hsi txt:
Output
# ImageMagick pixel enumeration: 1,2,65535,hsi
0,0: (54612.5,65535,43690) #D555FFFFAAAA hsi(300,100%,66.6667%)
0,1: (43690,65535,21845) #AAAAFFFF5555 hsi(240,100%,33.3333%)
And I can see their hues are 60 degrees apart (300-240). So I would use the -modulate
operator, which takes a Brightness, Saturation and Hue, leave the first two unchanged at 100%, and modify the Hue by 60 degrees:
convert start.png -modulate 100,100,60 result.png
Or maybe that is not what you mean? Maybe you only mean to affect specific colour. If so, it gets harder... but not that hard :-)
First, extract the Hue, Saturation and Brightness layers to separate files:
convert start.png -colorspace HSL -separate -colorspace gray HSL-%d.png
That will give us the Hue as a single channel greyscale image in HSL-0.png
, the Saturation in HSL-1.png
and the Lightness in HSL-2.png
.
Now we want to make a new LUT (Lookup Table) for the Hue channel, so we make a 360 pixel long LUT that maps 1:1, i.e. everything maps to normal.
convert -size 1x360 gradient: -rotate 90 greyscale.png
Then we want to dink with the lookups around magenta (300) and make them blue (240). So we want to subtract 60 degrees (which is 0.16 if you scale 0-360 degrees onto the range 0-1) from all pixels in the range 280-320 so there is some tolerance:
convert -size 1x360 gradient: -rotate 90 -colorspace gray -fx "i<280||i>320?u:u-0.16" hueCLUT.png
Now apply that LUT to the Hue of the original image and rebuild it...
convert HSL-0.png -colorspace gray hueCLUT.png -clut HSL-1.png HSL-2.png -set colorspace HSL -combine -colorspace RGB result.png
So, as a simpler script, that might become:
#!/bin/bash
# Make a hue CLUT, transforming magenta hues to blue
convert -size 1x360 gradient: -rotate 90 -colorspace gray -fx "i<295||i>305?u:u-0.16" -resize 256x1! hueclut.png
# Apply to the hue channel
convert start.png -colorspace HSL -write MPR:HSL \
-channel R -separate hueclut.png -clut \
\( MPR:HSL -channel G -separate \) \
\( MPR:HSL -channel B -separate \) \
-set colorspace HSL -combine -colorspace RGB result.png
Related Topics
How to Implement Editing/Formating Text Area in Rails
How to HTML_Escape Text Data in a Sinatra App
Ruby Range: Operators in Case Statement
How to Split String into 2 Parts After Certain Position
Rails: Organizing Models in Subfolders Having Warning: Toplevel Constant a Referenced by B::A
Ruby - Convert Integer to String
How to Get the Nth Element of an Enumerable in Ruby
Why Does Single '=' Work in 'If' Statement
Return True Only If All Values Evaluate to True in Ruby
Openssl::Cipher::Ciphererror When Running Staging Db on Local
How to Get the File Creation Time in Ruby on Windows
How Does Sinatra Define and Invoke the Get Method
Permanently Switching User in Capistrano 3 (Separate Authorization & Deploy)
Ruby Tcpserver to Get Client Ip Address
How to Parse Mailbox File in Ruby