Tengo un conjunto de archivos de imagen, y quiero reducir el número de colores de ellos a 64. ¿Cómo puedo hacer esto con OpenCV?

Necesito esto para que yo pueda trabajar con un 64 tamaño histograma de la imagen.
Estoy implementando CBIR técnicas

Lo que yo quiero es la cuantización del color de 4 bits de la paleta.

  • Si desea 64 colores, usted quiere un 6 bits de la paleta. Véase mi respuesta a continuación para una mejor explicación y el código de uso de 2 bits de cada canal de color con el fin de construir un 6 bits de la paleta de la imagen.
  • Añadido una nueva respuesta, puede que le resulte interesante.

7 Comentarios

  1. 9

    Hay muchas formas de hacerlo. Los métodos sugeridos por jeff7 están bien, pero algunos de los inconvenientes son:

    • método 1 parámetros N y M, que se debe elegir, y usted también debe convertirlo a otro espacio de color.
    • método 2 respondida puede ser muy lento, ya que se debe calcular un 16.7 Millones de contenedores de histograma y ordenar por frecuencia (para obtener el 64 valores de frecuencia más altos)

    Me gusta usar un algoritmo basado en el Bits Más Significativos para su uso en un color RGB y convertirlo en un 64 color de la imagen. Si estás usando C/OpenCV, usted puede usar algo como la siguiente función.

    Si usted está trabajando con los niveles de grises de las imágenes yo recomiendo el uso de la LUT() la función de OpenCV 2.3, ya que es más rápido. Hay un tutorial sobre cómo utilizar LUT para reducir el número de colores. Ver: Tutorial: Cómo escanear imágenes, tablas de búsqueda… sin Embargo me parece más complicado si usted está trabajando con imágenes RGB.

    void reduceTo64Colors(IplImage *img, IplImage *img_quant) {
        int i,j;
        int height   = img->height;   
        int width    = img->width;    
        int step     = img->widthStep;
    
        uchar *data = (uchar *)img->imageData;
        int step2 = img_quant->widthStep;
        uchar *data2 = (uchar *)img_quant->imageData;
    
        for (i = 0; i < height ; i++)  {
            for (j = 0; j < width; j++)  {
    
              //operator XXXXXXXX & 11000000 equivalent to  XXXXXXXX AND 11000000 (=192)
              //operator 01000000 >> 2 is a 2-bit shift to the right = 00010000 
              uchar C1 = (data[i*step+j*3+0] & 192)>>2;
              uchar C2 = (data[i*step+j*3+1] & 192)>>4;
              uchar C3 = (data[i*step+j*3+2] & 192)>>6;
    
              data2[i*step2+j] = C1 | C2 | C3; //merges the 2 MSB of each channel
            }     
        }
    }
    
    • Podría usted todavía no utilizar LUT en la no-imágenes en escala de gris? Si se ejecuta el código de la OpenCV tutorial en el enlace que dio aquí, usted puede fácilmente cuantizar el espacio de color de 64 colores, dando a los 64 años, como un parámetro de entrada a su código. Que hace esencialmente lo mismo como la extracción de los 2 bits más significativos en su ejemplo. O me estoy perdiendo algo?
    • Esta función no devuelve un valor, ya que la firma de los estados que devuelve void.
  2. 11

    Este tema fue bien cubierto en OpenCV 2 De La Visión De Computadora De Programación De Aplicaciones De Libro De Cocina:

    Cómo reducir el número de colores de una imagen con OpenCV?

    Capítulo 2 muestra un par de operaciones de reducción, uno de ellos se ha demostrado aquí que en C++:

    #include <iostream>
    #include <vector>
    
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    
    void colorReduce(cv::Mat& image, int div=64)
    {    
        int nl = image.rows;                    //number of lines
        int nc = image.cols * image.channels(); //number of elements per line
    
        for (int j = 0; j < nl; j++)
        {
            //get the address of row j
            uchar* data = image.ptr<uchar>(j);
    
            for (int i = 0; i < nc; i++)
            {
                //process each pixel
                data[i] = data[i] /div * div + div /2;
            }
        }
    }
    
    int main(int argc, char* argv[])
    {   
        //Load input image (colored, 3-channel, BGR)
        cv::Mat input = cv::imread(argv[1]);
        if (input.empty())
        {
            std::cout << "!!! Failed imread()" << std::endl;
            return -1;
        } 
    
        colorReduce(input);
    
        cv::imshow("Color Reduction", input);   
        cv::imwrite("output.jpg", input);   
        cv::waitKey(0);
    
        return 0;
    }
    

    Por debajo usted puede encontrar el de entrada imagen (izquierda) y el salida de esta operación (a la derecha):

    Cómo reducir el número de colores de una imagen con OpenCV?

    • deseo que usted no debe parar , muchos pueden aprender a través de este foro a través de ti !! porque en algún lugar principiantes como yo , no saben ni siquiera las pequeñas cosas , incluso no sé cuánto tiempo tendré que dar mi campo para convertirse en el mejor en esto
    • Bueno, yo no lo sé tampoco. Pero usted está haciendo lo correcto al venir aquí y leyendo todo esto. Este hombre tiene algunas de las mejores OpenCV respuestas en el sitio. Él tiene una increíble blog acerca de este material, check it out!
    • sí, a menudo se acercan a él en busca de ayuda 🙂 , yo en algún momento miedo de que me estoy tomando demasiado tiempo para aprender o para ser bueno en la programación , acabo de terminar mi licenciatura , poco confundido !! te vi el perfil de su Profesor !! bonito
    • Sabes el dicho: «Aquellos que no pueden hacer, enseñar!»
    • venga , estoy siguiendo a ti y te dijo esto lol
  3. 10

    Usted podría considerar la posibilidad de K-means, sin embargo, en este caso, lo más probable es extremadamente lento. Un mejor enfoque podría estar haciendo esto «manualmente» por su propia cuenta. Digamos que usted tiene de la imagen de tipo CV_8UC3, es decir, una imagen en la cual cada píxel está representado por 3 valores RGB de 0 a 255 (Vec3b). Usted puede «mapa» de los 256 valores a sólo 4 valores específicos, lo que produciría 4 x 4 x 4 = 64 colores posibles.

    He tenido un conjunto de datos, en la que necesitaba para asegurarse de que la oscuridad = negro, la luz = blanco y reducir la cantidad de colores de todo lo que entre. Esto es lo que yo hice (C++):

    inline uchar reduceVal(const uchar val)
    {
        if (val < 64) return 0;
        if (val < 128) return 64;
        return 255;
    }
    
    void processColors(Mat& img)
    {
        uchar* pixelPtr = img.data;
        for (int i = 0; i < img.rows; i++)
        {
            for (int j = 0; j < img.cols; j++)
            {
                const int pi = i*img.cols*3 + j*3;
                pixelPtr[pi + 0] = reduceVal(pixelPtr[pi + 0]); //B
                pixelPtr[pi + 1] = reduceVal(pixelPtr[pi + 1]); //G
                pixelPtr[pi + 2] = reduceVal(pixelPtr[pi + 2]); //R
            }
        }
    }
    

    causando [0,64) para convertirse en 0, [64,128) -> 64 y [128,255) -> 255, produciendo 27 colores:

    Cómo reducir el número de colores de una imagen con OpenCV?

    Esto me parece estar ordenado, perfectamente claro y más rápido que cualquier otra cosa mencionado en otras respuestas.

    También podría considerar la reducción de estos valores a uno de los múltiplos de un número, digamos:

    inline uchar reduceVal(const uchar val)
    {
        if (val < 192) return uchar(val /64.0 + 0.5) * 64;
        return 255;
    }
    

    que daría lugar a un conjunto de 5 valores posibles: {0, 64, 128, 192, 255}, es decir, 125 colores.

  4. 4

    Las respuestas que se proponen aquí son muy buenos. Yo quisiera añadir mi idea así. Yo sigo a la formulación de los muchos comentarios aquí, en la que se dice que el 64 colores puede ser representado por 2 bits de cada canal en una imagen RGB.

    La función en el código siguiente se toma como entrada una imagen y el número de bits necesarios para la cuantización. Utiliza la manipulación de bits a ‘soltar’ el LSB bits y mantener sólo el número necesario de bits. El resultado es un método flexible que puede cuantizar la imagen de cualquier número de bits.

    #include "include\opencv\cv.h"
    #include "include\opencv\highgui.h"
    
    //quantize the image to numBits 
    cv::Mat quantizeImage(const cv::Mat& inImage, int numBits)
    {
        cv::Mat retImage = inImage.clone();
    
        uchar maskBit = 0xFF;
    
        //keep numBits as 1 and (8 - numBits) would be all 0 towards the right
        maskBit = maskBit << (8 - numBits);
    
        for(int j = 0; j < retImage.rows; j++)
            for(int i = 0; i < retImage.cols; i++)
            {
                cv::Vec3b valVec = retImage.at<cv::Vec3b>(j, i);
                valVec[0] = valVec[0] & maskBit;
                valVec[1] = valVec[1] & maskBit;
                valVec[2] = valVec[2] & maskBit;
                retImage.at<cv::Vec3b>(j, i) = valVec;
            }
    
            return retImage;
    }
    
    
    int main ()
    {
        cv::Mat inImage;
        inImage = cv::imread("testImage.jpg");
        char buffer[30];
        for(int i = 1; i <= 8; i++)
        {
            cv::Mat quantizedImage = quantizeImage(inImage, i);
            sprintf(buffer, "%d Bit Image", i);
            cv::imshow(buffer, quantizedImage);
    
            sprintf(buffer, "%d Bit Image.png", i);
            cv::imwrite(buffer, quantizedImage);
        }
    
        cv::waitKey(0);
        return 0;
    }
    

    Aquí es una imagen que se utiliza en la función anterior llamada:

    Cómo reducir el número de colores de una imagen con OpenCV?

    Imagen cuantificadas a 2 bits para cada canal RGB (Total de 64 Colores):

    Cómo reducir el número de colores de una imagen con OpenCV?

    3 bits para cada canal:

    Cómo reducir el número de colores de una imagen con OpenCV?

    4 bits …

    Cómo reducir el número de colores de una imagen con OpenCV?

  5. 3

    No es el K-means clustering algoritmo, el cual ya está disponible en la biblioteca OpenCV. En breve se determina que son los mejores de los centroides, alrededor de las cuales clúster de sus datos para un valor definido por el usuario de k ( = no de clusters). Así que, en su caso, usted puede encontrar los centroides, alrededor de las cuales clúster de sus valores de los píxeles para un valor dado de k=64. Los detalles están ahí si google alrededor. Aquí‘s una breve introducción a la k-means.

    Algo similar a lo que están intentando probablemente fue preguntado aquí en ASÍ utilizando k-means, espero que ayude.

    Otro enfoque sería utilizar el la pirámide de la media de cambio de filtro función de OpenCV. El resultado es un poco «aplanado» de las imágenes, es decir, el número de colores son menos por lo que podría ser capaz de ayudarle.

  6. 1

    Suponiendo que usted desea utilizar la misma 64 colores para todas las imágenes (es decir, la paleta no optimizado por imagen), hay al menos un par de opciones que puedo pensar:

    1) Convertir de Laboratorio o espacio de color YCrCb y cuantificar el uso de N bits para la luminancia y M bits para cada canal de color, N debe ser mayor que M.

    2) Calcular 3D histograma de los valores de color durante toda su formación de imágenes, a continuación, elija el 64 colores con la mayor bin valores. Cuantización de sus imágenes mediante la asignación de cada pixel en el color de la más cercana de reciclaje, desde el conjunto de entrenamiento.

    Método 1 es el más genérico y más fáciles de implementar, mientras que el método 2 puede ser mejor adaptado a tus necesidades específicas del conjunto de datos.

    Actualización:
    Por ejemplo, 32 colores es de 5 bits para asignar 3 bits para el canal de luminancia y 1 de bits para cada canal de color. Para ello cuantización, hacer la división entera de el canal de luminancia por 2^8/2^3 = 32 y cada canal de color por 2^8/2^1 = 128. Ahora sólo hay 8 diferentes valores de luminancia y 2 canales de colores distintos cada uno. Recombinar estos valores en un único número entero haciendo bit de desplazamiento o de matemáticas (cuantificada valor de color = luminancia*4+color1*2+color2);

    • la cuantificación de uso de N bits para la luminancia y M bits para cada canal de color, N debe ser mayor que M.» – ¿Cómo puedo hacer esta parte?
  7. -1

    ¿Por qué no hacer de la Matriz de multiplicación/división? Los valores serán automáticamente redondeado.

    Pseudocódigo:

    convertir sus canales de caracteres sin signo (CV_8UC3),

    Dividir por
    total de colores /colores deseados. Mat = Mat /(256/64). Puntos decimales
    será truncado.

    Se multiplican por el mismo número. Mat = mat * 4

    Hecho. Cada canal ahora sólo contiene 64 colores.

Dejar respuesta

Please enter your comment!
Please enter your name here