Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I need to convert an RGB raw file into 3 files containing each the red, green and blue channel. I have not been able to find a UNIX command line to help me with this task.

share|improve this question
    
How does the RGB data organized? RGB RGB RGB or RRR GGG BBB? –  LiuYan 刘研 Feb 22 '13 at 10:21
    
Just to be clear, this is a simple binary file, not digital camera output in so-called "RAW" format, right? –  mattdm Feb 22 '13 at 10:47
    
This is exactly a binary file containing only rgb data, no header information. file is organized as RGB RGB RGB –  malat Feb 22 '13 at 11:29
add comment

3 Answers

up vote 4 down vote accepted

Have you tried the netpbm tools? This will work with R8G8B8 and other 8-bit RGB orders.

For a width 100 height 200 RGB order raw file:

rawtoppm -rgb 100 200 input.rgb > image.ppm
ppmtorgb3 image.ppm 

You will now have 3 pgm format grey-map files, each suffixed .red .grn and .blu. These .pgm files are almost a raw binary format, except for the short header, so:

tail +4 image.red > image_r.raw
tail +4 image.grn > image_g.raw
tail +4 image.blu > image_b.raw

if you really want the raw channels like that. Or, for further processing:

pgmtoppm red   image.red > image_red.ppm
pgmtoppm green image.grn > image_grn.ppm 
pgmtoppm blue  image.blu > image_blue.ppm

You now have three ppmformat files which are the separated RGB channels (see also rgb3toppm). These can be convert to other formats using ppmtoX, e.g. ppmtopng. Use "white" instead of the colour in the 2nd parameter to leave each as a grey scale.

Imagemagick's convert may also be also useful, it will handle RGB, RGBA and 16-bit raw formats too, and it has a -separate option to split channels.

for ch in R G B; do
  convert -set colorspace RGB -size 100x200 -depth 8 rgb:image.rgb \
      -channel ${ch} -separate -depth 8 gray:image_${ch}.raw
done

Check that the -set colorspace option is appropriate for your input. Newer versions let you do this in a single command, see http://www.imagemagick.org/Usage/color_basics

convert ... -channel RGB -separate gray:image_%d.raw

and R/G/B will be written to image_0.raw image_1.raw image_2.raw files


Note, convert command was updated based on help and feedback from Stephane Chazelas, there were several changes to colorspace behaviour from ImageMagic-6.7.7 which cause problems due to (I believe) sRGB being used instead of RGB.

  # colorspace changes mean this works differently after ImageMagick-6.7.6
  convert -size 100x200 -depth 8 rgb:image.rgb \
      -channel ${ch} -separate -depth 8 gray:image_${ch}.raw
share|improve this answer
    
echo -n '\x40\x50\x60' | convert -size 1x1 -depth 8 rgb:- -channel R -separate -depth 8 gray:- | od -An -tx1 gives me 0xd instead of 0x40. –  Stephane Chazelas Feb 22 '13 at 12:06
    
Try using printf instead of echo, that works for me. –  mr.spuratic Feb 22 '13 at 12:09
1  
The echo -n '\x40\x50\x60' does output the three bytes 0x40, 0x50 and 0x60 in my shell (zsh), but still, convert outputs one 0xd byte. I've just tested with the latest version released three days ago. Does it output 0x40 for you? Note that when converting to rgb:- instead of gray:-, I do see 0x40 0x40 0x40 as expected. –  Stephane Chazelas Feb 22 '13 at 12:32
    
It works if I add -set colorspace RGB (or -set colorspace Gray for that matters) and change -channel R -separate to -fx r. –  Stephane Chazelas Feb 22 '13 at 12:39
    
6.2.2 and 6.3.2 both work as expected, let me build 6.8.3-3 ... –  mr.spuratic Feb 22 '13 at 12:51
show 2 more comments

With ksh93, you can do:

command /opt/ast/bin/cut -r3 -Nb1 < file > red
command /opt/ast/bin/cut -r3 -Nb2 < file > green
command /opt/ast/bin/cut -r3 -Nb3 < file > blue

(yes, I know, there's no /opt/ast/bin/cut on your system, but chances are ksh93 still has a builtin for it).

With perl:

perl -F -ane '
  BEGIN{
    $/=\3;
    map {open $f[$n++], ">", $_} qw{red green blue}
  }
  for $i (0..2) {print {$f[$i]} $F[$i]}'

With only standard Unix tools, you can do:

od -vAn -tu1 < file |
  tr -cs 0-9 '[\n*]' |
  grep . |
  paste - - - |
  awk '{printf "%c", $1 > "red"
        printf "%c", $2 > "green"
        printf "%c", $3 > "blue"}'

Those would split a 123123123123 "file" into a 1111 "red", 2222 "green" and 3333 "blue". If instead you want a "red" file that has 100100100100, that is still a RGB file but where the other colours have been suppressed, you'd need to adapt the code above to output the extra NUL bytes for the other colours, or you could use an image manipulation utility like ImageMagick convert:

size=$(wc -c < file)
convert -size "1x$size" -channel GB -fx 0 rgb:- rgb:- < file > red
# ...and so on for green and blue
share|improve this answer
add comment

You can also do channel separation using MATLAB. Read this: http://blogs.mathworks.com/steve/2011/03/08/tips-for-reading-a-camera-raw-file-into-matlab/ this shows how to read RAW data. Separating channels in MATLAB is easy, like sampling some elements in matrix.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.