changeset 11688:101a3bd532ed octave-forge

ycbcr2rgb: new function * private/ycbcrfunc: private function for code of ycbcr2rgb and rgb2ycbcr functions which are very similar * rgb2ycbcr: move most of the code to new private function and share with new ycbcr2rgb function * ycbcr2rgb: new function * INDEX: add enw function * NEWS: mention new function
author carandraug
date Sun, 05 May 2013 16:18:48 +0000
parents 2c39ee206f66
children a5e636ebf237
files main/image/INDEX main/image/NEWS main/image/inst/private/ycbcrfunc.m main/image/inst/rgb2ycbcr.m main/image/inst/ycbcr2rgb.m
diffstat 5 files changed, 157 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/main/image/INDEX	Sun May 05 07:48:19 2013 +0000
+++ b/main/image/INDEX	Sun May 05 16:18:48 2013 +0000
@@ -51,6 +51,7 @@
  colorgradient
  rgb2ycbcr
  wavelength2rgb
+ ycbcr2rgb
 Display
  rgbplot
 Enhancement and Restoration
--- a/main/image/NEWS	Sun May 05 07:48:19 2013 +0000
+++ b/main/image/NEWS	Sun May 05 16:18:48 2013 +0000
@@ -11,6 +11,7 @@
       strel
       tformfwd
       tforminv
+      ycbcr2rgb
 
  ** The following functions have been moved from the Octave Forge Image package
     to GNU Octave core:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/image/inst/private/ycbcrfunc.m	Sun May 05 16:18:48 2013 +0000
