Manipulación del color en OpenCV


En este tema estudiaremos cómo podemos manipular el color de las imágenes haciendo uso de las funciones proporcionadas por OpenCV.

¿Cómo accedemos a los píxeles en una imagen de color?
Lo primero que tenemos que tener en cuenta, es que una imagen en color sería similar a una matriz tridimensional donde accedemos mediante la posición (i,j) y el índice del canal, o una matriz bidimensional donde en cada posición (i,j) existe una terna de valores.

a) Primera forma: haciendo uso de las funciones cvGet2D() y cvSet2D().
Dichas funciones trabajan sobre variables de tipo CvScalar.
CvScalar value;
 
// Get the set of values at pixel (i,j)
value = cvGet2D(img, i,j);
 
// Modify just one of the components
value.val[0] *= 0.5;
 
// Put the modified value back in image
cvSet2D(img, i,j, value);
 
b) Segunda forma: haciendo uso de punteros (más eficiente).
unsigned char value;
int channel;
 
channel = 2; // Selected image channel
 
// Get pixel at position (i,j) in selected channel
value = ((uchar*)(imgSpace->imageData + imgSpace->widthStep*i))[j*imgSpace->nChannels + channel];
 
// Set pixel at position (i,j) in selected channel
((uchar*)(imgSpace->imageData + imgSpace->widthStep*i))[j*imgSpace->nChannels + channel] = value;
 


¿Cómo transformamos una imagen a diferentes espacios de color?
OpenCV proporciona la siguiente función para cambiar entre espacios de color:
void cvCvtColor(const CvArr* src, CvArr* dst, int code);
Donde:
- src: imagen de origen.
- dst: imagen de destino.
- code: código que indica el tipo de conversión. Algunos código de interés son: CV_RGB2GRAY, CV_RGB2XYZ, CV_XYZ2RGB, CV_RGB2YCrCb, CV_YCrCb2RGB, CV_RGB2HSV, CV_HSV2RGB, CV_RGB2HLS, CV_HLS2RGB,...

Ejercicios propuestos.

1.- Espacio RGB.
Comenzaremos manipulando imágenes en color sobre el espacio RGB.
Sobre las imágenes de test realice las siguientes operaciones:
  1. Cargar imagen con cvLoadImage()
  2. Elegir uno de los canales de la imagen en color.
  3. Poner todos los valores del canal elegido a 0.
  4. Mostrar y/o guardar en disco la imagen resultante.
  5. Repetir los pasos 2-4 con el resto de canales de forma alternativa.

2.- Espacio HSV.
Ahora trabajaremos sobre un espacio de color con propiedades perceptuales, el espacio HSV.
Sobre las imágenes de test realice las siguientes operaciones:
  1. Cargar imagen con cvLoadImage()
  2. Convertir imagen a HSV con cvCvtColor()
  3. Multiplique los valores del canal S (ej. cvConvertScale()) por valores en el intervalo (0, 2] (si algún valor supera el máximo permitido para el canal, asigne el valor máximo permitido a esos píxeles).
  4. Convertir imagen modificada a RGB usando cvCvtColor()
  5. Mostrar imagen resultante (cvShowImage()) y guardar en disco (cvSaveImage()), con sufijo "_hsv.png".
  6. Multiplique los valores del canal V por valores en el intervalo (0, 2] ] (si algún valor supera el máximo permitido para el canal, asigne el valor máximo permitido a esos píxeles), convierta de nuevo a RGB y muestre (o guarde en disco) las imágenes resultantes.
  7. ¿Qué ocurre cuando escala los valores del canal S? ¿Y del canal V?
  8. Modifique ahora los valores del canal H, añadiendo una cantidad C a todos los píxeles en dicho canal. Haga la suma módulo 256, ya que H representa un ángulo. ¿Cuál es el efecto de cambiar los valores en dicho canal?

3.- Espacio YCrCb.
Realice las mismas operaciones que en el ejercicio 2 pero usando el espacio de color YCrCb.
En este caso, escale los valores de los canales Cr y Cb, y vaya mostrando (o guardando en disco) las imágenes resultantes.
¿Qué ocurre en este caso al hacer modificaciones en dichos canales?

4.- Otros espacios de color.
Compruebe qué ocurre al modificar los canales resultantes a cambiar a otros espacios de color, tales como XYZ o HLS.

Código de ejemplo.
Puede usar el siguiente código como base para realizar los ejercicios anteriores.
int main( int argc, char** argv )
{
   IplImage * img1, *imgSpace, *imgout;
 
   char * imgname;
   int channel = 0;
   int i,j, v;
   CvScalar v2;
   char ventana1[] = "Input image",
        ventana2[] = "Output image";
 
   // Parse params
   if (argc < 2)
      syntax(argv); // [TO DO]: create function syntax() to show program parameters
 
   // Load target image
   imgname = argv[1];
   img1 = cvLoadImage(imgname, 1);
   if (img1 == NULL)
   {
      fprintf(stderr, " ERROR: can not load image %s [main] \n", imgname);
      exit(1);
   }
 
   // Alloc mem for output images
   imgSpace = cvCloneImage(img1);
   imgout = cvCloneImage(img1);
 
   // Create windows
   cvNamedWindow(ventana1, 0);
   cvNamedWindow(ventana2, 0);
 
   // Convert to new color space, e.g. HSV
   cvCvtColor(img1, imgSpace, CV_RGB2HSV);
 
   // Modify selected channel
   channel = 2;
 
   for(i = 0; i < img1->height; i++)
      for(j = 0; j < img1->width; j++)
      {
         // [TO DO]: modify values in imgSpace
      }
 
   // Convert back imgSpace to RGB and store into imgout
   // [TO DO]: cvCvtColor()
 
   // Show input image
   cvShowImage(ventana1, img1);
 
   // Show output
   cvShowImage(ventana2, imgout);
 
   // Save output image to disk
   // [TO DO]
 
   // Wait for key
   cvWaitKey(0);
 
   // Release images memory
   // [TO DO]
 
   return 0;
}
 


Imágenes de test.
cmyk-rgb.jpg
Imagen obtenida con Google

cubocolor.jpg
Imagen obtenida con Google


Imagen enlazada de www.smashingapps.com
Imagen enlazada de www.smashingapps.com



Referencias.
Documentación OpenCV sobre color.


Última modificación: 11/Ene/2011 (mjmarin)