Pixel Rgb with Imagemagick and Rails

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:

Sample Image

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

Sample Image

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

Sample Image


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

Sample Image

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

Sample Image

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

Sample Image

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



Leave a reply



Submit