@@ -0,0 +1,103 @@
+## Copyright (C) 2013 Carnë Draug <carandraug+dev@gmail.com>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+## Private function for ycbcr2rgb and rgb2ycbcr functions which are
+## very similar
+
+function out = ycbcrfunc (func, in, standard)
+
+  img = false; # was input an image?
+  if (iscolormap (in))
+    ## do nothing, it's a colormap
+  elseif (isrgb (in))
+    img = true;
+    ## we shape it as a colormap (2D matrix) so we can use matrix multiplcation
+    nRows = rows (in);
+    nCols = columns (in);
+    in    = reshape (in, [nRows*nCols 3]);
+  else
+    error ("%s: input must be a colormap (Nx3) or RGB image (NxMx3)", func);
+  endif
+
+  if (ischar (standard))
+    if (strcmpi (standard, "601")) # for ITU-R BT.601
+      Kb = 0.114;
+      Kr = 0.299;
+    elseif (strcmpi (standard, "709")) # for ITU-R BT.709
+      Kb = 0.0722;
+      Kr = 0.2126;
+    else
+      error ("%s: unknown standard `%s'", func, standard);
+    endif
+  elseif (isnumeric (standard) && numel (standard) == 2)
+    Kb = standard(1);
+    Kr = standard(2);
+  else
+    error ("%s: must specify a standard (string), or Kb and Kr values", func);
+  endif
+
+  ## the color matrix for the conversion. Derived from:
+  ##    Y  = Kr*R + (1-Kr-Kb)*G + kb*B
+  ##    Cb = (1/2) * ((B-Y)/(1-Kb))
+  ##    Cr = (1/2) * ((R-Y)/(1-Kr))
+  ## It expects RGB values in the range [0 1], and returns Y in the
+  ## range [0 1], and Cb and Cr in the range [-0.5 0.5]
+  cmat = [  Kr            (1-Kr-Kb)            Kb
+          -(Kr/(2-2*Kb)) -(1-Kr-Kb)/(2-2*Kb)   0.5
+            0.5          -(1-Kr-Kb)/(2-2*Kr) -(Kb/(2-2*Kr)) ];
+
+  cls = class (in);
+  in  = im2double (in);
+
+  ## note that these blocks are the inverse of one another. Changes
+  ## in one will most likely require a change on the other
+  if (strcmp (func, "rgb2ycbcr"))
+    ## convert to YCbCr colorspace
+    out = (cmat * in')'; # transpose at the end to get back colormap shape
+    ## rescale Cb and Cr to range [0 1]
+    out(:, [2 3]) += 0.5;
+    ## footroom and headroom will take from the range 16/255 each for Cb and Cr,
+    ## and 16/255 and 20/255 for Y. So we have to compress the values of the
+    ## space, and then shift forward
+    out(:,1)     = (out(:,1) * 219/255) + 16/255;
+    out(:,[2 3]) = (out(:,[2 3]) * 223/255) + 16/255;
+
+  elseif (strcmp (func, "ycbcr2rgb"))
+    ## just the inverse of the rgb2ycbcr conversion
+    in(:,[2 3])  = (in(:,[2 3]) - 16/255) / (223/255);
+    in(:,1)      = (in(:,1) - 16/255) / (219/255);
+    in(:,[2 3]) -= 0.5;
+    out          = (inv (cmat) * in')';
+  else
+    error ("internal error for YCbCr conversion. Unknown function %s", func);
+  endif
+
+  switch (cls)
+    case {"single", "double"}
+      ## do nothing. All is good
+    case "uint8"
+      out = im2uint8 (out);
+    case "uint16"
+      out = im2uint16 (out);
+    otherwise
+      error ("%s: unsupported image class %s", func, cls);
+  endswitch
+
+  if (img)
+    ## put the image back together
+    out = reshape (out, [nRows nCols 3]);
+  endif
+
+endfunction
--- a/main/image/inst/rgb2ycbcr.m	Sun May 05 07:48:19 2013 +0000
+++ b/main/image/inst/rgb2ycbcr.m	Sun May 05 16:18:48 2013 +0000
@@ -41,76 +41,10 @@
 ## @end deftypefn
 
 function ycbcr = rgb2ycbcr (rgb, standard = "601")
-
-  img = false; # was input an image?
-
   if (nargin < 1 || nargin > 2)
     print_usage ();
   endif
-
-  if (iscolormap (rgb))
-    ## do nothing, it's a colormap
-  elseif (isrgb (rgb))
-    img = true;
-    ## if we have it in 2D, we can use matrix multiplcation
-    nRows = rows (rgb);
-    nCols = columns (rgb);
-    rgb   = reshape (rgb, [nRows*nCols 3]);
-  else
-    error ("rgb2ycbcr: input must be a colormap (Nx3) or RGB image (NxMx3)");
-  endif
-
-  ## TODO would be interesting to accept arbitrary values of Kb and Kr
-  if (! ischar (standard))
-    error ("rgb2ycbcr; STANDARD must be a string `601' or `709'");
-  elseif (strcmpi (standard, "601"))
-    ## these are the values for ITU-R BT.601
-    Kb = 0.114;
-    Kr = 0.299;
-  elseif (strcmpi (standard, "709"))
-    ## these are the values for ITU-R BT.709
-    Kb = 0.0722;
-    Kr = 0.2126;
-  else
-    error ("rgb2ycbcr: unknown standard `%s'", standard);
-  endif
-
-  ## the color matrix for the conversion. Derived from:
-  ##    Y  = Kr*R + (1-Kr-Kb)*G + kb*B
-  ##    Cb = (1/2) * ((B-Y)/(1-Kb))
-  ##    Cr = (1/2) * ((R-Y)/(1-Kr))
-  ## It expects RGB values in the range [0 1], and returns Y in the
-  ## range [0 1], and Cb and Cr in the range [-0.5 0.5]
-  cmat = [  Kr            (1-Kr-Kb)            Kb
-          -(Kr/(2-2*Kb)) -(1-Kr-Kb)/(2-2*Kb)   0.5
-            0.5          -(1-Kr-Kb)/(2-2*Kr) -(Kb/(2-2*Kr)) ];
-
-  cls   = class (rgb);
-  rgb   = im2double (rgb);
-  ycbcr = (cmat * rgb')'; # transpose in the end to get back colormap shape
-  ## rescale Cb and Cr to range [0 1]
-  ycbcr(:, [2 3]) += 0.5;
-  ## footroom and headroom will take from the range 16/255 each for Cb and Cr,
-  ## and 16/255 and 20/255 for Y. So we have to compress the values of the
-  ## space, and then shift forward
-  ycbcr(:,1) = (ycbcr(:,1) * 219/255) + 16/255;
-  ycbcr(:,[2 3]) = (ycbcr(:,[2 3]) * 223/255) + 16/255;
-
-  switch (cls)
-    case {"single", "double"}
-      ## do nothing. All is good
-    case "uint8"
-      ycbcr = im2uint8 (ycbcr);
-    case "uint16"
-      ycbcr = im2uint16 (ycbcr);
-    otherwise
-      error ("rgb2ycbcr: unsupported image class %s", cls);
-  endswitch
-
-  if (img)
-    ## put the image back together
-    ycbcr = reshape (ycbcr, [nRows nCols 3]);
-  endif
+  ycbcr = ycbcrfunc ("rgb2ycbcr", rgb, standard);
 endfunction
 
 %!test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/image/inst/ycbcr2rgb.m	Sun May 05 16:18:48 2013 +0000
@@ -0,0 +1,51 @@
+## Copyright (C) 2013 Carnë Draug <carandraug@octave.org>
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 3 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {Function File} {@var{cmap} =} ycbcr2rgb (@var{YCbCrmap})
+## @deftypefnx {Function File} {@var{RGB} =} ycbcr2rgb (@var{YCbCr})
+## @deftypefnx {Function File} {@dots{} =} ycbcr2rgb (@dots{}, [@var{Kb} @var{Kr}])
+## @deftypefnx {Function File} {@dots{} =} ycbcr2rgb (@dots{}, @var{standard})
+## Convert YCbCr color space to RGB.
+##
+## The convertion changes the image @var{YCbCr} or colormap @var{YCbCrmap},
+## from the YCbCr (luminance, chrominance blue, and chrominance red)
+## color space to RGB values.  @var{YCbCr} must be of class double, single,
+## uint8, or uint16.
+##
+## The formula used for the conversion is dependent on two constants, @var{Kb}
+## and @var{Kr} which can be specified individually, or according to existing
+## standards:
+##
+## @table @asis
+## @item "601" (default)
+## According to the ITU-R BT.601 (formerly CCIR 601) standard.  Its values
+## of @var{Kb} and @var{Kr} are 0.114 and 0.299 respectively.
+## @item "709" (default)
+## According to the ITU-R BT.709 standard.  Its values of @var{Kb} and
+## @var{Kr} are 0.0722 and 0.2116 respectively.
+## @end table
+##
+## @seealso{hsv2rgb, ntsc2rgb, rgb2hsv, rgb2ntsc, rgb2ycbcr}
+## @end deftypefn
+
+function rgb = ycbcr2rgb (ycbcr, standard = "601")
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+  endif
+  rgb = ycbcrfunc ("ycbcr2rgb", ycbcr, standard);
+endfunction
+
+%!assert (ycbcr2rgb (rgb2ycbcr (jet (10))), jet (10), 0.00001);